class DebugModelView(ModelView): """ Base class for Model/View's to provide a python shell for debugging. """ #### Private protocol ##################################################### # A dummy python value to allow us to display a Python shell. _python_value = PythonValue #### Traits UI ############################################################ python_shell_group = Group( Item( '_python_value', editor = ShellEditor(share=True), show_label = False, ), label = 'Python Shell' ) debug_group = python_shell_group debug_view = View( VGroup( Include('body'), Include('debug_group'), layout = 'split' ), resizable = True, width = 800, height = 600 )
class DemoButton ( HasPrivateTraits ): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # The demo to be launched via a button: demo = Instance( HasTraits ) # The demo view item to use: demo_item = Item( 'demo', show_label = False, editor = InstanceEditor( label = 'Run demo...', kind = 'live' ) ) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- traits_view = View( VGroup( VGroup( Heading( 'Click the button to run the demo:' ), '20' ), HGroup( spring, Include( 'demo_item' ), spring ) ), resizable = True )
class DemoButton(HasPrivateTraits): # ------------------------------------------------------------------------- # Trait definitions: # ------------------------------------------------------------------------- #: The demo to be launched via a button: demo = Instance(HasTraits) #: The demo view item to use: demo_item = Item( "demo", show_label=False, editor=InstanceEditor(label="Run demo...", kind="live"), ) # ------------------------------------------------------------------------- # Traits view definitions: # ------------------------------------------------------------------------- traits_view = View( VGroup( VGroup(Heading("Click the button to run the demo:"), "20"), HGroup(spring, Include("demo_item"), spring), ), resizable=True, )
class WithShell(HasTraits): df = Instance(DataFrame) shell = Any() pandasplot = Instance(PandasPlot) def __init__(self): # self.df=DataFrame([1,2,3]) self.pandasplot = PandasPlot() # self.pandasplot.df=self.df def _df_changed(self): if self.pandasplot: self.pandasplot.df = self.df main_group = Group( Item('pandasplot', show_label=False, style='custom'), # Item('df_new'), Item('df_change'), Item('shell', editor=ShellEditor(), style='simple'), #Include('sample_group'), #Include('axis_traits_group') ) traits_view = View(Include('main_group'), resizable=True, height=600, width=800)
def traits_view(self): traits_view = View(VGroup( self.traits_plot_item, Include('instructions_group'), ), resizable=True) return traits_view
class BasicAdapter(HasTraits): """ Adapter for previewing, other things. What is shown in "MATERIAL" tab. populate_object() method used to show an instance of the material. """ implements(IAdapter) mat_class = 'bulk' #<-- Don't change, needed by layer_editor name=Str('Basic Material') source=Str('Abstract Base Class for material') notes=Str('Not Found') matobject = Instance(IMaterial) preview = Button hide_preview = Button testview = Any # SHows material after preview fired apikey = 'basic' #<-- Materials API identifier def _preview_fired(self): """ View the material as plot""" if self.matobject == None: self.populate_object() self.testview = self.matobject.mview # self.matobject.edit_traits(kind='livemodal') #Modal screws up objects for some reason # self.destroy_object() def populate_object(self): """Instantiate selected object.""" # Imports must be in here because some objects need to access apikey, # but have infinite recursion if importing materials. For example, # if composite materials needs to set materia1 to a composite material, # this will lead to recursive imports. from materialapi import ALLMATERIALS self.matobject = ALLMATERIALS[self.apikey]() def destroy_object(self): """Method used to destroy an object; not sure if ever will be useful or if it even destroys the object...""" self.matobject = None self.testview = None def _hide_preview_fired(self): self.destroy_object() basicgroup=Group( Item('name', style='readonly'), #THESE ARENT READ ONLY! Item('source', style='readonly'), Item('notes'), Item('preview', show_label=False, visible_when='testview is None'), Item('hide_preview', show_label=False, visible_when='testview is not None'), Item('testview', visible_when='testview is not None', show_label=False, editor=InstanceEditor(), style='custom', ) ) traitsview= View(Include('basicgroup'), resizable=True, )
def traits_multiple_axes_view(self): traits_scroll_view = View( UItem('figure', editor=MPLFigureEditor(), style='custom'), Include('options_group_axes_sel'), handler=MPLInitHandler, resizable=True, ) return traits_scroll_view
class SinglePlotWindow(PlotWindow): """Window for embedding line plot """ plot = Instance(Handler) plot_navigator = Instance(ViewNavigator) next_plot = Button('Next plot') previous_plot = Button('Previous plot') view_table = Button('View result table') def _plot_navigator_default(self): if self.res and self.view_loop: return ViewNavigator(res=self.res, view_loop=self.view_loop) else: return None plot_gr = Group( Item('plot', editor=InstanceEditor(), style='custom', show_label=False, width=sz_abs[0], height=sz_abs[1]), ) main_gr = Group( Item('save_plot', show_label=False), Item('view_table', show_label=False), Item('previous_plot', show_label=False, defined_when='plot_navigator'), Item('next_plot', show_label=False, defined_when='plot_navigator'), orientation="horizontal", ) ## def default_traits_view(self): traits_view = View( Group( Include('plot_gr'), Include('main_gr'), layout="normal", ), resizable=True, handler=SinglePWC(), # kind = 'nonmodal', # width=sz_rel[0], # height=sz_rel[1], buttons=["OK"])
class Vis2D(BMCSLeafNode): '''Each state and operator object can be associated with several visualization objects with a shortened class name Viz3D. In order to introduce a n independent class subsystem into the class structure, objects supporting visualization inherit from Visual3D which introduces a dictionary viz3d objects. ''' vot = Float(0.0, time_change=True) '''Visual object time ''' viz2d_classes = Dict '''Visualization classes applicable to this object. ''' viz2d_class_names = Property(List(Str), depends_on='viz2d_classes') '''Keys of the viz2d classes ''' @cached_property def _get_viz2d_class_names(self): return self.viz2d_classes.keys() selected_viz2d_class = Str('default') add_selected_viz2d = Button(label='Add plot viz2d') def _add_selected_viz2d_fired(self): viz2d = self.viz2d[self.selected_viz2d_class] if self.ui: self.ui.plot_dock_pane.viz2d_list.append(viz2d) viz2d = Property(Dict) '''Dictionary of visualization objects''' @cached_property def _get_viz2d(self): '''Get a vizualization object given the key of the vizualization class. Construct it on demand and register in the viz3d_dict. ''' return Viz2DDict(vis2d=self) def viz2d_notify_change(self): for viz2d in self.viz2d.values(): viz2d.vis2d_changed = True actions = Group( HGroup( UItem('add_selected_viz2d'), UItem('selected_viz2d_class', springy=True, editor=EnumEditor(name='object.viz2d_class_names', )), springy=True, ), ) view = View(Include('actions'), resizable=True)
class DemoModel(BMCSModel): '''Demo model of the BMCS Window Shows how the time control within an application of BMCS is realized. Run mode ======== The model provides the methods for the Actions Run, Pause, and Continue. During these actions, values are registered within the response tracers. The model can also send an update to the visual object time - so that the response tracers are asked to be updated. Sliding mode ============ Once the calculation is finished, the slider in the VizSheet can be used to browse through the viz-adapters and visualize the response for the current vot. Interactive mode ================ Boundary condition can be constructed interactively by a boundary condition factory. The factory acts as a Run mode. ''' node_name = 'demo model' tree_node_list = List def _tree_node_list_default(self): return [self.tline, self.rt, self.bc_dof] tloop = Property(Instance(TimeLoop)) @cached_property def _get_tloop(self): return TimeLoop(tline=self.tline) def eval(self): self.tloop.eval() rt = Instance(ResponseTracer, ()) bc_dof = Instance(BCDof) def _bc_dof_default(self): return BCDof(time_function=TFunPWLInteractive()) tree_view = View( VGroup( Include('actions'), UItem('bc_dof@', height=500) ) )
class LmParams(HasTraits): data = Instance(tup) n_exps = Int(50, low=1, tooltip='Number of exponentials used as base') max_iter = Int(10000) params = Group() view = View(['max_iter', 'n_exps', Include('params')]) def fit(self): base = ltm._make_base(self.data) self.fitobj.fit()
class BoundaryCondition(BMCSLeafNode, Vis2D): node_name = 'boundary condition' t_values = List(Float, [0]) f_values = List(Float, [0]) n_f_values = Int(10, auto_set=False, enter_set=True) f_min = Float(0.0, auto_set=False, enter_set=True) f_max = Float(1.0, auto_set=False, enter_set=True) t_ref = Float(1.0, auto_set=False, enter_set=True) f_value = Range(low='f_min', high='f_max', value=0, auto_set=False, enter_set=True) d_t = Property(depends_on='t_ref,n_f_values') @cached_property def _get_d_t(self): return self.t_ref / self.n_f_values def _f_value_changed(self): delta_f = self.f_value - self.f_values[-1] self.f_values.append(self.f_value) rel_step = delta_f / self.f_max delta_t = rel_step * self.t_ref t_value = np.fabs(delta_t) + self.t_values[-1] self.t_values.append(t_value) if self.ui: self.ui.set_vot(t_value) def get_ty_data(self, vot): return self.t_values, self.f_values viz2d_classes = { 'time_function': TFViz2D, } tree_view = View(VGroup( VGroup(Include('actions'), ), VGroup(UItem('f_value', full_size=True, resizable=True), label='Steering slider'), VGroup( Item('f_min', full_size=True, resizable=True), Item('f_max', full_size=True), Item('n_f_values', full_size=True), spring, label='Steering range', ), ), resizable=True)
def test_traits_view(self): trait_view = View( UItem('figure', editor=MPLFigureEditor(), style='custom'), Include('options_group'), Item('t'), Item('terrorbar'), Item('tblit'), Item('timg'), handler=MPLInitHandler, resizable=True, # scrollable=True, ) return trait_view
class ResponseTracer(BMCSLeafNode, Vis2D): node_name = 'response tracer' def get_sim_results(self, vot): t = np.linspace(0, 1, 100) x = t y = x**2 - vot return t, x, y viz2d_classes = {'time_profile': TP} tree_view = View(HGroup(Include('actions')))
class effective_sphere(bare_sphere): """ Bare sphere, but r_core is implied to mean effective radius, usually r_core + shell_width passed in from another model. Used by NanoSphereShell, which handles the r_core + shell_width sum. Computationally, this is identical to bare sphere (no shell parameters into play in the cross section) """ bare_sphere_group = Group( Include('basic_group'), HGroup(Item('r_core', label='EFFECTIVE Radius')), )
class ShearCrack(BMCSLeafNode, Vis2D): '''Class representing the geometry of a crack using a piecewise linear representation ''' node_name = 'shear crack geometry' x = tr.Array(np.float_, value=[0.2, 0.15, 0.1], GEO=True) y = tr.Array(np.float_, value=[0.0, 0.15, 0.2], GEO=True) viz2d_classes = { 'shear_crack': ShearCrackViz2D } tree_view = View( HGroup( Include('actions') ) )
class SLSRxyz(LS): '''Serviceability limit state ''' # ------------------------------------------------------------ # SLS: outputs # ------------------------------------------------------------ ls_columns = List([]) ls_values = Property(depends_on='+input') @cached_property def _get_ls_values(self): '''get the outputs for SLS ''' return {} assess_name = '' #------------------------------- # ls view #------------------------------- # @todo: the dynamic selection of the columns to be displayed # does not work in connection with the LSArrayAdapter traits_view = View(VGroup( HGroup(Item(name='', label=''), Item(name='', label='') ), VGroup( Include('ls_group'), Item('ls_array', show_label=False, editor=TabularEditor(adapter=LSArrayAdapter())) ), ), resizable=True, scrollable=True, height=1000, width=1100 )
class ABCFileAdapter(BasicAdapter): from material_files import ABCExternal source="N/A" notes="Basic File of unknown type" file_path = File matobject = Instance(ABCExternal) name=Property(Str, depends_on='file_path') # File Trai openfile = Button hidecontents = Button contents = Str filegroup = Group( Item('openfile', show_label=False, visible_when="contents == ''", label='Show File Contents' ), Item('hidecontents', show_label=False, label='Hide File Contents', visible_when="contents != ''" ), Item('contents', style='readonly', show_label=False, visible_when="contents != ''" ) ) traitsview= View(VGroup( Include('basicgroup'), Include('filegroup'), ), resizable=True, # width=400, # height=200 ) def _openfile_fired(self): self.contents = open(self.file_path, 'r').read() def _hidecontents_fired(self): self.contents = '' def _get_name(self): return op.splitext(op.basename(self.file_path))[0] def populate_object(self): """ FileAdapters make the object and set the default name separately. Default material name is slightly different than self.name for display aesthetics. """ self._set_matobject() self._set_matname() # Let's me change keywords for file-to-file instantiation/populate_object? def _set_matobject(self): """ Create material. THIS IS WHAT SUBCLASSES SHOULD OVERLOAD""" self.matobject = self.ABCFile(file_path=self.file_path) def _set_matname(self): """ Sets material name after populating object. This name is: Source : filename instead of just filename. Need to separate or Source will end up in table when looking through DB """ self.matobject.mat_name = self.name def _set_name(self, newname): self.name = newname
class MATSXDMicroplaneDamageFatigueWu(MATSEvalMicroplaneFatigue): ''' Microplane Damage Fatigue Model. ''' #------------------------------------------------------------------------- # Configuration parameters #------------------------------------------------------------------------- model_version = Enum("compliance", "stiffness") symmetrization = Enum("product-type", "sum-type") regularization = Bool(False, desc='Flag to use the element length projection' ' in the direction of principle strains', enter_set=True, auto_set=False) elastic_debug = Bool(False, desc='Switch to elastic behavior - used for debugging', auto_set=False) double_constraint = Bool(False, desc='Use double constraint to evaluate microplane elastic and fracture energy (Option effects only the response tracers)', auto_set=False) #------------------------------------------------------------------------- # View specification #------------------------------------------------------------------------- config_param_vgroup = Group(Item('model_version', style='custom'), # Item('stress_state', style='custom'), Item('symmetrization', style='custom'), Item('elastic_debug@'), Item('double_constraint@'), Spring(resizable=True), label='Configuration parameters', show_border=True, dock='tab', id='ibvpy.mats.matsXD.MATSXD_cmdm.config', ) traits_view = View(Include('polar_fn_group'), dock='tab', id='ibvpy.mats.matsXD.MATSXD_cmdm', kind='modal', resizable=True, scrollable=True, width=0.6, height=0.8, buttons=['OK', 'Cancel'] ) #------------------------------------------------------------------------- # MICROPLANE-DISCRETIZATION RELATED METHOD #------------------------------------------------------------------------- # get the dyadic product of the microplane normals _MPNN = Property(depends_on='n_mp') @cached_property def _get__MPNN(self): # dyadic product of the microplane normals MPNN_nij = einsum('ni,nj->nij', self._MPN, self._MPN) return MPNN_nij # get the third order tangential tensor (operator) for each microplane @cached_property def _get__MPTT(self): # Third order tangential tensor for each microplane delta = identity(3) MPTT_nijr = 0.5 * (einsum('ni,jr -> nijr', self._MPN, delta) + einsum('nj,ir -> njir', self._MPN, delta) - 2 * einsum('ni,nj,nr -> nijr', self._MPN, self._MPN, self._MPN)) return MPTT_nijr def _get_e_vct_arr(self, eps_eng): # Projection of apparent strain onto the individual microplanes e_ni = einsum('nj,ji->ni', self._MPN, eps_eng) return e_ni def _get_e_N_arr(self, e_vct_arr): # get the normal strain array for each microplane eN_n = einsum('ni,ni->n', e_vct_arr, self._MPN) return eN_n def _get_e_T_vct_arr(self, e_vct_arr): # get the tangential strain vector array for each microplane eN_n = self._get_e_N_arr(e_vct_arr) eN_vct_ni = einsum('n,ni->ni', eN_n, self._MPN) return e_vct_arr - eN_vct_ni #------------------------------------------------- # Alternative methods for the kinematic constraint #------------------------------------------------- def _get_e_N_arr_2(self, eps_eng): #eps_mtx = self.map_eps_eng_to_mtx(eps_eng) return einsum('nij,ij->n', self._MPNN, eps_eng) def _get_e_T_vct_arr_2(self, eps_eng): #eps_mtx = self.map_eps_eng_to_mtx(eps_eng) MPTT_ijr = self._get__MPTT() return einsum('nijr,ij->nr', MPTT_ijr, eps_eng) def _get_e_vct_arr_2(self, eps_eng): return self._e_N_arr_2 * self._MPN + self._e_t_vct_arr_2 def _get_state_variables(self, sctx, eps_app_eng, sigma_kk): #-------------------------------------------------------- # return the state variables (Damage , inelastic strains) #-------------------------------------------------------- e_N_arr = self._get_e_N_arr_2(eps_app_eng) e_T_vct_arr = self._get_e_T_vct_arr_2(eps_app_eng) sctx_arr = zeros((28, 13)) for i in range(0, self.n_mp): if e_N_arr[i] > 0: sctx_N_ten = self.get_normal_tension_Law( e_N_arr[i], sctx[i, :]) sctx_N_comp = zeros(3) else: sctx_N_comp = self.get_normal_compression_Law( e_N_arr[i], sctx[i, :]) sctx_N_ten = zeros(2) sctx_tangential = self.get_tangential_Law( e_T_vct_arr[i, :], sctx[i, :], sigma_kk) sctx_arr[i, 0:2] = sctx_N_ten sctx_arr[i, 2:5] = sctx_N_comp sctx_arr[i, 5:13] = sctx_tangential return sctx_arr def _get_eps_N_p_arr(self, sctx, eps_app_eng, sigma_kk): #----------------------------------------------------------------- # Returns a list of the plastic normal strain for all microplanes. #----------------------------------------------------------------- eps_N_p = self._get_state_variables(sctx, eps_app_eng, sigma_kk)[:, 4] return eps_N_p def _get_eps_T_pi_arr(self, sctx, eps_app_eng, sigma_kk): #---------------------------------------------------------------- # Returns a list of the sliding strain vector for all microplanes. #---------------------------------------------------------------- eps_T_pi_vct_arr = self._get_state_variables( sctx, eps_app_eng, sigma_kk)[:, 10:13] return eps_T_pi_vct_arr def _get_I_vol_4(self): #---------------------------------------------------------------- # the fourth order volumetric-identity tensor #---------------------------------------------------------------- delta = identity(3) I_vol_ijkl = (1.0 / 3.0) * einsum('ij,kl -> ijkl', delta, delta) return I_vol_ijkl def _get_I_dev_4(self): #---------------------------------------------------------------- # Returns the fourth order deviatoric-identity tensor #---------------------------------------------------------------- delta = identity(3) I_dev_ijkl = 0.5 * (einsum('ik,jl -> ijkl', delta, delta) + einsum('il,jk -> ijkl', delta, delta)) \ - (1. / 3.0) * einsum('ij,kl -> ijkl', delta, delta) return I_dev_ijkl def _get_P_vol(self): #---------------------------------------------------------------- # Returns the fourth order tensor P_vol [Wu.2009] #---------------------------------------------------------------- delta = identity(3) P_vol_ij = (1. / 3.0) * delta return P_vol_ij def _get_P_dev(self): #---------------------------------------------------------------- # Returns the fourth order tensor P_dev [Wu.2009] #---------------------------------------------------------------- delta = identity(3) P_dev_njkl = 0.5 * einsum('ni,ij,kl -> njkl', self._MPN, delta, delta) return P_dev_njkl def _get_PP_vol_4(self): #---------------------------------------------------------------- # Returns the outer product of P_vol [Wu.2009] #---------------------------------------------------------------- delta = identity(3) PP_vol_ijkl = (1. / 9.) * einsum('ij,kl -> ijkl', delta, delta) return PP_vol_ijkl def _get_PP_dev_4(self): #---------------------------------------------------------------- # Returns the inner product of P_dev #---------------------------------------------------------------- delta = identity(3) PP_dev_nijkl = 0.5 * (0.5 * (einsum('ni,nk,jl -> nijkl', self._MPN, self._MPN, delta) + einsum('ni,nl,jk -> nijkl', self._MPN, self._MPN, delta)) + 0.5 * (einsum('ik,nj,nl -> nijkl', delta, self._MPN, self._MPN) + einsum('il,nj,nk -> nijkl', delta, self._MPN, self._MPN))) -\ (1. / 3.) * (einsum('ni,nj,kl -> nijkl', self._MPN, self._MPN, delta) + einsum('ij,nk,nl -> nijkl', delta, self._MPN, self._MPN)) +\ (1. / 9.) * einsum('ij,kl -> ijkl', delta, delta) return PP_dev_nijkl def _get_phi_arr(self, sctx, eps_app_eng, sigma_kk): #------------------------------------------------------------- # Returns a list of the integrity factors for all microplanes. #------------------------------------------------------------- phi_arr = 1. - \ self._get_state_variables(sctx, eps_app_eng, sigma_kk)[:, 5] return phi_arr def _get_phi_mtx(self, sctx, eps_app_eng, sigma_kk): #------------------------------------------------------------- # Returns the 2nd order damage tensor 'phi_mtx' #------------------------------------------------------------- # scalar integrity factor for each microplane phi_arr = self._get_phi_arr(sctx, eps_app_eng, sigma_kk) # integration terms for each microplanes phi_ij = einsum('n,n,nij->ij', phi_arr, self._MPW, self._MPNN) # print 'phi_ij', phi_ij return phi_ij #------------------------------------------------------------------------- # Construct the irreducible secant stiffness tensor (cf. [Wu.2009]) with three approaches #------------------------------------------------------------------------- def _get_S_1_tns(self, sctx, eps_app_eng, sigma_kk): #---------------------------------------------------------------------- # Returns the fourth order secant stiffness tensor (cf. [Wu.2009], Eq.(29)) #---------------------------------------------------------------------- K0 = self.E / (1. - 2. * self.nu) G0 = self.E / (1. + self.nu) phi_n = self._get_phi_arr(sctx, eps_app_eng, sigma_kk) PP_vol_4 = self._get_PP_vol_4() PP_dev_4 = self._get_PP_dev_4() I_dev_4 = self._get_I_dev_4() S_1_ijkl = K0 * einsum('n,n,ijkl->ijkl', phi_n, self._MPW, PP_vol_4) + \ G0 * 2 * self.zeta_G * einsum('n,n,nijkl->ijkl', phi_n, self._MPW, PP_dev_4) - (1. / 3.) * ( 2 * self.zeta_G - 1) * G0 * einsum('n,n,ijkl->ijkl', phi_n, self._MPW, I_dev_4) return S_1_ijkl def _get_d_scalar(self, sctx, eps_app_eng, sigma_kk): # scalar damage factor for each microplane d_n = self._get_state_variables(sctx, eps_app_eng, sigma_kk)[:, 5] d = (1.0 / 3.0) * einsum('n,n->', d_n, self._MPW) # print 'd', d return d def _get_M_vol_tns(self, sctx, eps_app_eng, sigma_kk): d = self._get_d_scalar(sctx, eps_app_eng, sigma_kk) delta = identity(3) I_4th_ijkl = einsum('ik,jl -> ijkl', delta, delta) # print 'M_vol', (1 - d) * I_4th_ijkl return (1 - d) * I_4th_ijkl def _get_M_dev_tns(self, phi_mtx): ''' Returns the 4th order deviatoric damage tensor ''' delta = identity(3) I_4th_ijkl = einsum('ik,jl -> ijkl', delta, delta) tr_phi_mtx = trace(phi_mtx) M_dev_ijkl = self.zeta_G * (0.5 * (einsum('ik,jl->ijkl', delta, phi_mtx) + einsum('il,jk->ijkl', delta, phi_mtx)) + 0.5 * (einsum('ik,jl->ijkl', phi_mtx, delta) + einsum('il,jk->ijkl', phi_mtx, delta))) \ - (2. * self.zeta_G - 1.) * (tr_phi_mtx / 3.) * I_4th_ijkl # print 'M_dev_ijkl', M_dev_ijkl return M_dev_ijkl def _get_S_2_tns(self, sctx, eps_app_eng, sigma_kk): #---------------------------------------------------------------------- # Returns the fourth order secant stiffness tensor (cf. [Wu.2009], Eq.(31)) #---------------------------------------------------------------------- K0 = self.E / (1. - 2. * self.nu) G0 = self.E / (1. + self.nu) I_vol_ijkl = self._get_I_vol_4() I_dev_ijkl = self._get_I_dev_4() phi_mtx = self._get_phi_mtx(sctx, eps_app_eng, sigma_kk) M_vol_ijkl = self._get_M_vol_tns(sctx, eps_app_eng, sigma_kk) M_dev_ijkl = self._get_M_dev_tns(phi_mtx) S_2_ijkl = K0 * einsum('ijmn,mnrs,rskl -> ijkl', I_vol_ijkl, M_vol_ijkl, I_vol_ijkl ) \ + G0 * einsum('ijmn,mnrs,rskl -> ijkl', I_dev_ijkl, M_dev_ijkl, I_dev_ijkl)\ # S_2_ijkl = K0 * einsum('ijmn,mnrs,rskl -> ijkl', I_dev_ijkl, M_dev_ijkl, I_dev_ijkl ) \ # + G0 * einsum('ijmn,mnrs,rskl -> ijkl', I_dev_ijkl, M_dev_ijkl, I_dev_ijkl)\ # print 'S_vol = ', einsum('ijmn,mnrs,rskl -> ijkl', I_vol_ijkl, M_vol_ijkl, I_vol_ijkl) # print 'S_dev = ', einsum('ijmn,mnrs,rskl -> ijkl', I_dev_ijkl, # M_dev_ijkl, I_dev_ijkl) print 'M_vol_ijkl', M_vol_ijkl print 'M_dev_ijkl', M_dev_ijkl return S_2_ijkl def _get_S_3_tns(self, sctx, eps_app_eng, sigma_kk): #---------------------------------------------------------------------- # Returns the fourth order secant stiffness tensor (cf. [Wu.2009], Eq.(34)) #---------------------------------------------------------------------- K0 = self.E / (1. - 2. * self.nu) G0 = self.E / (1. + self.nu) I_vol_ijkl = self._get_I_vol_4() I_dev_ijkl = self._get_I_dev_4() # The fourth order elastic stiffness tensor S_0_ijkl = K0 * I_vol_ijkl + G0 * I_dev_ijkl d_n = self._get_state_variables(sctx, eps_app_eng, sigma_kk)[:, 5] PP_vol_4 = self._get_PP_vol_4() PP_dev_4 = self._get_PP_dev_4() delta = identity(3) I_4th_ijkl = einsum('ik,jl -> ijkl', delta, delta) D_ijkl = einsum('n,n,ijkl->ijkl', d_n, self._MPW, PP_vol_4) + \ 2 * self.zeta_G * einsum('n,n,nijkl->ijkl', d_n, self._MPW, PP_dev_4) - ( 1 / 3.) * (2 * self.zeta_G - 1) * einsum('n,n,ijkl->ijkl', d_n, self._MPW, I_dev_ijkl) phi_ijkl = (I_4th_ijkl - D_ijkl) # print 'D_ijkl', D_ijkl S_ijkl = einsum('ijmn,mnkl', phi_ijkl, S_0_ijkl) return S_ijkl def _get_S_4_tns(self, sctx, eps_app_eng, sigma_kk): #---------------------------------------------------------------------- # Returns the fourth order secant stiffness tensor (double orthotropic) #---------------------------------------------------------------------- K0 = self.E / (1. - 2. * self.nu) G0 = self.E / (1. + self.nu) I_vol_ijkl = self._get_I_vol_4() I_dev_ijkl = self._get_I_dev_4() delta = identity(3) phi_mtx = self._get_phi_mtx(sctx, eps_app_eng, sigma_kk) D_ij = delta - phi_mtx d = (1. / 3.) * trace(D_ij) D_bar_ij = self.zeta_G * (D_ij - d * delta) S_4_ijkl = (1 - d) * K0 * I_vol_ijkl + (1 - d) * G0 * I_dev_ijkl + (2 / 3.) * (G0 - K0) * \ (einsum('ij,kl -> ijkl', delta, D_bar_ij) + einsum('ij,kl -> ijkl', D_bar_ij, delta)) + 0.5 * (K0 - 2 * G0) * (0.5 * (einsum('ik,jl -> ijkl', delta, D_bar_ij) + einsum('il,jk -> ijkl', D_bar_ij, delta)) + 0.5 * (einsum('il,jk -> ijkl', D_bar_ij, delta) + einsum('ik,jl -> ijkl', delta, D_bar_ij))) return S_4_ijkl def _get_eps_p_mtx(self, sctx, eps_app_eng, sigma_kk): #----------------------------------------------------------- # Integration of the (inelastic) strains for each microplane #----------------------------------------------------------- # plastic normal strains eps_N_P_n = self._get_eps_N_p_arr(sctx, eps_app_eng, sigma_kk) # sliding tangential strains eps_T_pi_ni = self._get_eps_T_pi_arr(sctx, eps_app_eng, sigma_kk) delta = identity(3) # 2-nd order plastic (inelastic) tensor eps_p_ij = einsum('n,n,ni,nj -> ij', self._MPW, eps_N_P_n, self._MPN, self._MPN) + \ 0.5 * (einsum('n,nr,ni,rj->ij', self._MPW, eps_T_pi_ni, self._MPN, delta) + einsum('n,nr,nj,ri->ij', self._MPW, eps_T_pi_ni, self._MPN, delta)) return eps_p_ij #------------------------------------------------------------------------- # Evaluation - get the corrector and predictor #------------------------------------------------------------------------- def get_corr_pred(self, sctx, eps_app_eng, sigma_kk): # Corrector predictor computation. # ---------------------------------------------------------------------------------------------- # for debugging purposes only: if elastic_debug is switched on, linear elastic material is used # ----------------------------------------------------------------------------------------------- if self.elastic_debug: # NOTE: This must be copied otherwise self.D2_e gets modified when # essential boundary conditions are inserted D2_e = copy(self.D2_e) sig_eng = tensordot(D2_e, eps_app_eng, [[1], [0]]) return sig_eng, D2_e #---------------------------------------------------------------------- # if the regularization using the crack-band concept is on calculate the # effective element length in the direction of principle strains #---------------------------------------------------------------------- # if self.regularization: # h = self.get_regularizing_length(sctx, eps_app_eng) # self.phi_fn.h = h #---------------------------------------------------------------------- # Return stresses (corrector) and damaged secant stiffness matrix (predictor) #---------------------------------------------------------------------- # secant stiffness tensor S_ijkl = self._get_S_4_tns(sctx, eps_app_eng, sigma_kk) # plastic strain tensor eps_p_ij = self._get_eps_p_mtx(sctx, eps_app_eng, sigma_kk) # elastic strain tensor eps_e_mtx = eps_app_eng - eps_p_ij # calculation of the stress tensor sig_eng = einsum('ijmn,mn -> ij', S_ijkl, eps_e_mtx) return sig_eng, S_ijkl
class AbsPlot(AbstractPlot): ''' Absorbance plot. This requires a copy of the data to locally modify so this plot deviates from the methodology I put forward for abstractplots. Namely, a local arrayplotobject (plotdata trait) is stored and completely emptied and repopulated with each event. Decided to just empty and refil because changes in the reference trait, and sampling traits would affect every single sampled line anyway! When sampling the entire dataset, this plot is probably slower than its specdata counterparts because of the excess redraw events.''' def __init__(self, *args, **kwargs): super(AbsPlot, self).__init__(*args, **kwargs) plot_title = Str('Absorbance') ### Note: Since absorbance needs to manipulator data, I actually sync a local copy of ### of array plot data to my plot rather than the original data object #### runstorage_data = DelegatesTo('plothandler', prefix='specdata') plotdata = Instance( ArrayPlotData, ()) #Must retain this traitname for plot defaults and things ### Reference line traits ### low = Int(0) ### THIS IS MESSED UP BECAUSE IT SHOULD BE THE LIST OF T_EFFECTIVES!!!! AKA [1,4,7] AS THE VALID ONES ref_col = Enum( values='t_effective' ) #This trips out if low is an integer and high is a string and high should be t_size-1 def _runstorage_data_changed(self): self.redrawplot( ) #This ensures a new plot is created when the runstorage data object changes #Replot everything def _ref_col_changed(self): for i in self.t_effective: self.plotdata.set_data(self.tlabel[i], \ self.runstorage_data.get_data(self.tlabel[i])/self.runstorage_data.get_data(self.tlabel[self.ref_col])) # @on_trait_change('ref_col, t_sampling, x_sampling') def update_lines(self): ''' Unlike specplot and timeplot, this actually completely deletes all the lineplot renderers, rewrites the entire local dataarray, and replots everything''' #Delete entire dictionary and current lineplots # for plot in self.plot.plots: self.plot.delplot(plot) oldplots = [name for name in self.plot.plots] for entry in self.plotdata.list_data(): self.plotdata.del_data(entry) #Repopulate data object self.plotdata.set_data('x', self.runstorage_data.get_data('x')) for i in self.t_effective: self.plotdata.set_data(self.tlabel[i], \ self.runstorage_data.get_data(self.tlabel[i])/self.runstorage_data.get_data(self.tlabel[self.ref_col])) #Replot everything for name in self.plotdata.list_data(): if name != 'x': self.plot.plot(("x", name), name=name, color=self.color) print self.plot.plots, 'number of plots' self.plot.request_redraw() #Needed so still works after zooming traits_view = View( Item('plot', editor=ComponentEditor(), show_label=False), Include('sample_group'), Item('ref_col', label='Reference Column'), )
class UnstructuredGridReader(FileDataSource): # The version of this class. Used for persistence. __version__ = 0 # The UnstructuredGridAlgorithm data file reader. reader = Instance(tvtk.Object, allow_none=False, record=True) # Information about what this object can produce. output_info = PipelineInfo(datasets=['unstructured_grid']) ###################################################################### # Private Traits _reader_dict = Dict(Str, Instance(tvtk.Object)) # Our view. view = View(Group(Include('time_step_group'), Item(name='base_file_name'), Item(name='reader', style='custom', resizable=True), show_labels=False), resizable=True) ###################################################################### # `object` interface ###################################################################### def __set_pure_state__(self, state): # The reader has its own file_name which needs to be fixed. state.reader.file_name = state.file_path.abs_pth # Now call the parent class to setup everything. super(UnstructuredGridReader, self).__set_pure_state__(state) ###################################################################### # `FileDataSource` interface ###################################################################### def update(self): self.reader.update() if len(self.file_path.get()) == 0: return self.render() def has_output_port(self): """ Return True as the reader has output port.""" return True def get_output_object(self): """ Return the reader output port.""" return self.reader.output_port ###################################################################### # Non-public interface ###################################################################### def _file_path_changed(self, fpath): value = fpath.get() if len(value) == 0: return # Extract the file extension splitname = value.strip().split('.') extension = splitname[-1].lower() # Select UnstructuredGridreader based on file type old_reader = self.reader if extension in self._reader_dict: self.reader = self._reader_dict[extension] else: error('Invalid file extension for file: %s' % value) return old_fname = self.reader.file_name self.reader.file_name = value.strip() self.reader.update_information() if isinstance(self.reader, tvtk.ExodusIIReader): # Make sure the point fields are read during Update(). for k in range(self.reader.number_of_point_result_arrays): arr_name = self.reader.get_point_result_array_name(k) self.reader.set_point_result_array_status(arr_name, 1) self.reader.update() if old_reader is not None: old_reader.on_trait_change(self.render, remove=True) self.reader.on_trait_change(self.render) self.outputs = [self.reader] if old_fname != value: self.data_changed = True # Change our name on the tree view self.name = self._get_name() def _get_name(self): """ Returns the name to display on the tree view. Note that this is not a property getter. """ fname = basename(self.file_path.get()) ret = "%s" % fname if len(self.file_list) > 1: ret += " (timeseries)" if '[Hidden]' in self.name: ret += ' [Hidden]' return ret def __reader_dict_default(self): """Default value for reader dict.""" rd = { 'inp': tvtk.AVSucdReader(), 'neu': tvtk.GAMBITReader(), 'ex2': tvtk.ExodusIIReader() } return rd
class ImageReader(FileDataSource): """A Image file reader. The reader supports all the different types of Image files. """ # The version of this class. Used for persistence. __version__ = 0 # The Image data file reader. reader = Instance(tvtk.Object, allow_none=False, record=True) # Information about what this object can produce. output_info = PipelineInfo(datasets=['image_data']) # Our view. view = View(Group(Include('time_step_group'), Item(name='base_file_name'), Item(name='reader', style='custom', resizable=True), show_labels=False), resizable=True) ###################################################################### # Private Traits _image_reader_dict = Dict(Str, Instance(tvtk.Object)) ###################################################################### # `object` interface ###################################################################### def __init__(self, **traits): d = { 'bmp': tvtk.BMPReader(), 'jpg': tvtk.JPEGReader(), 'png': tvtk.PNGReader(), 'pnm': tvtk.PNMReader(), 'dcm': tvtk.DICOMImageReader(), 'tiff': tvtk.TIFFReader(), 'ximg': tvtk.GESignaReader(), 'dem': tvtk.DEMReader(), 'mha': tvtk.MetaImageReader(), 'mhd': tvtk.MetaImageReader(), } # Account for pre 5.2 VTk versions, without MINC reader if hasattr(tvtk, 'MINCImageReader'): d['mnc'] = tvtk.MINCImageReader() d['jpeg'] = d['jpg'] self._image_reader_dict = d # Call parent class' init. super(ImageReader, self).__init__(**traits) def __set_pure_state__(self, state): # The reader has its own file_name which needs to be fixed. state.reader.file_name = state.file_path.abs_pth # Now call the parent class to setup everything. super(ImageReader, self).__set_pure_state__(state) ###################################################################### # `FileDataSource` interface ###################################################################### def update(self): self.reader.update() if len(self.file_path.get()) == 0: return self.render() def has_output_port(self): """ Return True as the reader has output port.""" return True def get_output_object(self): """ Return the reader output port.""" return self.reader.output_port ###################################################################### # Non-public interface ###################################################################### def _file_path_changed(self, fpath): value = fpath.get() if len(value) == 0: return # Extract the file extension splitname = value.strip().split('.') extension = splitname[-1].lower() # Select image reader based on file type old_reader = self.reader if extension in self._image_reader_dict: self.reader = self._image_reader_dict[extension] else: self.reader = tvtk.ImageReader() self.reader.file_name = value.strip() self.reader.update() self.reader.update_information() if old_reader is not None: old_reader.on_trait_change(self.render, remove=True) self.reader.on_trait_change(self.render) self.outputs = [self.reader] # Change our name on the tree view self.name = self._get_name() def _get_name(self): """ Returns the name to display on the tree view. Note that this is not a property getter. """ fname = basename(self.file_path.get()) ret = "%s" % fname if len(self.file_list) > 1: ret += " (timeseries)" if '[Hidden]' in self.name: ret += ' [Hidden]' return ret
class FESubDomain(HasTraits): # If the constructor specifies the name, then use it # otherwise generate the name based on the domain enumeration. _name = Str('_no_name_') _tree_label = Str('subdomain') tstepper = Property def _get_tstepper(self): return self.domain.dots.tstepper # specification of the container domain # managing all the sub domains _domain = Instance(FEDomain) domain = Property def _set_domain(self, value): 'reset the domain of this domain' if self._domain: # unregister in the old domain raise NotImplementedError( 'FESubDomain cannot be relinked to another FEDomain') self._domain = value # register in the domain as a sub domain self._domain.subdomains.append(self) self._domain._append_in_series(self) def _get_domain(self): return self._domain def validate(self): pass name = Property(Str) def _get_name(self): global _subdomain_counter if self._name == '_no_name_': self._name = self._tree_label + ' ' + str(_subdomain_counter) _subdomain_counter += 1 return self._name def _set_name(self, value): self._name = value # local dof enumeration n_dofs = Int(4, domain_changed=True) # dof offset within the global enumeration dof_offset = Property(Int, depends_on='previous_domain.dof_offset') # cached_property def _get_dof_offset(self): if self.previous_domain: return self.previous_domain.dof_offset + self.previous_domain.n_dofs else: return 0 def __repr__(self): if self.previous_domain: return self.name + ' <- ' + self.previous_domain.name else: return self.name # get the slice for DOFs within global vectors sub_slice = Property def _get_sub_slice(self): return slice(self.dof_offset, self.dof_offset + self.n_dofs) # dependency link for sequential enumeration previous_domain = Instance(IFESubDomain, domain_changed=True) @on_trait_change('previous_domain') def _validate_previous_domain(self): if self.previous_domain == self: raise TraitError('cyclic reference for ' + self.name) # dependency link for sequential enumeration next_domain = Instance(IFESubDomain, domain_changed=True) @on_trait_change('next_domain') def _validate_next_domain(self): if self.next_domain == self: raise TraitError('cyclic reference for ' + self.name) subdomain_group = Group(Item('n_dofs'), Item('dof_offset'), Item('previous_domain'), Item('next_domain'), ) traits_view = View(Include('subdomain_group'), resizable=True, scrollable=True )
class MATS3DMicroplaneDamage(MATSXDMicroplaneDamageFatigue, MATS3DEval): implements(IMATSEval) # number of spatial dimensions n_dim = Constant(3) # number of components of engineering tensor representation n_eng = Constant(6) # number of microplanes - currently fixed for 3D n_mp = Constant(28) # get the normal vectors of the microplanes _MPN = Property(depends_on='n_mp') @cached_property def _get__MPN(self): # microplane normals: return array([[.577350259, .577350259, .577350259], [.577350259, .577350259, -.577350259], [.577350259, -.577350259, .577350259], [.577350259, -.577350259, -.577350259], [.935113132, .250562787, .250562787], [.935113132, .250562787, -.250562787], [.935113132, -.250562787, .250562787], [.935113132, -.250562787, -.250562787], [.250562787, .935113132, .250562787], [.250562787, .935113132, -.250562787], [.250562787, -.935113132, .250562787], [.250562787, -.935113132, -.250562787], [.250562787, .250562787, .935113132], [.250562787, .250562787, -.935113132], [.250562787, -.250562787, .935113132], [.250562787, -.250562787, -.935113132], [.186156720, .694746614, .694746614], [.186156720, .694746614, -.694746614], [.186156720, -.694746614, .694746614], [.186156720, -.694746614, -.694746614], [.694746614, .186156720, .694746614], [.694746614, .186156720, -.694746614], [.694746614, -.186156720, .694746614], [.694746614, -.186156720, -.694746614], [.694746614, .694746614, .186156720], [.694746614, .694746614, -.186156720], [.694746614, -.694746614, .186156720], [.694746614, -.694746614, -.186156720]]) # get the weights of the microplanes # _MPW = Property(depends_on='n_mp') @cached_property def _get__MPW(self): # Note that the values in the array must be multiplied by 6 (cf. [Baz05])! # The sum of of the array equals 0.5. (cf. [BazLuz04])) # The values are given for an Gaussian integration over the unit # hemisphere. return array([ .0160714276, .0160714276, .0160714276, .0160714276, .0204744730, .0204744730, .0204744730, .0204744730, .0204744730, .0204744730, .0204744730, .0204744730, .0204744730, .0204744730, .0204744730, .0204744730, .0158350505, .0158350505, .0158350505, .0158350505, .0158350505, .0158350505, .0158350505, .0158350505, .0158350505, .0158350505, .0158350505, .0158350505 ]) * 6.0 #------------------------------------------------------------------------- # Cached elasticity tensors #------------------------------------------------------------------------- #------------------------------------------------------------------------- # Dock-based view with its own id #------------------------------------------------------------------------- traits_view = View(Include('polar_fn_group'), dock='tab', id='ibvpy.mats.mats3D.mats_3D_cmdm.MATS3D_cmdm', kind='modal', resizable=True, scrollable=True, width=0.6, height=0.8, buttons=['OK', 'Cancel'])
class MATSXDMicroplaneDamageFatigue(MATSEvalMicroplaneFatigue): ''' Microplane Damage Fatigue Model. ''' #------------------------------------------------------------------------- # Classification traits (supplied by the dimensional subclasses) #------------------------------------------------------------------------- # specification of the model dimension (2D, 3D) n_dim = Int # specification of number of engineering strain and stress components n_eng = Int #------------------------------------------------------------------------- # Configuration parameters #------------------------------------------------------------------------- model_version = Enum("compliance", "stiffness") symmetrization = Enum("product-type", "sum-type") regularization = Bool(False, desc='Flag to use the element length projection' ' in the direction of principle strains', enter_set=True, auto_set=False) elastic_debug = Bool( False, desc='Switch to elastic behavior - used for debugging', auto_set=False) double_constraint = Bool( False, desc= 'Use double constraint to evaluate microplane elastic and fracture energy (Option effects only the response tracers)', auto_set=False) #------------------------------------------------------------------------- # View specification #------------------------------------------------------------------------- config_param_vgroup = Group( Item('model_version', style='custom'), # Item('stress_state', style='custom'), Item('symmetrization', style='custom'), Item('elastic_debug@'), Item('double_constraint@'), Spring(resizable=True), label='Configuration parameters', show_border=True, dock='tab', id='ibvpy.mats.matsXD.MATSXD_cmdm.config', ) traits_view = View(Include('polar_fn_group'), dock='tab', id='ibvpy.mats.matsXD.MATSXD_cmdm', kind='modal', resizable=True, scrollable=True, width=0.6, height=0.8, buttons=['OK', 'Cancel']) #------------------------------------------------------------------------- # Setup for computation within a supplied spatial context #------------------------------------------------------------------------- #------------------------------------------------------------------------- # MICROPLANE-DISCRETIZATION RELATED METHOD #------------------------------------------------------------------------- # get the dyadic product of the microplane normals _MPNN = Property(depends_on='n_mp') @cached_property def _get__MPNN(self): # dyadic product of the microplane normals MPNN_nij = einsum('ni,nj->nij', self._MPN, self._MPN) return MPNN_nij # get Third order tangential tensor (operator) for each microplane _MPTT = Property(depends_on='n_mp') @cached_property def _get__MPTT(self): # Third order tangential tensor for each microplane delta = identity(3) MPTT_nijr = 0.5 * ( einsum('ni,jr -> nijr', self._MPN, delta) + einsum('nj,ir -> njir', self._MPN, delta) - 2.0 * einsum('ni,nj,nr -> nijr', self._MPN, self._MPN, self._MPN)) return MPTT_nijr def _get_P_vol(self): delta = identity(3) P_vol_ij = (1 / 3.0) * delta return P_vol_ij def _get_P_dev(self): delta = identity(3) P_dev_njkl = 0.5 * einsum('ni,ij,kl -> njkl', self._MPN, delta, delta) return P_dev_njkl def _get_I_vol_4(self): # The fourth order volumetric-identity tensor delta = identity(3) I_vol_ijkl = (1.0 / 3.0) * einsum('ij,kl -> ijkl', delta, delta) return I_vol_ijkl def _get_I_dev_4(self): # The fourth order deviatoric-identity tensor delta = identity(3) I_dev_ijkl = 0.5 * (einsum('ik,jl -> ijkl', delta, delta) + einsum('il,jk -> ijkl', delta, delta)) \ - (1 / 3.0) * einsum('ij,kl -> ijkl', delta, delta) return I_dev_ijkl def _get_PP_vol_4(self): # outer product of P_vol delta = identity(3) PP_vol_ijkl = (1 / 9.) * einsum('ij,kl -> ijkl', delta, delta) return PP_vol_ijkl def _get_PP_dev_4(self): # inner product of P_dev delta = identity(3) PP_dev_ijkl = 0.5 * (0.5 * (einsum('ni,nk,jl -> nijkl', self._MPN, self._MPN, delta) + einsum('ni,nl,jk -> nijkl', self._MPN, self._MPN, delta)) + 0.5 * (einsum('ik,nj,nl -> nijkl', delta, self._MPN, self._MPN) + einsum('il,nj,nk -> nijkl', delta, self._MPN, self._MPN))) -\ (1 / 3.) * (einsum('ni,nj,kl -> nijkl', self._MPN, self._MPN, delta) + einsum('ij,nk,nl -> nijkl', delta, self._MPN, self._MPN)) +\ (1 / 9.) * einsum('ij,kl -> ijkl', delta, delta) return PP_dev_ijkl def _get_e_vct_arr(self, eps_eng): # Projection of apparent strain onto the individual microplanes e_ni = einsum('nj,ji->ni', self._MPN, eps_eng) return e_ni def _get_e_N_arr(self, e_vct_arr): # get the normal strain array for each microplane eN_n = einsum('ni,ni->n', e_vct_arr, self._MPN) return eN_n def _get_e_T_vct_arr(self, e_vct_arr): # get the tangential strain vector array for each microplane eN_n = self._get_e_N_arr(e_vct_arr) eN_vct_ni = einsum('n,ni->ni', eN_n, self._MPN) return e_vct_arr - eN_vct_ni def _get_state_variables(self, sctx, eps_app_eng, sigma_kk): e_vct_arr = self._get_e_vct_arr(eps_app_eng) # print e_vct_arr.shape sctx_arr = zeros((28, 8)) for i in range(0, self.n_mp): sctx_i = self.get_phi_epspi(e_vct_arr[i, :], sctx[i, :], sigma_kk) sctx_arr[i, :] = sctx_i return sctx_arr def _get_phi_arr(self, sctx, eps_app_eng, sigma_kk): ''' Returns a list of the integrity factors for all microplanes. ''' phi_arr = 1. - \ self._get_state_variables(sctx, eps_app_eng, sigma_kk)[:, 0] return phi_arr def _get_phi_mtx(self, sctx, eps_app_eng, sigma_kk): ''' Returns the 2nd order damage tensor 'phi_mtx' ''' # scalar integrity factor for each microplane phi_arr = self._get_phi_arr(sctx, eps_app_eng, sigma_kk) # integration terms for each microplanes phi_ij = einsum('n,n,nij->ij', phi_arr, self._MPW, self._MPNN) return phi_ij def _get_d_scalar(self, sctx, eps_app_eng, sigma_kk): # scalar integrity factor for each microplane phi_arr = self._get_phi_arr(sctx, eps_app_eng, sigma_kk) d_arr = 1 - phi_arr d = (1.0 / 3.0) * einsum('n,n->', d_arr, self._MPW) print d return d def _get_M_vol_tns(self, sctx, eps_app_eng, sigma_kk): d = self._get_d_scalar(sctx, eps_app_eng, sigma_kk) delta = identity(3) I_4th_ijkl = einsum('ik,jl -> ijkl', delta, delta) return (1 - d) * I_4th_ijkl def _get_M_dev_tns(self, phi_mtx): ''' Returns the 4th order deviatoric damage tensor ''' n_dim = self.n_dim delta = identity(3) # use numpy functionality (einsum) to evaluate [Jir99], Eq.(21) # M_dev_ijkl = 0.25 * (einsum('ik,jl->ijkl', phi_mtx, delta) + # einsum('il,jk->ijkl', phi_mtx, delta) + # einsum('jk,il->ijkl', phi_mtx, delta) + # einsum('jl,ik->ijkl', phi_mtx, delta)) M_dev_ijkl = 0.5 * (0.5 * (einsum('ik,jl->ijkl', delta, phi_mtx) + einsum('il,jk->ijkl', delta, phi_mtx)) + 0.5 * (einsum('ik,jl->ijkl', phi_mtx, delta) + einsum('il,jk->ijkl', phi_mtx, delta))) # print 'M_dev_ijkl', M_dev_ijkl return M_dev_ijkl def _get_eps_pi_arr(self, sctx, eps_app_eng, sigma_kk): # Returns a list of the sliding strain vector for all microplanes. eps_pi_arr = self._get_state_variables(sctx, eps_app_eng, sigma_kk)[:, 5:9] return eps_pi_arr def _get_eps_pi_mtx(self, sctx, eps_app_eng, sigma_kk): # Vector integration of sliding (inelastic) strain for each microplane eps_pi_ni = self._get_eps_pi_arr(sctx, eps_app_eng, sigma_kk) eps_pi_ij = 0.5 * ( einsum('n,ni,nj -> ij', self._MPW, eps_pi_ni, self._MPN) + einsum('n,nj,ni -> ij', self._MPW, eps_pi_ni, self._MPN)) return eps_pi_ij #------------------------------------------------------------------------- # Secant stiffness (irreducible decomposition based on ODFs) #------------------------------------------------------------------------- def _get_S_tns(self, sctx, eps_app_eng, sigma_kk): K0 = self.E / (1. - 2. * self.poisson) G0 = self.E / (1. + self.poisson) I_vol_ijkl = self._get_I_vol_4() I_dev_ijkl = self._get_I_dev_4() # print 'I_vol_ijkl', I_vol_ijkl # print 'I_dev_ijkl', I_dev_ijkl phi_mtx = self._get_phi_mtx(sctx, eps_app_eng, sigma_kk) M_vol_ijkl = self._get_M_vol_tns(sctx, eps_app_eng, sigma_kk) M_dev_ijkl = self._get_M_dev_tns(phi_mtx) S_ijkl = K0 * einsum('ijmn,mnrs,rskl -> ijkl', I_vol_ijkl, M_vol_ijkl, I_vol_ijkl ) \ + G0 * einsum('ijmn,mnrs,rskl -> ijkl', I_dev_ijkl, M_dev_ijkl, I_dev_ijkl)\ S_0_ijkl = K0 * I_vol_ijkl + G0 * I_dev_ijkl print 'S_0_ijkl', S_0_ijkl return S_ijkl #------------------------------------------------------------------------- # Evaluation - get the corrector and predictor #------------------------------------------------------------------------- def get_corr_pred(self, sctx, eps_app_eng, sigma_kk): ''' Corrector predictor computation. @param eps_app_eng input variable - engineering strain ''' # ----------------------------------------------------------------------------------------------- # for debugging purposes only: if elastic_debug is switched on, linear elastic material is used # ----------------------------------------------------------------------------------------------- if self.elastic_debug: # NOTE: This must be copied otherwise self.D2_e gets modified when # essential boundary conditions are inserted D2_e = copy(self.D2_e) sig_eng = tensordot(D2_e, eps_app_eng, [[1], [0]]) return sig_eng, D2_e #---------------------------------------------------------------------- # if the regularization using the crack-band concept is on calculate the # effective element length in the direction of principle strains #---------------------------------------------------------------------- # if self.regularization: # h = self.get_regularizing_length(sctx, eps_app_eng) # self.phi_fn.h = h #---------------------------------------------------------------------- # Return stresses (corrector) and damaged secant stiffness matrix (predictor) #---------------------------------------------------------------------- eps_pi_ij = self._get_eps_pi_mtx(sctx, eps_app_eng, sigma_kk) eps_e_mtx = eps_app_eng - eps_pi_ij S_ijkl = self._get_S_tns(sctx, eps_app_eng, sigma_kk) print 'S_ijkl', S_ijkl sig_eng = einsum('ijkl,kl -> ij', S_ijkl, eps_e_mtx) return sig_eng
class MATS2DMicroplaneDamage(MATSXDMicroplaneDamage, MATS2DEval): implements(IMATSEval) # number of spatial dimensions # n_dim = Constant(2) # number of components of engineering tensor representation # n_eng = Constant(3) # planar constraint stress_state = Enum("plane_strain", "plane_stress") # Specify the class to use for directional dependence mfn_class = Class(MFnPolar) # get the normal vectors of the microplanes _MPN = Property(depends_on='n_mp') @cached_property def _get__MPN(self): return array([[cos(alpha), sin(alpha)] for alpha in self.alpha_list]) # get the weights of the microplanes _MPW = Property(depends_on='n_mp') @cached_property def _get__MPW(self): return ones(self.n_mp) / self.n_mp * 2 elasticity_tensors = Property(depends_on='E, nu, stress_state') @cached_property def _get_elasticity_tensors(self): ''' Intialize the fourth order elasticity tensor for 3D or 2D plane strain or 2D plane stress ''' # ---------------------------------------------------------------------------- # Lame constants calculated from E and nu # ---------------------------------------------------------------------------- E = self.E nu = self.nu # first Lame paramter la = E * nu / ((1 + nu) * (1 - 2 * nu)) # second Lame parameter (shear modulus) mu = E / (2 + 2 * nu) # ----------------------------------------------------------------------------------------------------- # Get the fourth order elasticity and compliance tensors for the 3D-case # ----------------------------------------------------------------------------------------------------- # The following lines correspond to the tensorial expression: # (using numpy functionality in order to avoid the loop): # # D4_e_3D = zeros((3,3,3,3),dtype=float) # C4_e_3D = zeros((3,3,3,3),dtype=float) # delta = identity(3) # for i in range(0,3): # for j in range(0,3): # for k in range(0,3): # for l in range(0,3): # # elasticity tensor (cf. Jir/Baz Inelastic analysis of structures Eq.D25): # D4_e_3D[i,j,k,l] = la * delta[i,j] * delta[k,l] + \ # mu * ( delta[i,k] * delta[j,l] + delta[i,l] * delta[j,k] ) # # elastic compliance tensor (cf. Simo, Computational Inelasticity, Eq.(2.7.16) AND (2.1.16)): # C4_e_3D[i,j,k,l] = (1+nu)/(2*E) * \ # ( delta[i,k] * delta[j,l] + delta[i,l]* delta[j,k] ) - \ # nu / E * delta[i,j] * delta[k,l] # # NOTE: swapaxes returns a reference not a copy! # (the index notation always refers to the initial indexing (i=0,j=1,k=2,l=3)) delta = identity(3) delta_ijkl = outer(delta, delta).reshape(3, 3, 3, 3) delta_ikjl = delta_ijkl.swapaxes(1, 2) delta_iljk = delta_ikjl.swapaxes(2, 3) D4_e_3D = la * delta_ijkl + mu * (delta_ikjl + delta_iljk) C4_e_3D = -nu / E * delta_ijkl + \ (1 + nu) / (2 * E) * (delta_ikjl + delta_iljk) # ----------------------------------------------------------------------------------------------------- # Get the fourth order elasticity and compliance tensors for the 2D-case # ----------------------------------------------------------------------------------------------------- # 1. step: Get the (6x6)-elasticity and compliance matrices # for the 3D-case: D2_e_3D = map3d_tns4_to_tns2(D4_e_3D) C2_e_3D = map3d_tns4_to_tns2(C4_e_3D) # 2. step: Get the (3x3)-elasticity and compliance matrices # for the 2D-cases plane stress and plane strain: D2_e_2D_plane_stress = get_D_plane_stress(D2_e_3D) D2_e_2D_plane_strain = get_D_plane_strain(D2_e_3D) C2_e_2D_plane_stress = get_C_plane_stress(C2_e_3D) C2_e_2D_plane_strain = get_C_plane_strain(C2_e_3D) if self.stress_state == 'plane_stress': D2_e = D2_e_2D_plane_stress if self.stress_state == 'plane_strain': D2_e = D2_e_2D_plane_strain # 3. step: Get the fourth order elasticity and compliance tensors # for the 2D-cases plane stress and plane strain (D4.shape = (2,2,2,2)) D4_e_2D_plane_stress = map2d_tns2_to_tns4(D2_e_2D_plane_stress) D4_e_2D_plane_strain = map2d_tns2_to_tns4(D2_e_2D_plane_strain) C4_e_2D_plane_stress = map2d_tns2_to_tns4(C2_e_2D_plane_stress) C4_e_2D_plane_strain = map2d_tns2_to_tns4(C2_e_2D_plane_strain) # ----------------------------------------------------------------------------------------------------- # assign the fourth order elasticity and compliance tensors as return values # ----------------------------------------------------------------------------------------------------- if self.stress_state == 'plane_stress': # print 'stress state: plane-stress' D4_e = D4_e_2D_plane_stress C4_e = C4_e_2D_plane_stress if self.stress_state == 'plane_strain': # print 'stress state: plane-strain' D4_e = D4_e_2D_plane_strain C4_e = C4_e_2D_plane_strain return D4_e, C4_e, D2_e def _get_explorer_config(self): '''Get the specific configuration of this material model in the explorer ''' c = super(MATS2DMicroplaneDamage, self)._get_explorer_config() from ibvpy.mats.mats2D.mats2D_rtrace_cylinder import MATS2DRTraceCylinder # overload the default configuration c['rtrace_list'] += [ MATS2DRTraceCylinder(name='Laterne', var_axis='time', idx_axis=0, var_surface='microplane_damage', record_on='update'), ] return c #------------------------------------------------------------------------- # Dock-based view with its own id #------------------------------------------------------------------------- traits_view = View(Include('polar_fn_group'), dock='tab', id='ibvpy.mats.mats3D.mats_2D_cmdm.MATS2D_cmdm', kind='modal', resizable=True, scrollable=True, width=0.6, height=0.8, buttons=['OK', 'Cancel'])
class RTDofGraph(RTrace, BMCSLeafNode, Vis2D): ''' Collects two response evaluators to make a response graph. The supplied strings for var_x and var_y are used to locate the rte in the current response manager. The bind method is used to navigate to the rte and is stored in here as var_x_eval and var_y_val as Callable object. The request for new response evaluation is launched by the time loop and directed futher by the response manager. This method is used solely for collecting the data, not for their visualization in the viewer. The timer_tick method is invoked when the visualization of the Graph should be synchronized with the actual contents. ''' label = Str('RTDofGraph') var_x = Str('', label='Variable on x', enter_set=True, auto_set=False) cum_x = Bool(label='Cumulative x', enter_set=True, auto_set=False) var_x_eval = Callable(trantient=True) idx_x = Int(-1, enter_set=True, auto_set=False) var_y = Str('', label='Variable on y', enter_set=True, auto_set=False) cum_y = Bool(label='Cumulative y', enter_set=True, auto_set=False) var_y_eval = Callable(trantient=True) idx_y = Int(-1, enter_set=True, auto_set=False) transform_x = Str(enter_set=True, auto_set=False) transform_y = Str(enter_set=True, auto_set=False) trace = Instance(MFnLineArray) _tdata = List(np.float) def _trace_default(self): return MFnLineArray() print_button = ToolbarButton('Print values', style='toolbar', trantient=True) @on_trait_change('print_button') def print_values(self, event=None): print('x:\t', self.trace.xdata, '\ny:\t', self.trace.ydata) _xdata = List(Array(float)) _ydata = List(Array(float)) def bind(self): ''' Locate the evaluators ''' self.var_x_eval = self.rmgr.rte_dict.get(self.var_x, None) if self.var_x_eval == None: raise KeyError('Variable %s not present in the dictionary:\n%s' % \ (self.var_x, list(self.rmgr.rte_dict.keys()))) self.var_y_eval = self.rmgr.rte_dict.get(self.var_y, None) if self.var_y_eval == None: raise KeyError('Variable %s not present in the dictionary:\n%s' % \ (self.var_y, list(self.rmgr.rte_dict.keys()))) def setup(self): self.clear() def close(self): self.write() def write(self): '''Generate the file name within the write_dir and submit the request for writing to the writer ''' # self.writer.scalars_name = self.name file_base_name = 'rtrace_diagramm_%s (%s,%s).dat' % \ (self.label, self.var_x, self.var_y) # full path to the data file file_name = os.path.join(self.dir, file_base_name) # file_rtrace = open( file_name, 'w' ) self.refresh() np.savetxt(file_name, np.vstack([self.trace.xdata, self.trace.ydata]).T) # pickle.dump( self, file_rtrace ) # file.close() def add_current_values(self, sctx, U_k, t, *args, **kw): ''' Invoke the evaluators in the current context for the specified control vector U_k. ''' x = self.var_x_eval(sctx, U_k, *args, **kw) y = self.var_y_eval(sctx, U_k, *args, **kw) self.add_pair(x.flatten(), y.flatten(), t) def add_pair(self, x, y, t): if self.cum_x and len(self._xdata) > 0: self._xdata.append(self._xdata[-1] + x) else: self._xdata.append(np.copy(x)) if self.cum_y and len(self._ydata) > 0: self._ydata.append(self._ydata[-1] + y) else: self._ydata.append(np.copy(y)) self._tdata.append(t) @on_trait_change('idx_x,idx_y') def redraw(self, e=None): if (self._xdata == [] or self._ydata == []): return # xarray = np.array(self._xdata)[:, self.idx_x] yarray = np.array(self._ydata)[:, self.idx_y] if self.transform_x: def transform_x_fn(x): '''makes a callable function out of the Str-attribute "transform_x". The vectorised version of this function is then used to transform the values in "xarray". Note that the function defined in "transform_x" must be defined in terms of a lower case variable "x". ''' return eval(self.transform_x) xarray = np.frompyfunc(transform_x_fn, 1, 1)(xarray) if self.transform_y: def transform_y_fn(y): '''makes a callable function out of the Str-attribute "transform_y". The vectorised version of this function is then used to transform the values in "yarray". Note that the function defined in "transform_y" must be defined in terms of a lower case variable "y". ''' return eval(self.transform_y) yarray = np.frompyfunc(transform_y_fn, 1, 1)(yarray) self.trace.xdata = np.array(xarray) self.trace.ydata = np.array(yarray) self.trace.replot() def timer_tick(self, e=None): # @todo: unify with redraw pass def clear(self): self._xdata = [] self._ydata = [] self._tdata = [] self.trace.clear() self.redraw() viz2d_classes = {'diagram': RTraceViz2D} traits_view = View(VSplit( VGroup( HGroup( VGroup( HGroup(Spring(), Item('var_x', style='readonly'), Item('idx_x', show_label=False)), Item('transform_x')), VGroup( HGroup(Spring(), Item('var_y', style='readonly'), Item('idx_y', show_label=False)), Item('transform_y')), VGroup('record_on', 'clear_on')), HGroup(Item('refresh_button', show_label=False), Item('print_button', show_label=False)), ), Item('trace@', show_label=False, resizable=True), ), buttons=[OKButton, CancelButton], resizable=True, scrollable=True, height=0.5, width=0.5) tree_view = View( Include('actions'), Item('var_x', style='readonly'), Item('idx_x', show_label=False), )
class AbsPlotDEPRECATE(AbstractPlot): ### Right now this works by presenting user a range of values for ref, ### but only updates plot when the actual value is a line in the plot ### can i implement enum as well using this ref and plot_ref double variable? low = Int(0) ref = Range( low='low', high='t_size', value=5) #This trips out if low is an integer and high is a string! plot_ref = Int(5) ref_color = Str('red') #### TRYIGN TO USE ENUM EXCEPT SOMETIMES IT GETS RESET TO 0 !!!! ### ### Get teh closest value in a list of similar value, ripped off from online ### def closest(self, target, collection): print 'target is', target print 'collection is', collection new = min((abs(target - i), i) for i in collection)[1] print 'returing', new return new @on_trait_change('ref') def update_ref(self): if self.closest(self.ref, self.t_effective) != self.plotref: self.update_lines() @on_trait_change('t_spacing') def update_lines(self): ### CHANGES PLOTS BASED ON LOCAL VARIABLES ### self.plotref = self.ref print 'updating plotref', self.plotref newplots = [self.tlabel[i] for i in self.t_effective] refplot = self.tlabel[self.plotref] oldplots = [name for name in self.plot.plots] toadd = [plot for plot in newplots if plot not in oldplots] todelete = [plot for plot in oldplots if plot not in newplots] if self.plot.plots != {}: todelete.append(refplot) for name in todelete: self.plot.delplot(name) for name in toadd: # data=self.plothandler.specdata[name]/self.plothandler.specdata[refplot] # print data, 'hewre' if name != self.tlabel[self.plotref]: self.plot.plot(("x", name), name=name, color=self.color) else: self.plot.plot(("x", name), name=name, color=self.ref_color) #JUST CHANGE COLOR, OR ADD A FIND REFERENCE METHOD!!! self.plot.request_redraw() #Needed so still works after zooming traits_view = View(VGroup( Include('abstract_group'), HGroup(Item('ref'), Item('ref', style='readonly'), Item('ref_color'))), resizable=True)
class MATS3DMicroplaneM7(MATSXDMicroplaneM7): # implements(IMATSEval) #----------------------------------------------- # number of microplanes - currently fixed for 3D #----------------------------------------------- n_mp = Constant(28) #----------------------------------------------- # get the normal vectors of the microplanes #----------------------------------------------- _MPN = Property(depends_on='n_mp') @cached_property def _get__MPN(self): # microplane normals: return array([[.577350259, .577350259, .577350259], [.577350259, .577350259, -.577350259], [.577350259, -.577350259, .577350259], [.577350259, -.577350259, -.577350259], [.935113132, .250562787, .250562787], [.935113132, .250562787, -.250562787], [.935113132, -.250562787, .250562787], [.935113132, -.250562787, -.250562787], [.250562787, .935113132, .250562787], [.250562787, .935113132, -.250562787], [.250562787, -.935113132, .250562787], [.250562787, -.935113132, -.250562787], [.250562787, .250562787, .935113132], [.250562787, .250562787, -.935113132], [.250562787, -.250562787, .935113132], [.250562787, -.250562787, -.935113132], [.186156720, .694746614, .694746614], [.186156720, .694746614, -.694746614], [.186156720, -.694746614, .694746614], [.186156720, -.694746614, -.694746614], [.694746614, .186156720, .694746614], [.694746614, .186156720, -.694746614], [.694746614, -.186156720, .694746614], [.694746614, -.186156720, -.694746614], [.694746614, .694746614, .186156720], [.694746614, .694746614, -.186156720], [.694746614, -.694746614, .186156720], [.694746614, -.694746614, -.186156720]]) #------------------------------------- # get the weights of the microplanes #------------------------------------- _MPW = Property(depends_on='n_mp') @cached_property def _get__MPW(self): # Note that the values in the array must be multiplied by 6 (cf. [Baz05])! # The sum of of the array equals 0.5. (cf. [BazLuz04])) # The values are given for an Gaussian integration over the unit # hemisphere. return array([.0160714276, .0160714276, .0160714276, .0160714276, .0204744730, .0204744730, .0204744730, .0204744730, .0204744730, .0204744730, .0204744730, .0204744730, .0204744730, .0204744730, .0204744730, .0204744730, .0158350505, .0158350505, .0158350505, .0158350505, .0158350505, .0158350505, .0158350505, .0158350505, .0158350505, .0158350505, .0158350505, .0158350505]) * 6.0 #------------------------------------------------------------------------- # Cached elasticity tensors #------------------------------------------------------------------------- @cached_property def _get_elasticity_tensors(self): ''' Intialize the fourth order elasticity tensor for 3D or 2D plane strain or 2D plane stress ''' # ---------------------------------------------------------------------------- # Lame constants calculated from E and nu # ---------------------------------------------------------------------------- # first Lame paramter la = self.E * self.nu / ((1 + self.nu) * (1 - 2 * self.nu)) # second Lame parameter (shear modulus) mu = self.E / (2 + 2 * self.nu) # ----------------------------------------------------------------------------------------------------- # Get the fourth order elasticity and compliance tensors for the 3D-case # ----------------------------------------------------------------------------------------------------- # construct the elasticity tensor (using Numpy - einsum function) delta = identity(3) D_ijkl = (einsum(',ij,kl->ijkl', la, delta, delta) + einsum(',ik,jl->ijkl', mu, delta, delta) + einsum(',il,jk->ijkl', mu, delta, delta)) return D_ijkl #------------------------------------------------------------------------- # Dock-based view with its own id #------------------------------------------------------------------------- traits_view = View(Include('polar_fn_group'), dock='tab', id='ibvpy.mats.mats3D.mats_3D_cmdm.MATS3D_cmdm', kind='modal', resizable=True, scrollable=True, width=0.6, height=0.8, buttons=['OK', 'Cancel'] )
class AbstractPlot(HasTraits): '''Plot with specific handlers and listeners to coordinate local and global changes in the data controlled by the RunStorage class ''' ### Do I need a special object to store lines/plots apart from what is here? ### implements(IPlot) plot = Instance(ToolbarPlot) plothandler = Instance(IRunStorage) #Must be initialized with this plot_title = Str('General Plot') color = Str('black') ### Plot Axis Traits ### x_axis_title = Str('Wavelength') #For easy editing x_axis_samples = Int(10) #Controls number of labels on the x-axis t_axis_title = Str('Samples') #For easy editing t_axis_samples = Int(10) #Controls number of labels on the x-axis ### Runstorage Traits ### plotdata = Instance( ArrayPlotData) #THESE DELEGATE TO PLOTHANDLER IN INHERETING CLASSES xlabel = List(Str) tlabel = List(Str) ### Averaging and local sampling variables ### x_size = Property(Int, depends_on='xlabel') x_samp_style = Enum('Bifurcating', 'Any') x_samples = Property( Array, depends_on='x_size, x_samp_style' ) #This stores a list of i % 2 valid sampling increments x_spacing = Enum(values='x_samples', style='custom') x_effective = Property(Array, depends_on='x_samples, x_spacing') t_size = Property(Int, depends_on='tlabel') #THIS TRAIT AINT EVEN IN MY PROGRAM t_samp_style = Enum('Bifurcating', 'Any') t_samples = Property( Array, depends_on='t_size, t_samp_style' ) #This stores a list of i % 2 valid sampling increments t_spacing = Enum(values='t_samples', style='custom') t_effective = Property( Array, depends_on='t_samples, t_spacing' ) #This is the effective list of indicies [1,3,5,7] for example depending on spacing variables ### Local averaging traits ### x_avg = Int #AVERAGING METHODS ARE NOT YET SUPPORTED! t_avg = Int #Autoreset when twoD data is changed window = Enum('flat , hanning , hamming , bartlett , blackman') ###### def __init__(self, *args, **kwargs): super(AbstractPlot, self).__init__(*args, **kwargs) self.draw_plot() #self.update_lines() ## IF I CAN THINK OF A WAY TO TRIGGER THIS ON FIRST UPDATE, DON'T NEED THIS ###Global Event Listeners @on_trait_change('plotdata') def redrawplot(self): print 'Plot detects data change' self.draw_plot() self.update_lines() ###Local Event listeners def _t_spacing_changed(self): self.update_lines() def _x_spacing_changed(self): self.update_lines() def update_lines(self): ''' Function that will change sampling and other aspects of lines already drawn on plot''' pass ### Averaging methods # def _x_bisect_spacing_changed(self): CAN RESET LOCAL AVERAGING # if self.x_bisect_spacing > 9: # self.x_bisect_spacing=3 ### Sampling properties/methods ### ### Eventually make the bottom two properties the return of a single function to remove the duplication ### @cached_property def _get_x_size(self): return len(self.xlabel) @cached_property def _get_t_size(self): return len(self.tlabel) @cached_property def _get_x_samples(self): if self.x_samp_style == 'Bifurcating': #Factorize by 2 validx = [] i = self.x_size / 2 #Ignores the first sampling size while i % 2 == 0: validx.append(i) i = i / 2 validx.append(1) validx.reverse() elif self.x_samp_style == 'Any': #CHANGE THIS LATER TO ACTUALLY PRESENT A LIST OF PERCENTS (1, 2, 3, 4 ETC...) validx = range(1, self.x_size / 2) #Any valid number between 1 and half sample size return validx def _set_x_samples(self, x_samples): ''' Global overrides through plothandler will pass these down ''' self.x_samples = x_samples @cached_property def _get_t_samples(self): if self.t_samp_style == 'Bifurcating': validt = [] i = self.t_size / 2 #Ignores the first sampling size while i % 2 == 0: validt.append(i) i = i / 2 validt.append(1) validt.reverse() elif self.t_samp_style == 'Any': validt = range(1, self.t_size / 2) #Any valid number between 1 and half sample size return validt @cached_property def _get_t_effective(self): return [i for i in range(0, self.t_size, self.t_spacing)] @cached_property def _get_x_effective(self): return [i for i in range(0, self.x_size, self.x_spacing)] ### Aesthetic TRAITS ### def _plot_title_changed(self): self.plot.title = self.plot_title self.plot.request_redraw() #Necessary def _x_axis_title_changed(self): self.plot.index_axis.title = self.x_axis_title self.plot.request_redraw() def _t_axis_title_changed(self): self.plot.request_redraw() self.plot.value_axis.title = self.t_axis_title # def _x_axis_samples_changed(self): # self.plot.index_axis.positions= # NEed to define new positions and labels accordingly, or maybe just redraw the axis ### Leve this method intact. When data changes, if I just dot plot.data=newdata-request_redraw it doesn't work! def draw_plot(self): '''Use this method as a way to either default a plot or call a full remake for when a global datasource changes. Datasource as an input also lets me easily adapt plot behavior when using inheritance ''' plot = ToolbarPlot(self.plotdata) #CHANGE FOR OTHER PLOTS plot.title = self.plot_title plot.padding = 50 plot.legend.visible = False plot.tools.append(PanTool(plot)) zoom = BetterSelectingZoom(component=plot, tool_mode="box", always_on=False) plot.overlays.append(zoom) plot.index_axis = LabelAxis( plot, orientation='bottom', positions=range(self.x_axis_samples), labels=['X0', 'X1', 'X2', 'X3', 'X4', 'X5'], resizable='hv', title=self.x_axis_title) plot.value_axis = LabelAxis( plot, orientation='left', positions=range(self.t_axis_samples), labels=['t1', 't2', 't3', 't4', 't5', 't6'], resizable='hv', title=self.t_axis_title) self.plot = plot return axis_traits_group = HGroup(Item('x_axis_title'), Item('t_axis_title'), Item('plot_title')) sample_group = Group(HGroup(Item('t_spacing'), Item('t_samp_style'))) traits_view = View( Item('plot', editor=ComponentEditor(), show_label=False), Include('sample_group'), Include('axis_traits_group'))