示例#1
0
 def bleedthrough_traits_view(self):
     return View(HGroup(Item('channel', style = 'readonly'),
                        Item('file', show_label = False),
                        show_labels = False),
                 handler = self)
示例#2
0
class NMR(Pulsed):

    mwA_frequency = Range(low=1,
                          high=20e9,
                          value=2.87405e+09,
                          desc='microwave A frequency',
                          label='MW frequency [Hz]',
                          mode='text',
                          auto_set=False,
                          enter_set=True)
    mwA_power = Range(low=-100.,
                      high=25.,
                      value=-19,
                      desc='microwave A power',
                      label='MW power [dBm]',
                      mode='text',
                      auto_set=False,
                      enter_set=True)
    t_pi_A = Range(low=1.,
                   high=100000.,
                   value=1040.,
                   desc='length of pi pulse of MW A[ns]',
                   label='pi [ns]',
                   mode='text',
                   auto_set=False,
                   enter_set=True)

    mwB_frequency = Range(low=1,
                          high=20e9,
                          value=2.880965e9,
                          desc='microwave B frequency',
                          label='MW frequency [Hz]',
                          mode='text',
                          auto_set=False,
                          enter_set=True)
    mwB_power = Range(low=-100.,
                      high=25.,
                      value=-19,
                      desc='microwave B power',
                      label='MW power [dBm]',
                      mode='text',
                      auto_set=False,
                      enter_set=True)
    t_pi_B = Range(low=1.,
                   high=100000.,
                   value=1020.,
                   desc='length of pi pulse of MW B[ns]',
                   label='pi [ns]',
                   mode='text',
                   auto_set=False,
                   enter_set=True)

    rf_power = Range(low=-130.,
                     high=25.,
                     value=-20,
                     desc='RF power',
                     label='RF power [dBm]',
                     mode='text',
                     auto_set=False,
                     enter_set=True)
    rf_begin = Range(low=1,
                     high=200e6,
                     value=2.4e6,
                     desc='Start Frequency [Hz]',
                     label='RF Begin [Hz]',
                     mode='text',
                     auto_set=False,
                     enter_set=True)
    rf_end = Range(low=1,
                   high=200e6,
                   value=2.7e6,
                   desc='Stop Frequency [Hz]',
                   label='RF End [Hz]',
                   mode='text',
                   auto_set=False,
                   enter_set=True)
    rf_delta = Range(low=1e-3,
                     high=200e6,
                     value=2.0e3,
                     desc='frequency step [Hz]',
                     label='Delta [Hz]',
                     mode='text',
                     auto_set=False,
                     enter_set=True)
    rf_t_pi = Range(low=1.,
                    high=1.e7,
                    value=1.e6,
                    desc='length of pi pulse of RF[ns]',
                    label='RF pi [ns]',
                    mode='text',
                    auto_set=False,
                    enter_set=True)
    # ESR:
    """
    rf_begin        = Range(low=1,      high=10e9, value=2.8e9,    desc='Start Frequency [Hz]',    label='RF Begin [Hz]')
    rf_end          = Range(low=1,      high=10e9, value=2.9e9,    desc='Stop Frequency [Hz]',     label='RF End [Hz]')
    rf_delta        = Range(low=1e-3,   high=10e9, value=1e6,       desc='frequency step [Hz]',     label='Delta [Hz]')
    """
    laser = Range(low=1.,
                  high=1.0e7,
                  value=3000.,
                  desc='laser [ns]',
                  label='laser [ns]',
                  mode='text',
                  auto_set=False,
                  enter_set=True)
    wait = Range(low=1.,
                 high=1.0e7,
                 value=2.0e6,
                 desc='wait [ns]',
                 label='wait [ns]',
                 mode='text',
                 auto_set=False,
                 enter_set=True)

    seconds_per_point = Range(low=0.1,
                              high=10.,
                              value=0.5,
                              desc='Seconds per point',
                              label='Seconds per point',
                              mode='text',
                              auto_set=False,
                              enter_set=True)
    sweeps_per_point = Int()
    run_time = Float(value=0.0)

    frequencies = Array(value=np.array((0., 1.)))

    def generate_sequence(self):
        # ESR:
        #return 100*[ (['laser','aom'], self.laser), ([],self.wait), (['mw'], self.mw_t_pi), (['sequence'], 10) ]
        return 100 * [(['laser', 'aom'], self.laser), ([], self.wait),
                      (['mw_b'], self.t_pi_B), (['rf'], self.rf_t_pi),
                      ([], 500), (['aom'], self.laser), ([], self.wait),
                      (['mw'], self.t_pi_A), (['rf'], self.rf_t_pi), ([], 500),
                      (['mw'], self.t_pi_A), (['sequence'], 10)]

    def apply_parameters(self):
        """Apply the current parameters and decide whether to keep previous data."""

        frequencies = np.arange(self.rf_begin, self.rf_end + self.rf_delta,
                                self.rf_delta)
        n_bins = int(self.record_length / self.bin_width)
        time_bins = self.bin_width * np.arange(n_bins)
        sequence = self.generate_sequence()

        if not (
                self.keep_data and sequence == self.sequence
                and np.all(time_bins == self.time_bins)
                and np.all(frequencies == self.frequencies)
        ):  # if the sequence and time_bins are the same as previous, keep existing data
            self.count_data = np.zeros((len(frequencies), n_bins))
            self.run_time = 0.0

        self.frequencies = frequencies
        self.sequence = sequence
        self.time_bins = time_bins
        self.n_bins = n_bins
        # ESR:
        #self.sweeps_per_point = int(self.seconds_per_point * 1e9 / (self.laser+self.wait+self.mw_t_pi))
        self.sweeps_per_point = int(
            np.max((1,
                    int(self.seconds_per_point * 1e9 /
                        (self.laser * 2 + self.wait * 2 + 2 * self.t_pi_A +
                         self.t_pi_B + 2 * self.rf_t_pi + 1000.0)))))
        self.keep_data = True  # when job manager stops and starts the job, data should be kept. Only new submission should clear data.

    def _run(self):
        """Acquire data."""

        try:  # try to run the acquisition from start_up to shut_down
            self.state = 'run'
            self.apply_parameters()
            ha.PulseGenerator().Night()
            ha.Microwave().setOutput(self.mwA_power, self.mwA_frequency)
            ha.MicrowaveD().setOutput(self.mwB_power, self.mwB_frequency)
            tagger = ha.TimeTagger.Pulsed(self.n_bins,
                                          int(np.round(self.bin_width * 1000)),
                                          1, 0, 2, 3)
            tagger.setMaxCounts(self.sweeps_per_point)
            ha.PulseGenerator().Sequence(self.sequence)
            ha.RFSource().setMode()

            while True:

                if self.thread.stop_request.isSet():
                    break

                t_start = time.time()

                for i, fi in enumerate(self.frequencies):

                    # ESR:
                    #ha.Microwave().setOutput(self.mw_power,fi)
                    ha.RFSource().setOutput(self.rf_power, fi)
                    tagger.clear()
                    while not tagger.ready():
                        time.sleep(1.1 * self.seconds_per_point)
                    self.count_data[i, :] += tagger.getData()[0]

                self.trait_property_changed('count_data', self.count_data)
                self.run_time += time.time() - t_start

            del tagger
            ha.PulseGenerator().Light()
            ha.Microwave().setOutput(None, self.mwA_frequency)
            ha.MicrowaveD().setOutput(None, self.mwB_frequency)
            ha.RFSource().setOutput(None, self.rf_begin)
        finally:  # if anything fails, recover
            self.state = 'idle'
            ha.PulseGenerator().Light()

    get_set_items = Pulsed.get_set_items + [
        'mwA_frequency', 'mwA_power', 't_pi_A', 'mwB_frequency', 'mwB_power',
        't_pi_B', 'rf_power', 'rf_begin', 'rf_end', 'rf_delta', 'rf_t_pi',
        'laser', 'wait', 'seconds_per_point', 'frequencies', 'count_data',
        'sequence'
    ]

    traits_view = View(
        VGroup(
            HGroup(
                Item('submit_button', show_label=False),
                Item('remove_button', show_label=False),
                Item('resubmit_button', show_label=False),
                Item('priority', width=-40),
                Item('state', style='readonly'),
                Item('run_time', style='readonly'),
            ),
            Tabbed(
                VGroup(HGroup(
                    Item('mwA_power', width=-40),
                    Item('mwA_frequency',
                         width=-80,
                         editor=TextEditor(auto_set=False,
                                           enter_set=True,
                                           evaluate=float,
                                           format_func=lambda x: '%e' % x)),
                    Item('t_pi_A', width=-80),
                ),
                       HGroup(
                           Item('mwB_power', width=-40),
                           Item('mwB_frequency',
                                width=-80,
                                editor=TextEditor(
                                    auto_set=False,
                                    enter_set=True,
                                    evaluate=float,
                                    format_func=lambda x: '%e' % x)),
                           Item('t_pi_B', width=-80),
                       ),
                       HGroup(
                           Item('rf_power', width=-40),
                           Item('rf_begin',
                                width=-80,
                                editor=TextEditor(
                                    auto_set=False,
                                    enter_set=True,
                                    evaluate=float,
                                    format_func=lambda x: '%e' % x)),
                           Item('rf_end',
                                width=-80,
                                editor=TextEditor(
                                    auto_set=False,
                                    enter_set=True,
                                    evaluate=float,
                                    format_func=lambda x: '%e' % x)),
                           Item('rf_delta',
                                width=-80,
                                editor=TextEditor(
                                    auto_set=False,
                                    enter_set=True,
                                    evaluate=float,
                                    format_func=lambda x: '%e' % x)),
                           Item('rf_t_pi', width=-80),
                       ),
                       label='parameter'),
                VGroup(HGroup(
                    Item('laser', width=-80, enabled_when='state == "idle"'),
                    Item('wait', width=-80, enabled_when='state == "idle"'),
                    Item('record_length',
                         width=-80,
                         enabled_when='state == "idle"'),
                    Item('bin_width',
                         width=-80,
                         enabled_when='state == "idle"'),
                ),
                       HGroup(
                           Item('seconds_per_point',
                                width=-120,
                                enabled_when='state == "idle"'),
                           Item('sweeps_per_point',
                                width=-120,
                                style='readonly'),
                       ),
                       label='settings'),
            ),
        ),
        title='NMR, use frequencies to fit',
    )
示例#3
0
 def traits_view(self):
     v = View(UItem('container', editor=ComponentEditor()),
              resizable=True,
              handler=self.handler_klass)
     return v
示例#4
0
class Controller(HasTraits):
    # A reference to the plot viewer object

    # Some parameters controller the random signal that will be generated
    distribution_type = Enum("normal")
    mean = Float(0.0)
    stddev = Float(1.0)

    # The max number of data points to accumulate and show in the plot
    max_num_points = Int(100)

    # The number of data points we have received; we need to keep track of
    # this in order to generate the correct x axis data series.
    num_ticks = Int(0)

    # private reference to the random number generator.  this syntax
    # just means that self._generator should be initialized to
    # random.normal, which is a random number function, and in the future
    # it can be set to any callable object.
    _generator = Trait(np.random.normal, Callable)

    view = View(Group('distribution_type',
                      'mean',
                      'stddev',
                      'max_num_points',
                      orientation="vertical"),
                buttons=["OK", "Cancel"])

    def timer_tick(self, *args):
        """
        Callback function that should get called based on a timer tick.  This
        will generate a new random data point and set it on the `.data` array
        of our viewer object.
        """
        # Generate a new number and increment the tick count
        # x, y, z=accel.read()

        # ADXL345 address, 0x53(83)

        # Select bandwidth rate register, 0x2C(44)

        #		0x0A(10)	Normal mode, Output data rate = 100 Hz

        bus.write_byte_data(0x53, 0x2C, 0x0A)

        # ADXL345 address, 0x53(83)

        # Select power control register, 0x2D(45)

        #		0x08(08)	Auto Sleep disable

        bus.write_byte_data(0x53, 0x2D, 0x08)

        # ADXL345 address, 0x53(83)

        # Select data format register, 0x31(49)

        #		0x08(08)	Self test disabled, 4-wire interface

        #					Full resolution, Range = +/-2g

        bus.write_byte_data(0x53, 0x31, 0x08)

        # time.sleep(0.5)

        # ADXL345 address, 0x53(83)

        # Read data back from 0x32(50), 2 bytes

        # X-Axis LSB, X-Axis MSB

        data0 = bus.read_byte_data(0x53, 0x32)

        data1 = bus.read_byte_data(0x53, 0x33)

        # Convert the data to 10-bits

        xAccl = ((data1 & 0x03) * 256) + data0

        if xAccl > 511:
            xAccl -= 1024

        # ADXL345 address, 0x53(83)

        # Read data back from 0x34(52), 2 bytes

        # Y-Axis LSB, Y-Axis MSB

        data0 = bus.read_byte_data(0x53, 0x34)

        data1 = bus.read_byte_data(0x53, 0x35)

        # Convert the data to 10-bits

        yAccl = ((data1 & 0x03) * 256) + data0

        if yAccl > 511:
            yAccl -= 1024

        # ADXL345 address, 0x53(83)

        # Read data back from 0x36(54), 2 bytes

        # Z-Axis LSB, Z-Axis MSB

        data0 = bus.read_byte_data(0x53, 0x36)

        data1 = bus.read_byte_data(0x53, 0x37)

        # Convert the data to 10-bits

        zAccl = ((data1 & 0x03) * 256) + data0

        if zAccl > 511:
            zAccl -= 1024

        # Output data to screen

        # print "Acceleration in X-Axis : %d" %xAccl

        # print "Acceleration in Y-Axis : %d" %yAccl

        # print "Acceleration in Z-Axis : %d" %zAccl
        new_val = xAccl
        self.num_ticks += 1

        # grab the existing data, truncate it, and append the new point.
        # This isn't the most efficient thing in the world but it works.
        cur_data = self.viewer.data
        new_data = np.hstack((cur_data[-self.max_num_points + 1:], [new_val]))
        new_index = np.arange(self.num_ticks - len(new_data) + 1,
                              self.num_ticks + 0.01)

        self.viewer.index = new_index
        self.viewer.data = new_data
        return

    def _distribution_type_changed(self):
        # This listens for a change in the type of distribution to use.
        while True:
            # Read the X, Y, Z axis acceleration values and print them.
            x, y, z = accel.read()
            print('X={0}, Y={1}, Z={2}'.format(x, y, z))
            # Wait half a second and repeat.
            time.sleep(0.1)
        self._generator = x
示例#5
0
class J2(YieldFaceCPP):
    '''
    Current version by Jakub (16.09.2008)
    '''

    sigma_y = Float(100.)
    cronecker_delta = array([1., 1., 0.])
    P = diag([1., 1., 2.])

    def get_f_trial(self, xi_trial, q_1):
        xi_v = (xi_trial[0] + xi_trial[1]) / 3.
        s_xi = xi_trial - dot(xi_v, self.cronecker_delta)
        J_2 = 0.5 * dot(dot(s_xi, self.P), s_xi)
        f_trial = J_2 - 1. / 3 * (self.sigma_y + q_1)**2
        # print "YF f_trial",f_trial
        return f_trial

    def get_diff1s(self, epsilon_n1, E, nu, sctx):
        diff1s = zeros(3)
        epsilon_p = sctx.mats_state_array[:3]
        q_1 = sctx.mats_state_array[3]
        q_2 = sctx.mats_state_array[4:]
        t1 = 1.0 - nu
        t2 = E * t1
        t4 = 1 / (1.0 + nu)
        t7 = 1 / (1.0 - 2.0 * nu)
        t8 = t4 * t7
        t9 = epsilon_n1[0] - epsilon_p[0]
        t11 = t2 * t8 * t9
        t13 = E * t4
        t14 = t7 * nu
        t15 = epsilon_n1[1] - epsilon_p[1]
        t17 = t13 * t14 * t15
        t21 = t13 * t14 * t9
        t24 = t2 * t8 * t15
        diff1s[0] = 5.0 / 9.0 * t11 + 5.0 / 9.0 * t17 - 5.0 / 9.0 * \
            q_2[0] - 4.0 / 9.0 * t21 - 4.0 / 9.0 * t24 + 4.0 / 9.0 * q_2[1]
        diff1s[1] = -4.0 / 9.0 * t11 - 4.0 / 9.0 * t17 + 4.0 / 9.0 * \
            q_2[0] + 5.0 / 9.0 * t21 + 5.0 / 9.0 * t24 - 5.0 / 9.0 * q_2[1]
        diff1s[2] = t2 * t4 / t1 * \
            (epsilon_n1[2] - epsilon_p[2]) - 2.0 * q_2[2]
        return diff1s

    def get_diff1q(self, epsilon_n1, E, nu, sctx):
        diff1q = zeros(4)
        epsilon_p = sctx.mats_state_array[:3]
        q_1 = sctx.mats_state_array[3]
        q_2 = sctx.mats_state_array[4:]
        t2 = 1.0 - nu
        t3 = E * t2
        t5 = 1 / (1.0 + nu)
        t8 = 1 / (1.0 - 2.0 * nu)
        t9 = t5 * t8
        t10 = epsilon_n1[0] - epsilon_p[0]
        t12 = t3 * t9 * t10
        t14 = E * t5
        t15 = t8 * nu
        t16 = epsilon_n1[1] - epsilon_p[1]
        t18 = t14 * t15 * t16
        t22 = t14 * t15 * t10
        t25 = t3 * t9 * t16
        diff1q[0] = -2.0 / 3.0 * self.sigma_y - 2.0 / 3.0 * q_1
        diff1q[1] = -5.0 / 9.0 * t12 - 5.0 / 9.0 * t18 + 5.0 / 9.0 * \
            q_2[0] + 4.0 / 9.0 * t22 + 4.0 / 9.0 * t25 - 4.0 / 9.0 * q_2[1]
        diff1q[2] = 4.0 / 9.0 * t12 + 4.0 / 9.0 * t18 - 4.0 / 9.0 * \
            q_2[0] - 5.0 / 9.0 * t22 - 5.0 / 9.0 * t25 + 5.0 / 9.0 * q_2[1]
        diff1q[3] = -t3 * t5 / t2 * \
            (epsilon_n1[2] - epsilon_p[2]) + 2.0 * q_2[2]
        return diff1q

    def get_diff2ss(self, epsilon_n1, E, nu, sctx):
        diff2ss = zeros([3, 3])
        diff2ss[0, 0] = 5.0 / 9.0
        diff2ss[0, 1] = -4.0 / 9.0
        diff2ss[1, 0] = -4.0 / 9.0
        diff2ss[1, 1] = 5.0 / 9.0
        diff2ss[2, 2] = 2.0
        return diff2ss

    def get_diff2sq(self, epsilon_n1, E, nu, sctx):
        diff2sq = zeros([3, 4])
        diff2sq[0, 1] = -5.0 / 9.0
        diff2sq[0, 2] = 4.0 / 9.0
        diff2sq[1, 1] = 4.0 / 9.0
        diff2sq[1, 2] = -5.0 / 9.0
        diff2sq[2, 3] = -2.0
        return diff2sq

    def get_diff2qq(self, epsilon_n1, E, nu, sctx):
        diff2qq = zeros([4, 4])
        diff2qq[0, 0] = -2.0 / 3.0
        diff2qq[1, 1] = 5.0 / 9.0
        diff2qq[1, 2] = -4.0 / 9.0
        diff2qq[2, 1] = -4.0 / 9.0
        diff2qq[2, 2] = 5.0 / 9.0
        diff2qq[3, 3] = 2.0
        return diff2qq

    view_traits = View(Item('sigma_y'))
    def _get_edit_view(self):
        g1 = HGroup(Item('name', editor=EnumEditor(name='names')),
                    Item('equilibration_time', label='Eq. Time'))

        v = View(VGroup(g1, show_border=True))
        return v
示例#7
0
class SetEditorDemo(HasTraits):
    """Defines the SetEditor demo class."""

    # Define a trait each for four SetEditor variants:
    unord_nma_set = List(
        editor=SetEditor(
            values=['kumquats', 'pomegranates', 'kiwi'],
            left_column_title='Available Fruit',
            right_column_title='Exotic Fruit Bowl',
            can_move_all=False,
        )
    )

    unord_ma_set = List(
        editor=SetEditor(
            values=['kumquats', 'pomegranates', 'kiwi'],
            left_column_title='Available Fruit',
            right_column_title='Exotic Fruit Bowl',
        )
    )

    ord_nma_set = List(
        editor=SetEditor(
            values=['apples', 'berries', 'cantaloupe'],
            left_column_title='Available Fruit',
            right_column_title='Fruit Bowl',
            ordered=True,
            can_move_all=False,
        )
    )

    ord_ma_set = List(
        editor=SetEditor(
            values=['apples', 'berries', 'cantaloupe'],
            left_column_title='Available Fruit',
            right_column_title='Fruit Bowl',
            ordered=True,
        )
    )

    # SetEditor display, unordered, no move-all buttons:
    no_nma_group = Group(
        Item('unord_nma_set', style='simple'),
        label='Unord I',
        show_labels=False,
    )

    # SetEditor display, unordered, move-all buttons:
    no_ma_group = Group(
        Item('unord_ma_set', style='simple'),
        label='Unord II',
        show_labels=False,
    )

    # SetEditor display, ordered, no move-all buttons:
    o_nma_group = Group(
        Item('ord_nma_set', style='simple'), label='Ord I', show_labels=False
    )

    # SetEditor display, ordered, move-all buttons:
    o_ma_group = Group(
        Item('ord_ma_set', style='simple'), label='Ord II', show_labels=False
    )

    # The view includes one group per data type. These will be displayed
    # on separate tabbed panels:
    traits_view = View(
        no_nma_group,
        no_ma_group,
        o_nma_group,
        o_ma_group,
        title='SetEditor',
        buttons=['OK'],
    )
示例#8
0
class HeadViewController(HasTraits):
    """Set head views for the given coordinate system.

    Parameters
    ----------
    system : 'RAS' | 'ALS' | 'ARI'
        Coordinate system described as initials for directions associated with
        the x, y, and z axes. Relevant terms are: Anterior, Right, Left,
        Superior, Inferior.
    """

    system = Enum("RAS", "ALS", "ARI", desc="Coordinate system: directions of "
                  "the x, y, and z axis.")

    right = Button()
    front = Button()
    left = Button()
    top = Button()
    interaction = Enum('Trackball', 'Terrain')

    scale = Float(0.16)

    scene = Instance(MlabSceneModel)

    view = View(VGrid('0', 'top', '0', Item('scale', label='Scale',
                                            show_label=True),
                      'right', 'front', 'left', 'interaction',
                      show_labels=False, columns=4))

    @on_trait_change('scene.activated')
    def _init_view(self):
        self.scene.parallel_projection = True
        self._trackball_interactor = None

        # apparently scene,activated happens several times
        if self.scene.renderer:
            self.sync_trait('scale', self.scene.camera, 'parallel_scale')
            # and apparently this does not happen by default:
            self.on_trait_change(self.scene.render, 'scale')

    @on_trait_change('interaction')
    def on_set_interaction(self, _, interaction):
        if self.scene is None:
            return
        if interaction == 'Terrain':
            # Ensure we're in the correct orientatino for the
            # InteractorStyleTerrain to have the correct "up"
            if self._trackball_interactor is None:
                self._trackball_interactor = \
                    self.scene.interactor.interactor_style
            self.on_set_view('front', '')
            self.scene.mlab.draw()
            self.scene.interactor.interactor_style = \
                tvtk.InteractorStyleTerrain()
            self.on_set_view('front', '')
            self.scene.mlab.draw()
        else:  # interaction == 'trackball'
            self.scene.interactor.interactor_style = self._trackball_interactor

    @on_trait_change('top,left,right,front')
    def on_set_view(self, view, _):
        if self.scene is None:
            return

        system = self.system
        kwargs = dict(ALS=dict(front=(0, 90, -90),
                               left=(90, 90, 180),
                               right=(-90, 90, 0),
                               top=(0, 0, -90)),
                      RAS=dict(front=(90., 90., 180),
                               left=(180, 90, 90),
                               right=(0., 90, 270),
                               top=(90, 0, 180)),
                      ARI=dict(front=(0, 90, 90),
                               left=(-90, 90, 180),
                               right=(90, 90, 0),
                               top=(0, 180, 90)))
        if system not in kwargs:
            raise ValueError("Invalid system: %r" % system)
        if view not in kwargs[system]:
            raise ValueError("Invalid view: %r" % view)
        kwargs = dict(zip(('azimuth', 'elevation', 'roll'),
                          kwargs[system][view]))
        with SilenceStdout():
            self.scene.mlab.view(distance=None, reset_roll=True,
                                 figure=self.scene.mayavi_scene, **kwargs)
# configure_traits_view_group.py -- Sample code to demonstrate
# configure_traits()

#--[Imports]--------------------------------------------------------------
from __future__ import absolute_import
from traits.api import HasTraits, Str, Int
from traitsui.api import View, Item, Group
import traitsui

#--[Code]-----------------------------------------------------------------


class SimpleEmployee(HasTraits):
    first_name = Str
    last_name = Str
    department = Str

    employee_number = Str
    salary = Int


view1 = View(
    Group(Item(name='first_name'),
          Item(name='last_name'),
          Item(name='department'),
          label='Personnel profile',
          show_border=True))

sam = SimpleEmployee()
sam.configure_traits(view=view1)
示例#10
0
class MATS3DMicroplaneDamageJir(MATSXDMicroplaneDamageFatigueJir):

    # 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
    #-------------------------------------------------------------------------

    elasticity_tensors = Property(
        depends_on='E, nu, dimensionality, 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
        # ----------------------------------------------------------------------------

        # 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'])
示例#11
0
class PointObject(Object):
    """Represent a group of individual points in a mayavi scene."""

    label = Bool(False, enabled_when='visible')
    text3d = List

    glyph = Instance(Glyph)
    resolution = Int(8)

    view = View(HGroup(Item('visible', show_label=False),
                       Item('color', show_label=False),
                       Item('opacity')))

    def __init__(self, view='points', *args, **kwargs):
        """Init.

        Parameters
        ----------
        view : 'points' | 'cloud'
            Whether the view options should be tailored to individual points
            or a point cloud.
        """
        self._view = view
        super(PointObject, self).__init__(*args, **kwargs)

    def default_traits_view(self):  # noqa: D102
        color = Item('color', show_label=False)
        scale = Item('point_scale', label='Size')
        if self._view == 'points':
            visible = Item('visible', label='Show', show_label=True)
            view = View(HGroup(visible, color, scale, 'label'))
        elif self._view == 'cloud':
            visible = Item('visible', show_label=False)
            view = View(HGroup(visible, color, scale))
        else:
            raise ValueError("PointObject(view = %r)" % self._view)
        return view

    @on_trait_change('label')
    def _show_labels(self, show):
        _toggle_mlab_render(self, False)
        while self.text3d:
            text = self.text3d.pop()
            text.remove()

        if show:
            fig = self.scene.mayavi_scene
            for i, pt in enumerate(np.array(self.src.data.points)):
                x, y, z = pt
                t = text3d(x, y, z, ' %i' % i, scale=.01, color=self.color,
                           figure=fig)
                self.text3d.append(t)
        _toggle_mlab_render(self, True)

    @on_trait_change('visible')
    def _on_hide(self):
        if not self.visible:
            self.label = False

    @on_trait_change('scene.activated')
    def _plot_points(self):
        """Add the points to the mayavi pipeline"""
        if self.scene is None:
            return
        if hasattr(self.glyph, 'remove'):
            self.glyph.remove()
        if hasattr(self.src, 'remove'):
            self.src.remove()

        _toggle_mlab_render(self, False)
        x, y, z = self.points.T
        fig = self.scene.mayavi_scene
        scatter = pipeline.scalar_scatter(x, y, z, fig=fig)
        if not scatter.running:
            # this can occur sometimes during testing w/ui.dispose()
            return
        # fig.scene.engine.current_object is scatter
        glyph = pipeline.glyph(scatter, color=self.color,
                               figure=fig,
                               scale_factor=self.point_scale, opacity=1.,
                               resolution=self.resolution)
        glyph.actor.property.backface_culling = True
        self.src = scatter
        self.glyph = glyph

        self.sync_trait('point_scale', self.glyph.glyph.glyph, 'scale_factor')
        self.sync_trait('color', self.glyph.actor.property, mutual=False)
        self.sync_trait('visible', self.glyph)
        self.sync_trait('opacity', self.glyph.actor.property)
        self.on_trait_change(self._update_points, 'points')
        _toggle_mlab_render(self, True)

#         self.scene.camera.parallel_scale = _scale

    def _resolution_changed(self, new):
        if not self.glyph:
            return

        self.glyph.glyph.glyph_source.glyph_source.phi_resolution = new
        self.glyph.glyph.glyph_source.glyph_source.theta_resolution = new
class SourceWidget(Component):

    # The version of this class.  Used for persistence.
    __version__ = 0

    # The actual poly data source widget.
    widget = Instance(tvtk.ThreeDWidget, record=True)

    # Specifies the updation mode of the poly_data attribute.  There
    # are three modes: 1) 'interactive' -- the poly_data attribute is
    # updated as the widget is interacted with, 2) 'semi-interactive'
    # -- poly_data attribute is updated when the traits of the widget
    # change and when the widget interaction is complete, 3)
    # 'non-interactive' -- poly_data is updated only explicitly at
    # users request by calling `object.update_poly_data`.
    update_mode = Trait(
        'interactive',
        TraitPrefixList(['interactive', 'semi-interactive',
                         'non-interactive']),
        desc='the speed at which the poly data is updated')

    # A list of predefined glyph sources that can be used.
    widget_list = List(tvtk.Object, record=False)

    # The poly data that the widget manages.
    poly_data = Instance(tvtk.PolyData, args=())

    ########################################
    # Private traits.

    _first = Bool(True)
    _busy = Bool(False)
    _unpickling = Bool(False)
    _bounds = List

    ########################################
    # View related traits.

    view = View(
        Group(
            Item(name='widget',
                 style='custom',
                 resizable=True,
                 editor=InstanceEditor(name='widget_list')),
            label='Source Widget',
            show_labels=False,
        ),
        resizable=True,
    )

    ######################################################################
    # `Base` interface
    ######################################################################
    def __get_pure_state__(self):
        d = super(SourceWidget, self).__get_pure_state__()
        for attr in ('poly_data', '_unpickling', '_first', '_busy'):
            d.pop(attr, None)
        return d

    def __set_pure_state__(self, state):
        self._unpickling = True
        # First create all the allowed widgets in the widget_list attr.
        handle_children_state(self.widget_list, state.widget_list)
        # Now set their state.
        set_state(self, state, first=['widget_list'], ignore=['*'])
        # Set the widget attr depending on value saved.
        m = [x.__class__.__name__ for x in self.widget_list]
        w_c_name = state.widget.__metadata__['class_name']
        w = self.widget = self.widget_list[m.index(w_c_name)]
        # Set the input.
        if len(self.inputs) > 0:
            self.configure_input(w, self.inputs[0].outputs[0])
        # Fix for the point widget.
        if w_c_name == 'PointWidget':
            w.place_widget()
        # Set state of rest of the attributes ignoring the widget_list.
        set_state(self, state, ignore=['widget_list'])
        # Some widgets need some cajoling to get their setup right.
        w.update_traits()
        if w_c_name == 'PlaneWidget':
            w.origin = state.widget.origin
            w.normal = state.widget.normal
            w.center = state.widget.center
            w.update_placement()
            w.get_poly_data(self.poly_data)
        elif w_c_name == 'SphereWidget':
            # XXX: This hack is necessary because the sphere widget
            # does not update its poly data even when its ivars are
            # set (plus it does not have an update_placement method
            # which is a bug).  So we force this by creating a similar
            # sphere source and copy its output.
            s = tvtk.SphereSource(center=w.center,
                                  radius=w.radius,
                                  theta_resolution=w.theta_resolution,
                                  phi_resolution=w.phi_resolution,
                                  lat_long_tessellation=True)
            s.update()
            self.poly_data.shallow_copy(s.output)
        else:
            w.get_poly_data(self.poly_data)
        self._unpickling = False
        # Set the widgets trait so that the widget is rendered if needed.
        self.widgets = [w]

    ######################################################################
    # `Component` interface
    ######################################################################
    def setup_pipeline(self):
        """Override this method so that it *creates* the tvtk
        pipeline.

        This method is invoked when the object is initialized via
        `__init__`.  Note that at the time this method is called, the
        tvtk data pipeline will *not* yet be setup.  So upstream data
        will not be available.  The idea is that you simply create the
        basic objects and setup those parts of the pipeline not
        dependent on upstream sources and filters.  You should also
        set the `actors` attribute up at this point.
        """
        # Setup the glyphs.
        sources = [
            tvtk.SphereWidget(theta_resolution=8, phi_resolution=6),
            tvtk.LineWidget(clamp_to_bounds=False),
            tvtk.PlaneWidget(),
            tvtk.PointWidget(outline=False,
                             x_shadows=False,
                             y_shadows=False,
                             z_shadows=False),
        ]
        self.widget_list = sources
        # The 'widgets' trait is set in the '_widget_changed' handler.
        self.widget = sources[0]

        for s in sources:
            self._connect(s)

    def update_pipeline(self):
        """Override this method so that it *updates* the tvtk pipeline
        when data upstream is known to have changed.

        This method is invoked (automatically) when any of the inputs
        sends a `pipeline_changed` event.
        """
        if len(self.inputs) == 0:
            return
        inp = self.inputs[0].outputs[0]
        w = self.widget
        self.configure_input(w, inp)
        dsh = DataSetHelper(self.inputs[0].outputs[0])
        b = dsh.get_bounds()
        self._bounds = list(b)
        if self._first:
            w.place_widget(b)
            self._first = False

        # If the dataset is effectively 2D switch to using the line
        # widget since that works best.
        l = [(b[1] - b[0]), (b[3] - b[2]), (b[5] - b[4])]
        max_l = max(l)
        for i, x in enumerate(l):
            if x / max_l < 1.0e-6:
                w = self.widget = self.widget_list[1]
                w.clamp_to_bounds = True
                w.align = ['z_axis', 'z_axis', 'y_axis'][i]
                break

        # Set our output.
        w.get_poly_data(self.poly_data)
        self.outputs = [self.poly_data]

        self.pipeline_changed = True

    def update_data(self):
        """Override this method so that it flushes the vtk pipeline if
        that is necessary.

        This method is invoked (automatically) when any of the inputs
        sends a `data_changed` event.
        """
        self.data_changed = True

    ######################################################################
    # `SourceWidget` interface
    ######################################################################
    def update_poly_data(self):
        self.widget.get_poly_data(self.poly_data)

    ######################################################################
    # Non-public traits.
    ######################################################################
    def _widget_changed(self, value):
        # If we are being unpickled do nothing.
        if self._unpickling:
            return
        if value not in self.widget_list:
            classes = [o.__class__ for o in self.widget_list]
            vc = value.__class__
            self._connect(value)
            if vc in classes:
                self.widget_list[classes.index(vc)] = value
            else:
                self.widget_list.append(value)

        recorder = self.recorder
        if recorder is not None:
            idx = self.widget_list.index(value)
            name = recorder.get_script_id(self)
            lhs = '%s.widget' % name
            rhs = '%s.widget_list[%d]' % (name, idx)
            recorder.record('%s = %s' % (lhs, rhs))

        if len(self.inputs) > 0:
            self.configure_input(value, self.inputs[0].outputs[0])
            value.place_widget(self._bounds)

        value.on_trait_change(self.render)
        self.widgets = [value]

    def _update_mode_changed(self, value):
        if value in ['interactive', 'semi-interactive']:
            self.update_poly_data()
            self.render()

    def _on_interaction_event(self, obj, event):
        if (not self._busy) and (self.update_mode == 'interactive'):
            self._busy = True
            self.update_poly_data()
            self._busy = False

    def _on_widget_trait_changed(self):
        if (not self._busy) and (self.update_mode != 'non-interactive'):
            self._busy = True
            # This render call forces any changes to the trait to be
            # rendered only then will updating the poly data make
            # sense.
            self.render()
            self.update_poly_data()
            self._busy = False

    def _on_alignment_set(self):
        w = self.widget
        w.place_widget(self._bounds)
        w.update_traits()

    def _connect(self, obj):
        """Wires up all the event handlers."""
        obj.add_observer('InteractionEvent', self._on_interaction_event)
        if isinstance(obj, tvtk.PlaneWidget):
            obj.on_trait_change(self._on_alignment_set, 'normal_to_x_axis')
            obj.on_trait_change(self._on_alignment_set, 'normal_to_y_axis')
            obj.on_trait_change(self._on_alignment_set, 'normal_to_z_axis')
        elif isinstance(obj, tvtk.LineWidget):
            obj.on_trait_change(self._on_alignment_set, 'align')

        # Setup the widgets colors.
        fg = (1, 1, 1)
        if self.scene is not None:
            fg = self.scene.foreground
        self._setup_widget_colors(obj, fg)

        obj.on_trait_change(self._on_widget_trait_changed)
        obj.on_trait_change(self.render)

    def _setup_widget_colors(self, widget, color):
        trait_names = widget.trait_names()
        props = [
            x for x in trait_names if 'property' in x and 'selected' not in x
        ]
        sel_props = [
            x for x in trait_names if 'property' in x and 'selected' in x
        ]
        for p in props:
            setattr(getattr(widget, p), 'color', color)
            setattr(getattr(widget, p), 'line_width', 2)
        for p in sel_props:
            # Set the selected color to 'red'.
            setattr(getattr(widget, p), 'color', (1, 0, 0))
            setattr(getattr(widget, p), 'line_width', 2)
        self.render()

    def _foreground_changed_for_scene(self, old, new):
        # Change the default color for the actor.
        for w in self.widget_list:
            self._setup_widget_colors(w, new)
        self.render()

    def _scene_changed(self, old, new):
        super(SourceWidget, self)._scene_changed(old, new)
        self._foreground_changed_for_scene(None, new.foreground)
示例#13
0
class DOTSListEval(TStepperEval):
    '''Domain with uniform FE-time-step-eval.
    '''
    implements(ITStepperEval)

    sdomain = WeakRef('ibvpy.mesh.fe_domain.FEDomain')

    dots_list = List

    def new_cntl_var(self):
        return zeros(self.sdomain.n_dofs, float_)

    def new_resp_var(self):
        return zeros(self.sdomain.n_dofs, float_)

    K = Property

    @cached_property
    def _get_K(self):
        return SysMtxAssembly()

    F_int = Property(depends_on='sdomain.changed_structure')

    @cached_property
    def _get_F_int(self):
        n_dofs = self.sdomain.n_dofs
        return zeros(n_dofs, 'float_')

    def setup(self, sctx):
        print 'DEPRECATED CALL TO SETUP'

    def get_state_array_size(self):
        return 0

    def apply_constraints(self, K):
        for dots_eval in self.dots_list:
            dots_eval.apply_constraints(K)

    def get_corr_pred(self, sctx, U, d_U, tn, tn1, *args, **kw):

        K = self.K
        K.reset()

        F_int = self.F_int
        F_int[:] = 0.0

        U = self.tstepper.U_k
        d_U = self.tstepper.d_U

        for dots_eval in self.dots_list:

            K_mtx_arr = dots_eval.get_corr_pred(sctx, U, d_U, tn, tn1,
                                                self.F_int, *args, **kw)

            K.sys_mtx_arrays.append(K_mtx_arr)

        return self.F_int, self.K

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

    @cached_property
    def _get_rte_dict(self):
        rte_dict = {}

        dots_rte_dicts = []
        rte_keys = []
        for dots_eval in self.dots_list:
            dots_rte_dict = {}
            for key, eval in dots_eval.rte_dict.items():
                # add the mapping here
                #
                if key not in rte_keys:
                    rte_keys.append(key)
                dots_rte_dict[key] = eval
            dots_rte_dicts.append(dots_rte_dict)

        # Get the union of all available rte keys
        for key in rte_keys:
            rte_list = []
            for rte_dict in dots_rte_dicts:
                rte_list.append(rte_dict.get(key, None))
            rte_dict[key] = tuple(rte_list)

        return rte_dict

    traits_view = View()
示例#14
0
 def translation_traits_view(self):
     return View(HGroup(Item('from_channel', style = 'readonly', show_label = False),
                        Item('', label = '->'),
                        Item('to_channel', style = 'readonly', show_label = False),
                        Item('file', show_label = False)),
                 handler = self)
class ModelView(HasTraits):

    model = Instance(Model)
    view = Instance(PlotUI)
    timer = Instance(Timer)
    timer_controller = Instance(TimerController, ())

    edit_model = Button
    edit_view = Button
    animated = Bool(False)

    # Whether to animate colors on a bounce of each side:
    animate_left = Bool(False)
    animate_right = Bool(False)
    animate_top = Bool(False)
    animate_bottom = Bool(False)

    traits_view = View(UItem('@view'),
                       HGroup(
                           UItem('edit_model', enabled_when='not animated'),
                           UItem('edit_view'), Item('animated'),
                           Item('animate_left',
                                enabled_when='animated',
                                label='Change colors at:  Left'),
                           Item('animate_right',
                                enabled_when='animated',
                                label='Right'),
                           Item('animate_top',
                                enabled_when='animated',
                                label='Top'),
                           Item('animate_bottom',
                                enabled_when='animated',
                                label='Bottom'), spring),
                       title="Function Inspector",
                       resizable=True)

    @on_trait_change('model, view')
    def update_view(self):
        if self.model is not None and self.view is not None:
            self.view.update(self.model)

    def _edit_model_fired(self):
        self.model.configure_traits()

    def _edit_view_fired(self):
        self.view.configure_traits(view="plot_edit_view")

    def _model_changed(self):
        if self.view is not None:
            self.view.update(self.model)

    def _start_timer(self):
        # Start up the timer! We should do this only when the demo actually
        # starts and not when the demo object is created.
        # FIXME: close timer on exit.
        self.timer_controller.view = self.view
        self.timer_controller.model_view = self
        self.timer = Timer(40, self.timer_controller.onTimer)

    def edit_traits(self, *args, **kws):
        self._start_timer()
        return super(ModelView, self).edit_traits(*args, **kws)

    def configure_traits(self, *args, **kws):
        self._start_timer()
        return super(ModelView, self).configure_traits(*args, **kws)
class Viz2DPullOutFW(Viz2D):
    '''Plot adaptor for the pull-out simulator.
    '''
    label = 'F-W'

    show_legend = Bool(True, auto_set=False, enter_set=True)

    def plot(self, ax, vot, *args, **kw):
        sim = self.vis2d.sim
        P_t, w_0_t, w_L_t = sim.hist['Pw'].Pw
        ymin, ymax = np.min(P_t), np.max(P_t)
        L_y = ymax - ymin
        ymax += 0.05 * L_y
        ymin -= 0.05 * L_y
        xmin, xmax = np.min(w_L_t), np.max(w_L_t)
        L_x = xmax - xmin
        xmax += 0.03 * L_x
        xmin -= 0.03 * L_x
        ax.plot(w_L_t,
                P_t,
                linewidth=2,
                color='black',
                alpha=0.4,
                label='P(w;x=L)')
        ax.plot(w_0_t,
                P_t,
                linewidth=1,
                color='magenta',
                alpha=0.4,
                label='P(w;x=0)')
        ax.set_ylim(ymin=ymin, ymax=ymax)
        ax.set_xlim(xmin=xmin, xmax=xmax)
        ax.set_ylabel('pull-out force P [N]')
        ax.set_xlabel('pull-out slip w [mm]')
        if self.show_legend:
            ax.legend(loc=4)
        self.plot_marker(ax, vot)

    def plot_marker(self, ax, vot):
        sim = self.vis2d.sim
        P_t, w_0_t, w_L_t = sim.hist['Pw'].Pw
        idx = sim.hist.get_time_idx(vot)
        P, w = P_t[idx], w_L_t[idx]
        ax.plot([w], [P], 'o', color='black', markersize=10)
        P, w = P_t[idx], w_0_t[idx]
        ax.plot([w], [P], 'o', color='magenta', markersize=10)

    show_data = Button()

    def _show_data_fired(self):
        P_t = self.vis2d.get_P_t()
        w_0, w_L = self.vis2d.get_w_t()
        data = np.vstack([w_0, w_L, P_t]).T
        show_data = DataSheet(data=data)
        show_data.edit_traits()

    def plot_tex(self, ax, vot, *args, **kw):
        self.plot(ax, vot, *args, **kw)

    traits_view = View(Item('name', style='readonly'), Item('show_legend'),
                       Item('show_data'))
示例#17
0
    selected_cell = Tuple(Instance(ListItem), Str)
    selected_cells = List(Tuple(Instance(ListItem), Str))
    selected_cell_index = Tuple(Int, Int)
    selected_cell_indices = List(Tuple(Int, Int))


class ObjectList(HasTraits):
    values = List(Instance(ListItem))


simple_view = View(
    Item(
        "values",
        show_label=False,
        editor=TableEditor(columns=[
            ObjectColumn(name="value"),
            ObjectColumn(name="other_value"),
        ]),
    ),
    buttons=["OK"],
)

filtered_view = View(
    Item(
        "values",
        show_label=False,
        editor=TableEditor(
            columns=[
                ObjectColumn(name="value"),
                ObjectColumn(name="other_value"),
            ],
class PullOut2LayerSim(Simulator):

    node_name = 'pull out 2 layer simulation'

    tree_node_list = List([])

    def _tree_node_list_default(self):

        return [
            self.tline, self.loading_scenario, self.mats_eval1,
            self.cross_section1, self.mats_eval2, self.cross_section2,
            self.geometry
        ]

    def _update_node_list(self):
        self.tree_node_list = [
            self.tline,
            self.loading_scenario,
            self.mats_eval1,
            self.cross_section1,
            self.mats_eval2,
            self.cross_section2,
            self.geometry,
        ]

    tree_view = View(
        Group(Item('mats_eval_type1', resizable=True, full_size=True),
              Item('mats_eval_type2', resizable=True, full_size=True),
              Item('control_variable', resizable=True, full_size=True),
              Item('w_max', resizable=True, full_size=True),
              Item('n_e_x', resizable=True, full_size=True),
              Item('fixed_boundary'),
              Group(Item('loading_scenario@', show_label=False), )))

    #=========================================================================
    # Test setup parameters
    #=========================================================================
    loading_scenario = Instance(LoadingScenario,
                                report=True,
                                desc='object defining the loading scenario')

    def _loading_scenario_default(self):
        return LoadingScenario()

    cross_section1 = Instance(CrossSection,
                              report=True,
                              desc='1 cross section parameters')

    def _cross_section1_default(self):
        return CrossSection()

    cross_section2 = Instance(CrossSection,
                              report=True,
                              desc='2 cross section parameters')

    def _cross_section2_default(self):
        return CrossSection()

    geometry = Instance(
        Geometry,
        report=True,
        desc='geometry parameters of the boundary value problem')

    def _geometry_default(self):
        return Geometry()

    control_variable = Enum('u', 'f', auto_set=False, enter_set=True, BC=True)

    #=========================================================================
    # Discretization
    #=========================================================================
    n_e_x = Int(20,
                MESH=True,
                auto_set=False,
                enter_set=True,
                symbol='n_\mathrm{E}',
                unit='-',
                desc='number of finite elements along the embedded length')

    #=========================================================================
    # Algorithimc parameters
    #=========================================================================
    k_max = Int(400,
                unit='\mathrm{mm}',
                symbol='k_{\max}',
                desc='maximum number of iterations',
                ALG=True)

    tolerance = Float(1e-4,
                      unit='-',
                      symbol='\epsilon',
                      desc='required accuracy',
                      ALG=True)

    mats_eval_type1 = Trait('multilinear', {
        'multilinear': MATSBondSlipMultiLinear,
        'damage': MATSBondSlipD,
        'elasto-plasticity': MATSBondSlipEP,
        'damage-plasticity': MATSBondSlipDP,
        'cumulative fatigue': MATSBondSlipFatigue
    },
                            MAT=True,
                            desc='material model type')

    @on_trait_change('mats_eval_type1')
    def _set_mats_eval1(self):
        self.mats_eval = self.mats_eval_type1_()
        self._update_node_list()

    mats_eval1 = Instance(IMATSEval, report=True)
    '''Material model 1'''

    def _mats_eval1_default(self):
        return self.mats_eval_type_()

    mats_eval_type2 = Trait('multilinear', {
        'multilinear': MATSBondSlipMultiLinear,
        'damage': MATSBondSlipD,
        'elasto-plasticity': MATSBondSlipEP,
        'damage-plasticity': MATSBondSlipDP,
        'cumulative fatigue': MATSBondSlipFatigue
    },
                            MAT=True,
                            desc='material model type')

    @on_trait_change('mats_eval_type2')
    def _set_mats_eval2(self):
        self.mats_eval = self.mats_eval_type1_()
        self._update_node_list()

    mats_eval2 = Instance(IMATSEval, report=True)
    '''Material model 2'''

    def _mats_eval2_default(self):
        return self.mats_eval_type2_()

    #=========================================================================
    # Finite element type
    #=========================================================================
    fets_eval = Property(Instance(FETS1D52ULRH), depends_on='CS,MAT')
    '''Finite element time stepper implementing the corrector
    predictor operators at the element level'''

    @cached_property
    def _get_fets_eval(self):
        return FETS1D52ULRH(A_m=self.cross_section.A_m,
                            P_b=self.cross_section.P_b,
                            A_f=self.cross_section.A_f)

    dots_grid1 = Property(Instance(XDomainFEInterface1D), depends_on=itags_str)
    '''Discretization object.
    '''

    @cached_property
    def _get_dots_grid1(self):
        geo = self.geometry
        return XDomainFEInterface1D(dim_u=2,
                                    coord_max=[geo.L_x],
                                    shape=[self.n_e_x],
                                    fets=self.fets_eval)

    fe_grid1 = Property

    def _get_fe_grid1(self):
        return self.dots_grid.mesh

    dots_grid2 = Property(Instance(XDomainFEInterface1D), depends_on=itags_str)
    '''Discretization object.
    '''

    @cached_property
    def _get_dots_grid2(self):
        geo = self.geometry
        return XDomainFEInterface1D(dim_u=2,
                                    coord_max=[geo.L_x],
                                    shape=[self.n_e_x],
                                    fets=self.fets_eval)

    fe_grid2 = Property

    def _get_fe_grid2(self):
        return self.dots_grid.mesh

    domains = Property(depends_on=itags_str)

    @cached_property
    def _get_domains(self):
        return [
            (self.dots_grid1, self.mats_eval1),
            (self.dots_grid2, self.mats_eval2),
        ]

    #=========================================================================
    # Boundary conditions
    #=========================================================================
    w_max = Float(1,
                  BC=True,
                  symbol='w_{\max}',
                  unit='mm',
                  desc='maximum pullout slip',
                  auto_set=False,
                  enter_set=True)

    u_f0_max = Property(depends_on='BC')

    @cached_property
    def _get_u_f0_max(self):
        return self.w_max

    def _set_u_f0_max(self, value):
        self.w_max = value

    fixed_boundary = Enum(
        'non-loaded end (matrix)',
        'loaded end (matrix)',
        'non-loaded end (reinf)',
        'clamped left',
        BC=True,
        desc=
        'which side of the specimen is fixed [non-loaded end [matrix], loaded end [matrix], non-loaded end [reinf]]'
    )

    fixed_dofs = Property(depends_on=itags_str)

    @cached_property
    def _get_fixed_dofs(self):
        if self.fixed_boundary == 'non-loaded end (matrix)':
            return [0]
        elif self.fixed_boundary == 'non-loaded end (reinf)':
            return [1]
        elif self.fixed_boundary == 'loaded end (matrix)':
            return [self.controlled_dof - 1]
        elif self.fixed_boundary == 'clamped left':
            return [0, 1]

    controlled_dof = Property(depends_on=itags_str)

    @cached_property
    def _get_controlled_dof(self):
        return 2 + 2 * self.n_e_x - 1

    free_end_dof = Property(depends_on=itags_str)

    @cached_property
    def _get_free_end_dof(self):
        return 1

    fixed_bc_list = Property(depends_on=itags_str)
    '''Foxed boundary condition'''

    @cached_property
    def _get_fixed_bc_list(self):
        return [
            BCDof(node_name='fixed left end', var='u', dof=dof, value=0.0)
            for dof in self.fixed_dofs
        ]

    control_bc = Property(depends_on=itags_str)
    '''Control boundary condition - make it accessible directly
    for the visualization adapter as property
    '''

    @cached_property
    def _get_control_bc(self):
        return BCDof(node_name='pull-out displacement',
                     var=self.control_variable,
                     dof=self.controlled_dof,
                     value=self.w_max,
                     time_function=self.loading_scenario)

    bc_link_dofs = Property(depends_on=itags_str)

    def _get_bc_link_dofs(self):
        return BCSlice(name='link_m',
                       slice=self.fe_grid1[:, :],
                       link_slice=self.fe_grid2[:, :],
                       dims=[1],
                       link_coeffs=[-1],
                       value=0)

    bc = Property(depends_on=itags_str)

    @cached_property
    def _get_bc(self):
        return [self.control_bc, self.link_coeffs] + self.fixed_bc_list

    X_M = Property()

    def _get_X_M(self):
        state = self.tstep.fe_domain[0]
        return state.xdomain.x_Ema[..., 0].flatten()

    #=========================================================================
    # Getter functions @todo move to the PulloutStateRecord
    #=========================================================================

    def get_u_p(self, vot):
        '''Displacement field
        '''
        idx = self.hist.get_time_idx(vot)
        U = self.hist.U_t[idx]
        state = self.tstep.fe_domain[0]
        dof_Epia = state.xdomain.o_Epia
        fets = state.xdomain.fets
        u_Epia = U[dof_Epia]
        N_mi = fets.N_mi
        u_Emap = np.einsum('mi,Epia->Emap', N_mi, u_Epia)
        return u_Emap.reshape(-1, 2)

    def get_eps_Ems(self, vot):
        '''Epsilon in the components'''
        state = self.tstep.fe_domain[0]
        idx = self.hist.get_time_idx(vot)
        U = self.hist.U_t[idx]
        return state.xdomain.map_U_to_field(U)

    def get_eps_p(self, vot):
        '''Epsilon in the components'''
        eps_Ems = self.get_eps_Ems(vot)
        return eps_Ems[..., (0, 2)].reshape(-1, 2)

    def get_s(self, vot):
        '''Slip between the two material phases'''
        eps_Ems = self.get_eps_Ems(vot)
        return eps_Ems[..., 1].flatten()

    def get_sig_Ems(self, vot):
        '''Get streses in the components 
        '''
        txdomain = self.tstep.fe_domain[0]
        idx = self.hist.get_time_idx(vot)
        U = self.hist.U_t[idx]
        t_n1 = self.hist.t[idx]
        eps_Ems = txdomain.xdomain.map_U_to_field(U)
        state_vars_t = self.tstep.hist.state_vars[idx]
        state_k = copy.deepcopy(state_vars_t)
        sig_Ems, _ = txdomain.tmodel.get_corr_pred(eps_Ems, t_n1, **state_k[0])
        return sig_Ems

    def get_sig_p(self, vot):
        '''Epsilon in the components'''
        sig_Ems = self.get_sig_Ems(vot)
        return sig_Ems[..., (0, 2)].reshape(-1, 2)

    def get_sf(self, vot):
        '''Get the shear flow in the interface
        '''
        sig_Ems = self.get_sig_Ems(vot)
        return sig_Ems[..., 1].flatten()

    def get_shear_integ(self):
        #         d_ECid = self.get_d_ECid(vot)
        #         s_Emd = np.einsum('Cim,ECid->Emd', self.tstepper.sN_Cim, d_ECid)
        #         idx = self.tloop.get_time_idx(vot)
        #         sf = self.tloop.sf_Em_record[idx]

        sf_t_Em = np.array(self.tloop.sf_Em_record)
        w_ip = self.fets_eval.ip_weights
        J_det = self.tstepper.J_det
        P_b = self.cross_section.P_b
        shear_integ = np.einsum('tEm,m,em->t', sf_t_Em, w_ip, J_det) * P_b
        return shear_integ

    def get_Pw_t(self):
        sim = self
        c_dof = sim.controlled_dof
        f_dof = sim.free_end_dof
        U_ti = sim.hist.U_t
        F_ti = sim.hist.F_t
        P = F_ti[:, c_dof]
        w_L = U_ti[:, c_dof]
        w_0 = U_ti[:, f_dof]
        return P, w_0, w_L

    #=========================================================================
    # Plot functions
    #=========================================================================
    def plot_u_p(self, ax, vot, label_m='matrix', label_f='reinf'):
        X_M = self.X_M
        L = self.geometry.L_x
        u_p = self.get_u_p(vot).T
        ax.plot(X_M, u_p[0], linewidth=2, color='blue', label=label_m)
        ax.fill_between(X_M, 0, u_p[0], facecolor='blue', alpha=0.2)
        ax.plot(X_M, u_p[1], linewidth=2, color='orange', label=label_f)
        ax.fill_between(X_M, 0, u_p[1], facecolor='orange', alpha=0.2)
        ax.plot([0, L], [0, 0], color='black')
        ax.set_ylabel('displacement')
        ax.set_xlabel('bond length')
        ax.legend(loc=2)
        return np.min(u_p), np.max(u_p)

    def plot_eps_p(self, ax, vot, label_m='matrix', label_f='reinf'):
        X_M = self.X_M
        L = self.geometry.L_x
        eps_p = self.get_eps_p(vot).T
        ax.plot(X_M, eps_p[0], linewidth=2, color='blue', label=label_m)
        ax.fill_between(X_M, 0, eps_p[0], facecolor='blue', alpha=0.2)
        ax.plot(X_M, eps_p[1], linewidth=2, color='orange', label=label_f)
        ax.fill_between(X_M, 0, eps_p[1], facecolor='orange', alpha=0.2)
        ax.plot([0, L], [0, 0], color='black')
        ax.set_ylabel('strain')
        ax.set_xlabel('bond length')
        return np.min(eps_p), np.max(eps_p)

    def plot_sig_p(self, ax, vot):
        X_M = self.X_M
        sig_p = self.get_sig_p(vot).T

        #        A_m = self.cross_section.A_m
        #        A_f = self.cross_section.A_f
        L = self.geometry.L_x
        F_m = sig_p[0]
        F_f = sig_p[1]
        ax.plot(
            X_M,
            F_m,
            linewidth=2,
            color='blue',
        )
        ax.fill_between(X_M, 0, F_m, facecolor='blue', alpha=0.2)
        ax.plot(X_M, F_f, linewidth=2, color='orange')
        ax.fill_between(X_M, 0, F_f, facecolor='orange', alpha=0.2)
        ax.plot([0, L], [0, 0], color='black')
        ax.set_ylabel('stress [MPa]')
        ax.set_xlabel('bond length')
        F_min = min(np.min(F_m), np.min(F_f))
        F_max = max(np.max(F_m), np.max(F_f))
        return F_min, F_max

    def plot_s(self, ax, vot):
        X_J = self.X_M
        s = self.get_s(vot)
        ax.fill_between(X_J, 0, s, facecolor='lightcoral', alpha=0.3)
        ax.plot(X_J, s, linewidth=2, color='lightcoral')
        ax.set_ylabel('slip')
        ax.set_xlabel('bond length')
        return np.min(s), np.max(s)

    def plot_sf(self, ax, vot):
        X_J = self.X_M
        sf = self.get_sf(vot)
        ax.fill_between(X_J, 0, sf, facecolor='lightcoral', alpha=0.3)
        ax.plot(X_J, sf, linewidth=2, color='lightcoral')
        ax.set_ylabel('shear flow')
        ax.set_xlabel('bond length')
        return np.min(sf), np.max(sf)

    def plot_omega(self, ax, vot):
        X_J = self.X_J
        omega = self.get_omega(vot)
        ax.fill_between(X_J, 0, omega, facecolor='lightcoral', alpha=0.3)
        ax.plot(X_J, omega, linewidth=2, color='lightcoral', label='bond')
        ax.set_ylabel('damage')
        ax.set_xlabel('bond length')
        ax.legend(loc=2)
        return 0.0, 1.05

    def plot_eps_s(self, ax, vot):
        eps_p = self.get_eps_p(vot).T
        s = self.get_s(vot)
        ax.plot(eps_p[1], s, linewidth=2, color='lightcoral')
        ax.set_ylabel('reinforcement strain')
        ax.set_xlabel('slip')

    def get_window(self):
        self.record['Pw'] = PulloutRecord()
        fw = Viz2DPullOutFW(name='pullout-curve', vis2d=self.hist['Pw'])
        u_p = Viz2DPullOutField(name='displacement along the bond',
                                plot_fn='u_p',
                                vis2d=self)
        eps_p = Viz2DPullOutField(name='strain along the bond',
                                  plot_fn='eps_p',
                                  vis2d=self)
        sig_p = Viz2DPullOutField(name='stress along the bond',
                                  plot_fn='sig_p',
                                  vis2d=self)
        s = Viz2DPullOutField(name='slip along the bond',
                              plot_fn='s',
                              vis2d=self)
        sf = Viz2DPullOutField(name='shear flow along the bond',
                               plot_fn='sf',
                               vis2d=self)
        energy = Viz2DEnergyPlot(name='energy', vis2d=self.hist['Pw'])
        dissipation = Viz2DEnergyReleasePlot(name='energy release',
                                             vis2d=self.hist['Pw'])
        w = BMCSWindow(sim=self)
        w.viz_sheet.viz2d_list.append(fw)
        w.viz_sheet.viz2d_list.append(u_p)
        w.viz_sheet.viz2d_list.append(eps_p)
        w.viz_sheet.viz2d_list.append(sig_p)
        w.viz_sheet.viz2d_list.append(s)
        w.viz_sheet.viz2d_list.append(sf)
        w.viz_sheet.viz2d_list.append(energy)
        w.viz_sheet.viz2d_list.append(dissipation)
        w.viz_sheet.monitor_chunk_size = 10
        return w
示例#19
0
class CombinationTable(HasTraits):
    row_set = List(Tuple())
    col_set = List(Tuple())
    rows = List(Row)
    cols = List()
    selected_row = Any()
    combination_updated = Event()


    def __init__(self, *args, **kwargs):
        super(CombinationTable, self).__init__(*args, **kwargs)
        self._generate_combinations()


    # FIXME: Implement automatic update of table based on
    # change to row and col set. But I need to implemnt this
    # and to preserv the selection already made.
    #@on_trait_change('row_set, col_set', post_init=True)
    #def _update_table(self, obj, name, new):
    #    print("Name list changed")
    #    self._generate_combinations()
    #    self.update_names()


    def get_selected_combinations(self):
        combinations = []
        for row in self.rows:
            for i, cn in enumerate(self.col_set):
                an = 'ck{0}'.format(i)
                if getattr(row, an):
                    cmb = (row.nid, cn[0])
                    combinations.append(cmb)
        return combinations


    def update_names(self):
        for i in self.row_set:
            for row in self.rows:
                if row.nid == i[0]:
                    row.name = i[1]
        for i,col in enumerate(self.col_set):
            self.cols[i+1].label = col[1]


    @on_trait_change('rows.ck+')
    def _selection_changed(self, obj, name, old, new):
        self.combination_updated = True


    def _generate_combinations(self):
        if not self.row_set:
            self.row_set.append(('a',''))
        self.rows = []
        for row in self.row_set:
            ro = Row()
            ro.nid = row[0]
            ro.name = row[1]
            for i in range(len(self.col_set)):
                an = 'ck{0}'.format(i)
                setattr(ro, an, False)
            self.rows.append(ro)
        self._define_columns()


    def _define_columns(self):
        self.cols = []
        oc = ObjectColumn(name='name', editable=False)
        self.cols.append(oc)
        for i, cn in enumerate(self.col_set):
            cc = CombCheck()
            cc.name = 'ck{0}'.format(i)
            cc.label = cn[1]
            self.cols.append(cc)


    traits_view = View(
        Item('rows',
             editor=table_editor,
             show_label=False),
        resizable=True,
        )


    test_view = View(
        Item('rows',
             editor=table_editor,
             show_label=False),
        resizable=True,
        width=300,
        height=200,
        )
class MATS1D5PressureSensitive(MATS1D5Eval):
    ur'''Bond model for two phases interacting over an interface with zero thickness.
The frictional resistance is governed by the current level of pressure 
using the cohesion :math:`c` and frictional angle :math`\phi`. 

Basic formulas

The threshold level of frictional stress is prescribed by the Mohr-Coulomb rule:
    
.. math::
    \tau_\mathrm{fr}(\sigma) = \left( c + \sigma \; \tan{(\phi)} \right) 
     H\left( \sigma -  \frac{c}{\tan{(\phi)}}\right)
    :label: eq_MATS1D5PressureSensitive
    
The deformation variables include interface opening :math:`w` and sliding :math:`s`
related to the stress variables using the equations

.. math::
    \tau = G_s \cdot ( s - s^p )
    
.. math::
    \sigma = \left( G_w^{(+)} H(w) + G_w^{(-)} H(-w) \right) \cdot w

where 
 - :math:`G_s` represents elastic shear stiffness, 
 - :math:`G_w^{(+)}` is the adhesive stiffness for crack opening and 
 - :math:`G_w^{(-)}` is the penetration (or penalty) stiffness to be set large.

The elastic domain is given by the yield condition

.. math::
    f := \left| \tau \right| - \tau_\mathrm{fr}(\sigma) \leq 0

Thus, the Kuhn-Tucker condition must hold:

.. math::
    \dot{\gamma} \geq 0, \; f( \sigma, \tau ) \cdot \gamma \leq 0, \;
    \dot{\gamma} f(\sigma, \tau) = 0

where :math:`\gamma` represents the plastic multiplier.     
The flow rule for yielding slip is provided as

.. math::
    \dot{s}_p = \dot{\gamma} \; \mathrm{sign}(\tau)
    
and the consistency condition (staying on the yield surface upon platic loading)

.. math::
    \dot{\gamma} \dot{f}(\sigma, \tau) = 0

Discrete form

Using the midpoint rule 

Given the displacement increment 

.. math::
    s_{n+1} = s_{n} + \Delta s_{n}, \; 
    w_{n+1} = w_{n} + \Delta w_{n}, \;
    :label: eq_increment
    
the elastic trial stresses are calculated as

.. math::
    \tau_{n+1}^{\mathrm{trial}} = G_s ( s_{n+1} - s_n^p ), \;
    \sigma_{n+1} = G_w ( w_{n+1} )
    :label: eq_constitutive_law

and the frictional threshold for the current transverse stresses

.. math::
    \tau^\mathrm{fr}_{n+1}(\sigma_{n+1}) = 
    \left( c + \sigma_{n+1} \; \tan{(\phi)} \right) 
     H\left( \sigma_{n+1} -  \frac{c}{\tan{(\phi)}}\right)
    :label: eq_mohr_coulomb

The trial consistency condition is obtained as
    
.. math::
    f_{n+1}^\mathrm{trial} = \left| \tau_{n+1}^\mathrm{trial} \right|
    - \tau^\mathrm{fr}_{n+1}(\sigma_{n+1})
    :label: eq_discr_consistency

If :math:`f^\mathrm{trial}_{n+1} \leq 0` then step is elastic.

If :math:`f^\mathrm{trial}_{n+1} > 0 \Leftrightarrow f(\tau_{n+1}, \sigma_{n+1} ) = 0`
The objective is to identify :math:`s^{p}_{n+1}, \Delta \gamma` satisfying this condition
and the condition of consistency. To accomplish this task we first note that

.. math::
    \tau_{n+1}= G_s( s_{n+1} - s^p_{n+1} ) =G_s( s_{n+1} - s^p_{n}) - G_s( s^p_{n+1} - s^p_n )

Using Eq.:eq:`eq_midpoint` the shear stress can be related to trial state and the plastic 
(return mapping) multiplier :math:`\Delta \gamma` as 

.. math::
    \tau_{n+1} = \tau^{\mathrm{trial}}_{n+1} - G_s( s^p_{n+1} - s^p_n )
    = \tau^{\mathrm{trial}}_{n+1} - G_s \Delta \gamma \, \mathrm{sign}( \tau_{n+1} ).

The other two incremental equation deliver the plastic slip and consistency condition.

.. math::
    s^{p}_{n+1} = s^p_n + \Delta \gamma \, \mathrm{sign}( \tau_{n+1} )
    :label: eq_midpoint

.. math::
    f_{n+1} = \left| \tau_{n+1} \right| - \tau^{\mathrm{fr}}(\sigma_{n+1}) = 0
    :label: eq_discr_consistency2

It can be shown that the direction of mapping given by :math:`\mathrm{sign}(\tau_{n+1})`
is consistent with the trial state, i,e. :math:`\mathrm{sign}(\tau^{\mathrm{trial}}_{n+1})`
and

.. math::
    \left| \tau_{n+1} \right| + \Delta \gamma G_s = \left| \tau^{\mathrm{trial}}_{n+1} \right|
    
Finally, due to :math:`\Delta \gamma > 0` the discrete consistency condition 
(:eq:`eq_discr_consistency`) can be further expanded as

.. math::
    f_{n+1} = \left| \tau^{\mathrm{trial}}_{n+1} \right| - 
    G_s \Delta \gamma- \tau^{\mathrm{fr}}( \sigma_{n+1} )

Hence

.. math::
    f_{n+1} = 0 \implies \Delta \gamma = \frac{ f^{\mathrm{trial}}_{n+1}}{ G_s } > 0

and

.. math::
    \tau_{n+1} &= \tau^{\mathrm{trial}}_{n+1} - 
    \Delta \gamma G_s \, \mathrm{sign}( \tau_{n+1}^{\mathrm{trial}} ) \\
    s^p_{n+1} &= s^p_n + 
    \Delta \gamma \, \mathrm{sign}( \tau_{n+1}^{\mathrm{trial}} ) \\ 

    '''

    implements(IMATSEval)

    G_s = Float(1.0, input = True, enter_set = False,
                   label = 'cohesion')

    G_w_open = Float(1.0, input = True, enter_set = False,
                   label = 'cohesion')

    G_w_close = Float(1e+6, input = True, enter_set = False,
                   label = 'cohesion')

    c = Float(0.0, input = True, enter_set = False,
               label = 'cohesion')

    phi = Float(0.1, input = True, enter_set = False,
                label = 'friction angle')

    #-----------------------------------------------------------------------------------------------
    # Submodels constituting the interface behavior
    #-----------------------------------------------------------------------------------------------

    traits_view = View(Item('c@'),
                        Item('phi@'),
                        Item('G_open@'),
                        Item('G_slip@'),
                        Item('G_penalty@'),
                        resizable = True,
                        scrollable = True,
                        width = 0.8,
                        height = 0.9,
                        buttons = ['OK', 'Cancel'])

    #-----------------------------------------------------------------------------------------------
    # Setup for computation within a supplied spatial context
    #-----------------------------------------------------------------------------------------------

    def get_state_array_size(self):
        '''
        Return the number of floats to be saved
        '''
        return 1

    #-----------------------------------------------------------------------------------------------
    # Evaluation - get the corrector and predictor
    #-----------------------------------------------------------------------------------------------

    def get_corr_pred(self, sctx, eps_app_eng, d_eps_app_eng, tn, tn1, *args, **kw):
        '''
        Corrector predictor computation.
        @param eps_app_eng input variable - engineering strain
        '''

        eps1, s, w, eps2 = eps_app_eng
        d_eps1, d_s, d_w, e_eps2 = eps_app_eng
        sig_app_eng = zeros_like(eps_app_eng)

        if sctx.update_state_on:
            slip_n = s - d_s
            slip_p_n = slip_n # get the plastic slip 
            sctx.mats_state_array[0] = slip_p_n

        # @todo [rch] dirty - when called form response tracer        
        if isinstance(d_eps_app_eng, int) and d_eps_app_eng == 0:
            d_eps_app_eng = zeros_like(eps_app_eng)

        s_n = s
        s_p_n = sctx.mats_state_array[0]

        f_separate = (Heaviside(w) * self.G_open + Heaviside(-w) * self.G_penalty) * w

        n = self.G_penalty
        tau_trial = self.G_slip * (s_n - s_p_n);
        f_trial = abs(tau_trial) - (f_separate + math.tan(self.phi));

        if f_trial <= 1e-8:
            sig_n1[2] = tau_trial;
            D_n1[0, 0] = E;
        else:
            d_gamma = f_trial / (self.E + self.K_bar + self.H_bar);
            sig_n1[0] = sigma_trial - d_gamma * self.E * sign(xi_trial);
            D_n1[0, 0] = (self.E * (self.K_bar + self.H_bar)) / \
                            (self.E + self.K_bar + self.H_bar);

        sig_n1 = zeros((1,), dtype = 'float_')
        D_n1 = zeros((1, 1), dtype = 'float_')


        D_mtx = zeros((eps_app_eng.shape[0], eps_app_eng.shape[0]), dtype = 'float_')

        return sig_app_eng, D_mtx

    def get_sig1(self, sctx, eps_app_eng, *args, **kw):
        sig_eng, D_mtx = self.get_corr_pred(sctx, eps_app_eng, 0, 0, 0)
        return sig_eng[0:1]

    def get_sig2(self, sctx, eps_app_eng, *args, **kw):
        sig_eng, D_mtx = self.get_corr_pred(sctx, eps_app_eng, 0, 0, 0)
        return sig_eng[3:]

    def get_shear_flow(self, sctx, eps_app_eng, *args, **kw):
        sig_eng, D_mtx = self.get_corr_pred(sctx, eps_app_eng, 0, 0, 0)
        return sig_eng[1:2]

    def get_cohesive_stress(self, sctx, eps_app_eng, *args, **kw):
        sig_eng, D_mtx = self.get_corr_pred(sctx, eps_app_eng, 0, 0, 0)
        return sig_eng[2:3]

    rte_dict = Property
    def _get_rte_dict(self):

        rte_dict = {}
        ix_maps = [0, 1, 2, 3]
        for name, mats, ix_map, size, offset in \
            zip(self._mats_names, self._mats_list, ix_maps, self._state_sizes,
                 self._state_offsets):
            for key, v_eval in mats.rte_dict.items():

                __call_v_eval = RTE1D5Bond(v_eval = v_eval,
                                            name = name + '_' + key,
                                            size = size,
                                            offset = offset,
                                            ix_map = ix_map)

                rte_dict[ name + '_' + key ] = __call_v_eval


        # sigma is also achievable through phase1_sig_app and phase_2_sig_app
        extra_rte_dict = {'sig1' : self.get_sig1,
                          'sig2' : self.get_sig2,
                          'shear_flow' : self.get_shear_flow,
                          'cohesive_stress' : self.get_cohesive_stress,
                          }
        rte_dict.update(extra_rte_dict)
        return rte_dict
    #-------------------------------------------------------------------------------------
    # Methods required by the mats_explore tool
    #-------------------------------------------------------------------------------------
    def new_cntl_var(self):
        return zeros(4, 'float_')

    def new_resp_var(self):
        return zeros(4, 'float_')
示例#21
0
class Person(HasTraits):
    first_name = Str()
    last_name = Str()
    age = Int()
    gender = Trait(None, 'M', 'F')
    name_view = View('first_name', 'last_name')
示例#22
0
class ExpBT4PTRF(ExType):
    '''Experiment: Bending Test Four Point with RetroFitting beam
    '''
    #    label = Str('four point bending test')

    implements(IExType)

    file_ext = 'DAT'

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

    input_change = Event

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

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

    # effective length of the bending test specimen
    # (does not include the part at each side of the specimens that leaps over the support lines)
    #
    length = Float(3.30,
                   unit='m',
                   input=True,
                   table_field=True,
                   auto_set=False,
                   enter_set=True)
    length_loadintroduction = Float(0.70,
                                    unit='m',
                                    input=True,
                                    table_field=True,
                                    auto_set=False,
                                    enter_set=True)
    width = Float(0.50,
                  unit='m',
                  input=True,
                  table_field=True,
                  auto_set=False,
                  enter_set=True)
    thickness = Float(0.20,
                      unit='m',
                      input=True,
                      table_field=True,
                      auto_set=False,
                      enter_set=True)

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

    # additional own weight of the steel traverse and steel rolls used for
    # load introduction
    weight_load_introduction = Float(1.3,
                                     unit='kN',
                                     input=True,
                                     table_field=True,
                                     auto_set=False,
                                     enter_set=True)

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

    ccs = Instance(CompositeCrossSection)

    def _ccs_default(self):
        '''default settings'
        '''
        # SFB 532 - demonstrator textil and concrete:
        fabric_layout_key = 'CAR-3300-SBR_BTZ2'
        concrete_mixture_key = 'Pagel_TF10'
        orientation_fn_key = 'all0'
        n_layers = 2
        s_tex_z = 0.015 / (n_layers + 1)
        ccs = CompositeCrossSection(fabric_layup_list=[
            plain_concrete(s_tex_z * 0.5),
            FabricLayUp(n_layers=n_layers,
                        orientation_fn_key=orientation_fn_key,
                        s_tex_z=s_tex_z,
                        fabric_layout_key=fabric_layout_key),
            plain_concrete(s_tex_z * 0.5)
        ],
                                    concrete_mixture_key=concrete_mixture_key)
        return ccs

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

    # E-modulus of the composite at the time of testing
    E_c = Property(Float,
                   unit='MPa',
                   depends_on='input_change',
                   table_field=True)

    def _get_E_c(self):
        return self.ccs.get_E_c_time(self.age)

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

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

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

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

    data_array_ironed = Property(
        Array(float), depends_on='data_array, +ironing_param, +axis_selection')

    @cached_property
    def _get_data_array_ironed(self):
        '''remove the jumps in the displacement curves
        due to resetting the displacement gauges.
        '''
        print '*** curve ironing activated ***'

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

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

            # use ironing method only for columns of the displacement gauges.
            #
            #            print 'self.names_and_units[0]',self.names_and_units[0]
            #            print 'self.names_and_units',self.names_and_units
            if self.names_and_units[0][idx] in {
                    'WA_M1', 'WA_M2', 'WA_L', 'WA_R'
            }:

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

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

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

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

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

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

                data_array_ironed[:, idx] = data_arr[:]

        return data_array_ironed

    def process_source_data(self):
        '''read in the measured data from file and assign
        attributes after array processing.
        If necessary modify the assigned data, i.e. change
        the sign or specify an offset for the specific test setup.
        '''
        print '*** process source data ***'

        super(ExpBT4PTRF, self).process_source_data()

        self._read_data_array()

        # curve ironing:
        #
        self.processed_data_array = self.data_array_ironed

        # set attributes:
        #
        self._set_array_attribs()

        # PEEKEL-measuring software:

        # convert units and change signs
        self.Kraft -= self.Kraft[0]
        self.Kraft *= -1

        # add weight of load introduction to force
        print 'add weight of steel traverse to force'
        self.Kraft += self.weight_load_introduction
        print 'force at initial state ', self.weight_load_introduction
        # @todo: interpolate an initial deformation based on the initial force and the initial stiffness
        #       measured in order to start the F-w-curve at the origin!

        # (reset displacement gauges by their initial values and change sign
        # in order to return a positive value for a displacement)

        # vertical displacements [mm]:
        self.WA_M1 -= self.WA_M1[0]
        self.WA_M1 *= -1
        self.WA_M2 -= self.WA_M2[0]
        self.WA_M2 *= -1
        self.WA_L -= self.WA_L[0]
        self.WA_L *= -1
        self.WA_R -= self.WA_R[0]
        self.WA_R *= -1

        # horizontal displacements at the bottom side of the bending specimen
        # [mm]
        self.WA_HR -= self.WA_HR[0]
        self.WA_HR *= -1
        self.WA_HM -= self.WA_HM[0]
        self.WA_HM *= -1
        self.WA_HL -= self.WA_HL[0]
        self.WA_HL *= -1

        # optional additional displacement gauges for crack width measuring of
        # shear cracks
        self.Schub1 -= self.Schub1[0]
        self.Schub1 *= -1
        self.Schub1 -= self.Schub1[0]
        self.Schub1 *= -1

        # DMS for steel bars on vertical shear reinforcement
        self.VL2 -= self.VL2[0]
        self.VL2 *= -1
        self.VL3 -= self.VL3[0]
        self.VL3 *= -1
        self.VR2 -= self.VR2[0]
        self.VR2 *= -1
        self.VR3 -= self.VR3[0]
        self.VR3 *= -1

        # compressive strain at the upper side of the bending specimen at midspan [mm]
        # change unite from [nm/m], i.e. [10^(-6)*m / m], to [mm/m=permille]
        self.CM -= self.CM[0]
        self.CM /= 1000.
        self.CML -= self.CML[0]
        self.CML /= 1000.
        self.CMR -= self.CMR[0]
        self.CMR /= 1000.

        # DMS for longitudinal steel bars
        self.SL -= self.SL[0]
        self.SL /= 1000.
        self.SML -= self.SML[0]
        self.SML /= 1000.
        self.SR -= self.SR[0]
        self.SR /= 1000.
        self.SMR -= self.SMR[0]
        self.SMR /= 1000.
        self.SM1 -= self.SM1[0]
        self.SM1 /= 1000.
        self.SM2 -= self.SM2[0]
        self.SM2 /= 1000.

        # set attributes of displacement (original data before ironing):
        #
        WA_M1_orig = np.copy(self.WA_M1)
        self.add_trait("WA_M1_orig", Array(value=WA_M1_orig, transient=True))
        WA_M2_orig = np.copy(self.WA_M2)
        self.add_trait("WA_M2_orig", Array(value=WA_M2_orig, transient=True))
        WA_R_orig = np.copy(self.WA_R)
        self.add_trait("WA_R_orig", Array(value=WA_R_orig, transient=True))
        WA_L_orig = np.copy(self.WA_L)
        self.add_trait("WA_L_orig", Array(value=WA_L_orig, transient=True))

    K_bending_elast_c = Property(Array('float_'), depends_on='input_change')

    @cached_property
    def _get_K_bending_elast_c(self):
        '''calculate the analytical bending stiffness of the beam (4 point bending)
        relation between center deflection and 2 * load/2 in the thirdpoints (sum up to F)
        '''
        # @todo: update formula to be calculated based on 'with',total 'length' and 'lenght_loadintroduction'
        t = self.thickness
        w = self.width
        L = self.length
        L_load = self.length_loadintroduction

        # coposite E-modulus
        #
        E_c = self.E_c

        # moment of inertia
        #
        I_yy = t**3 * w / 12.

        delta_11 = (L**3) / 56.348 / E_c / I_yy

        # [MN/m]=[kN/mm] bending stiffness with respect to a force applied at center of the beam
        #
        K_bending_elast_c = 1 / delta_11
        #         print 'K_bending_elast_c', K_bending_elast_c

        print 'K_bending_elast_c', K_bending_elast_c
        return K_bending_elast_c

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

    plot_templates = {
        'force / deflection (center)':
        '_plot_force_deflection_center',
        'force / deflection (center) - original':
        '_plot_force_deflection_center_orig',
        'force / deflection (thirdpoints)':
        '_plot_force_deflection_thirdpoints',
        'strain (top/bottom) / force':
        '_plot_strain_top_bottom_force',
        'displacement (ironed/original - center)':
        '_plot_ironed_orig_force_deflection_center',
        'displacement (ironed/original - left)':
        '_plot_ironed_orig_force_deflection_left',
        'displacement (ironed/original - right)':
        '_plot_ironed_orig_force_deflection_right',
    }

    default_plot_template = 'force / deflection (center)'

    # get only the ascending branch of the response curve
    #
    max_force_idx = Property(Int)

    def _get_max_force_idx(self):
        '''get the index of the maximum force'''
        # NOTE: processed data returns positive values for force and
        # displacement
        return argmax(self.Kraft)

    def _plot_force_deflection_center(self,
                                      axes,
                                      offset_w=0.,
                                      color='black',
                                      linewidth=1.,
                                      label=None):
        # get only the ascending branch of the response curve
        f_asc = self.Kraft[:self.max_force_idx + 1]
        w_asc_M1 = self.WA_M1[:self.max_force_idx + 1]
        w_asc_M2 = self.WA_M2[:self.max_force_idx + 1]
        w_asc_Mavg = (w_asc_M1 + w_asc_M2) / 2.

        # add curves
        #
        axes.plot(w_asc_Mavg,
                  f_asc,
                  linewidth=linewidth,
                  label=label,
                  color=color)

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

    def _plot_force_deflection_center_orig(self,
                                           axes,
                                           offset_w=0.,
                                           color='black',
                                           linewidth=1.,
                                           label=None):
        '''plot the original data before jumps has been processed out
        '''
        # get the ascending AND unloading branch of the response curve
        f = self.Kraft
        w_M1_orig = self.WA_M1_orig
        w_M2_orig = self.WA_M2_orig
        w_Mavg_orig = (w_M1_orig + w_M2_orig) / 2.

        # get only the ascending branch of the response curve
        f_asc = self.Kraft[:self.max_force_idx + 1]
        w_asc_M1_orig = self.WA_M1_orig[:self.max_force_idx + 1]
        w_asc_M2_orig = self.WA_M2_orig[:self.max_force_idx + 1]
        w_asc_Mavg_orig = (w_asc_M1_orig + w_asc_M2_orig) / 2.

        # add curves
        #
        #         axes.plot(w_asc_Mavg_orig, f_asc, linewidth=linewidth, label=label, color=color)
        axes.plot(w_Mavg_orig,
                  f,
                  linewidth=linewidth,
                  label=label,
                  color=color)

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

    def _plot_force_deflection_thirdpoints(self, axes):
        '''deflection at the third points (under the loading points)
        '''
        # get only the ascending branch of the response curve
        f_asc = self.Kraft[:self.max_force_idx + 1]
        # displacement left
        w_l_asc = self.WA_L[:self.max_force_idx + 1]
        # displacement right
        w_r_asc = self.WA_R[:self.max_force_idx + 1]

        axes.plot(w_l_asc, f_asc, color='green', linewidth=1)
        axes.plot(w_r_asc, f_asc, color='green', linewidth=1)

    def _plot_strain_top_bottom_force(self,
                                      axes,
                                      color='black',
                                      linewidth=1.,
                                      label=None):
        '''plot compressive strains at top and
        average tensile strains based on horizontal displacement gauges
        '''
        # get only the ascending branch of the response curve
        f_asc = self.Kraft[:self.max_force_idx + 1]

        # compressive strains (top) [permile]
        eps_CM = self.CM[:self.max_force_idx + 1]
        eps_CMR = self.CMR[:self.max_force_idx + 1]
        eps_CML = self.CML[:self.max_force_idx + 1]

        # tensile strain (bottom) [permile];
        eps_HL = self.WA_HL[:self.max_force_idx + 1] / \
            self.gauge_length_horizontal
        eps_HM = self.WA_HM[:self.max_force_idx + 1] / \
            self.gauge_length_horizontal
        eps_HR = self.WA_HR[:self.max_force_idx + 1] / \
            self.gauge_length_horizontal

        # add curves
        #
        axes.plot(eps_CM,
                  f_asc,
                  linewidth=linewidth,
                  label='compression: eps_CM',
                  color='grey')
        axes.plot(eps_CMR,
                  f_asc,
                  linewidth=linewidth,
                  label='compression: eps_CMR',
                  color='grey')
        axes.plot(eps_CML,
                  f_asc,
                  linewidth=linewidth,
                  label='compression: eps_CML',
                  color='grey')
        axes.plot(eps_HL,
                  f_asc,
                  linewidth=linewidth,
                  label='tension: eps_HL',
                  color='k')
        axes.plot(eps_HM,
                  f_asc,
                  linewidth=linewidth,
                  label='tension: eps_HM',
                  color='k')
        axes.plot(eps_HR,
                  f_asc,
                  linewidth=linewidth,
                  label='tension: eps_HR',
                  color='k')

        # add axes labels
        #
        xkey = 'strain [1*e-3]'
        ykey = 'force [kN]'
        axes.set_xlabel('%s' % (xkey, ))
        axes.set_ylabel('%s' % (ykey, ))

    def _plot_avg_strain_bottom_force(self,
                                      axes,
                                      color='black',
                                      linewidth=1.,
                                      label=None):
        '''plot compressive strains at top and
        average tensile strains based on horizontal displacement gauges
        '''
        # get only the ascending branch of the response curve
        f_asc = self.Kraft  # [:self.max_force_idx + 1]

        # tensile strain (bottom) [permile];
        eps_HL = self.WA_HL / \
            self.gauge_length_horizontal
        eps_HM = self.WA_HM / \
            self.gauge_length_horizontal
        eps_HR = self.WA_HR / \
            self.gauge_length_horizontal

        # add curves
        #

        #        axes.plot(eps_HL, f_asc, linewidth=linewidth,
        #                   label= label + ' WA: HL', color='k')
        #        axes.plot(eps_HM, f_asc, linewidth=linewidth,
        #                   label= label + ' WA: HM', color='g')
        axes.plot(eps_HR,
                  f_asc,
                  linewidth=linewidth,
                  label=label + ' WA: HR',
                  color='k')

        # add axes labels
        #
        xkey = 'strain [1*e-3]'
        ykey = 'force [kN]'
        axes.set_xlabel('%s' % (xkey, ))
        axes.set_ylabel('%s' % (ykey, ))

    def _plot_ironed_orig_force_deflection_center(self, axes):
        '''plot original displacement (center) as measured by the displacement gauge
        and compare with curve after data has been processed by ironing procedure
        '''
        # get only the ascending branch of the response curve
        F_asc = self.Kraft[:self.max_force_idx + 1]
        w_ironed_asc = self.WA_M1[:self.max_force_idx + 1]
        w_orig_asc = self.WA_M1_orig[:self.max_force_idx + 1]

        # add curves
        #
        axes.plot(w_ironed_asc, F_asc, color='blue', linewidth=1.5)
        axes.plot(w_orig_asc, F_asc, color='grey', linewidth=1.5)

        # add axes labels
        #
        xkey = 'deflection (original data / ironed data) [mm]'
        ykey = 'force [kN]'
        axes.set_xlabel('%s' % (xkey, ))
        axes.set_ylabel('%s' % (ykey, ))

    def _plot_ironed_orig_force_deflection_left(self, axes):
        '''plot original displacement (left) as measured by the displacement gauge
        and compare with curve after data has been processed by ironing procedure
        '''
        w_ironed = self.WA_L
        w_orig = self.WA_L_orig
        F = self.Kraft
        axes.plot(w_ironed, F)
        axes.plot(w_orig, F)
        xkey = 'deflection (original data / ironed data) [mm]'
        ykey = 'force [kN]'
        axes.set_xlabel('%s' % (xkey, ))
        axes.set_ylabel('%s' % (ykey, ))

    def _plot_ironed_orig_force_deflection_right(self, axes):
        '''plot original displacement (left) as measured by the displacement gauge
        and compare with curve after data has been processed by ironing procedure
        '''
        w_ironed = self.WA_R
        w_orig = self.WA_R_orig
        F = self.Kraft
        axes.plot(w_ironed, F)
        axes.plot(w_orig, F)
        xkey = 'deflection (original data / ironed data) [mm]'
        ykey = 'force [kN]'
        axes.set_xlabel('%s' % (xkey, ))
        axes.set_ylabel('%s' % (ykey, ))

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

    traits_view = View(VGroup(
        Group(Item('length', format_str="%.3f"),
              Item('length_loadintroduction', format_str="%.3f"),
              Item('width', format_str="%.3f"),
              Item('thickness', format_str="%.3f"),
              label='geometry'),
        Group(Item('weight_load_introduction'),
              Item('loading_rate'),
              Item('gauge_length_horizontal'),
              Item('age'),
              label='loading rate and age'),
        Group(Item('jump_rtol', format_str="%.4f"), label='curve_ironing'),
        Group(Item('E_c', show_label=True, style='readonly',
                   format_str="%.0f"),
              Item('ccs@', show_label=False),
              label='composite cross section')),
                       scrollable=True,
                       resizable=True,
                       height=0.8,
                       width=0.6)
示例#23
0
 def traits_view(self):
     v = View(UItem('component', editor=ComponentEditor()))
     return v
示例#24
0
 def traits_view(self):
     v = View(HGroup(Item('auto_title'),
                     UItem('title', enabled_when='not auto_title'),
                     icon_button_editor('options_button', 'cog')))
     return v
示例#25
0
"""This demo shows how to use Traits TreeEditors with PyTables to walk the
heirarchy of an HDF5 file.  This only picks out arrays and groups, but could
easily be extended to other structures, like tables.

In the demo, the path to the selected item is printed whenever the selection
changes.  In order to run, a path to an existing HDF5 database must be given
at the bottom of this file.
"""

from traits.api import HasTraits, Str, List, Instance
from traitsui.api import TreeEditor, TreeNode, View, Item, Group

import tables as tb

# View for objects that aren't edited
no_view = View()


# HDF5 Nodes in the tree
class Hdf5ArrayNode(HasTraits):
    name = Str('<unknown>')
    path = Str('<unknown>')
    parent_path = Str('<unknown>')


class Hdf5GroupNode(HasTraits):
    name = Str('<unknown>')
    path = Str('<unknown>')
    parent_path = Str('<unknown>')
    # Can't have recursive traits?  Really?
    #groups = List( Hdf5GroupNode )
class PlotUI(HasTraits):

    # container for all plots
    container = Instance(HPlotContainer)

    # Plot components within this container:
    polyplot = Instance(ContourPolyPlot)
    lineplot = Instance(ContourLinePlot)
    cross_plot = Instance(Plot)
    cross_plot2 = Instance(Plot)
    colorbar = Instance(ColorBar)

    # plot data
    pd = Instance(ArrayPlotData)

    # view options
    num_levels = Int(15)
    colormap = Enum(colormaps)

    #Traits view definitions:
    traits_view = View(Group(
        UItem('container', editor=ComponentEditor(size=(800, 600)))),
                       resizable=True)

    plot_edit_view = View(Group(Item('num_levels'), Item('colormap')),
                          buttons=["OK", "Cancel"])

    #---------------------------------------------------------------------------
    # Private Traits
    #---------------------------------------------------------------------------

    _image_index = Instance(GridDataSource)
    _image_value = Instance(ImageData)

    _cmap = Trait(default_colormaps.jet, Callable)

    #---------------------------------------------------------------------------
    # Public View interface
    #---------------------------------------------------------------------------

    def __init__(self, *args, **kwargs):
        super(PlotUI, self).__init__(*args, **kwargs)
        # FIXME: 'with' wrapping is temporary fix for infinite range in initial
        # color map, which can cause a distracting warning print. This 'with'
        # wrapping should be unnecessary after fix in color_mapper.py.
        with errstate(invalid='ignore'):
            self.create_plot()

    def create_plot(self):

        # Create the mapper, etc
        self._image_index = GridDataSource(array([]),
                                           array([]),
                                           sort_order=("ascending",
                                                       "ascending"))
        image_index_range = DataRange2D(self._image_index)
        self._image_index.on_trait_change(self._metadata_changed,
                                          "metadata_changed")

        self._image_value = ImageData(data=array([]), value_depth=1)
        image_value_range = DataRange1D(self._image_value)

        # Create the contour plots
        self.polyplot = ContourPolyPlot(index=self._image_index,
                                        value=self._image_value,
                                        index_mapper=GridMapper(range=
                                            image_index_range),
                                        color_mapper=\
                                            self._cmap(image_value_range),
                                        levels=self.num_levels)

        self.lineplot = ContourLinePlot(
            index=self._image_index,
            value=self._image_value,
            index_mapper=GridMapper(range=self.polyplot.index_mapper.range),
            levels=self.num_levels)

        # Add a left axis to the plot
        left = PlotAxis(orientation='left',
                        title="y",
                        mapper=self.polyplot.index_mapper._ymapper,
                        component=self.polyplot)
        self.polyplot.overlays.append(left)

        # Add a bottom axis to the plot
        bottom = PlotAxis(orientation='bottom',
                          title="x",
                          mapper=self.polyplot.index_mapper._xmapper,
                          component=self.polyplot)
        self.polyplot.overlays.append(bottom)

        # Add some tools to the plot
        self.polyplot.tools.append(
            PanTool(self.polyplot, constrain_key="shift"))
        self.polyplot.overlays.append(
            ZoomTool(component=self.polyplot, tool_mode="box",
                     always_on=False))
        self.polyplot.overlays.append(
            LineInspector(component=self.polyplot,
                          axis='index_x',
                          inspect_mode="indexed",
                          write_metadata=True,
                          is_listener=True,
                          color="white"))
        self.polyplot.overlays.append(
            LineInspector(component=self.polyplot,
                          axis='index_y',
                          inspect_mode="indexed",
                          write_metadata=True,
                          color="white",
                          is_listener=True))

        # Add these two plots to one container
        contour_container = OverlayPlotContainer(padding=20,
                                                 use_backbuffer=True,
                                                 unified_draw=True)
        contour_container.add(self.polyplot)
        contour_container.add(self.lineplot)

        # Create a colorbar
        cbar_index_mapper = LinearMapper(range=image_value_range)
        self.colorbar = ColorBar(index_mapper=cbar_index_mapper,
                                 plot=self.polyplot,
                                 padding_top=self.polyplot.padding_top,
                                 padding_bottom=self.polyplot.padding_bottom,
                                 padding_right=40,
                                 resizable='v',
                                 width=30)

        self.pd = ArrayPlotData(line_index=array([]),
                                line_value=array([]),
                                scatter_index=array([]),
                                scatter_value=array([]),
                                scatter_color=array([]))

        self.cross_plot = Plot(self.pd, resizable="h")
        self.cross_plot.height = 100
        self.cross_plot.padding = 20
        self.cross_plot.plot(("line_index", "line_value"), line_style="dot")
        self.cross_plot.plot(
            ("scatter_index", "scatter_value", "scatter_color"),
            type="cmap_scatter",
            name="dot",
            color_mapper=self._cmap(image_value_range),
            marker="circle",
            marker_size=8)

        self.cross_plot.index_range = self.polyplot.index_range.x_range

        self.pd.set_data("line_index2", array([]))
        self.pd.set_data("line_value2", array([]))
        self.pd.set_data("scatter_index2", array([]))
        self.pd.set_data("scatter_value2", array([]))
        self.pd.set_data("scatter_color2", array([]))

        self.cross_plot2 = Plot(self.pd,
                                width=140,
                                orientation="v",
                                resizable="v",
                                padding=20,
                                padding_bottom=160)
        self.cross_plot2.plot(("line_index2", "line_value2"), line_style="dot")
        self.cross_plot2.plot(
            ("scatter_index2", "scatter_value2", "scatter_color2"),
            type="cmap_scatter",
            name="dot",
            color_mapper=self._cmap(image_value_range),
            marker="circle",
            marker_size=8)

        self.cross_plot2.index_range = self.polyplot.index_range.y_range

        # Create a container and add components
        self.container = HPlotContainer(padding=40,
                                        fill_padding=True,
                                        bgcolor="white",
                                        use_backbuffer=False)
        inner_cont = VPlotContainer(padding=0, use_backbuffer=True)
        inner_cont.add(self.cross_plot)
        inner_cont.add(contour_container)
        self.container.add(self.colorbar)
        self.container.add(inner_cont)
        self.container.add(self.cross_plot2)

    def update(self, model):
        self.minz = model.minz
        self.maxz = model.maxz
        self.colorbar.index_mapper.range.low = self.minz
        self.colorbar.index_mapper.range.high = self.maxz
        self._image_index.set_data(model.xs, model.ys)
        self._image_value.data = model.zs
        self.pd.set_data("line_index", model.xs)
        self.pd.set_data("line_index2", model.ys)
        self.container.invalidate_draw()
        self.container.request_redraw()

    #---------------------------------------------------------------------------
    # Event handlers
    #---------------------------------------------------------------------------

    def _metadata_changed(self, old, new):
        """ This function takes out a cross section from the image data, based
        on the line inspector selections, and updates the line and scatter
        plots."""

        self.cross_plot.value_range.low = self.minz
        self.cross_plot.value_range.high = self.maxz
        self.cross_plot2.value_range.low = self.minz
        self.cross_plot2.value_range.high = self.maxz
        if self._image_index.metadata.has_key("selections"):
            x_ndx, y_ndx = self._image_index.metadata["selections"]
            if y_ndx and x_ndx:
                self.pd.set_data("line_value",
                                 self._image_value.data[y_ndx, :])
                self.pd.set_data("line_value2", self._image_value.data[:,
                                                                       x_ndx])
                xdata, ydata = self._image_index.get_data()
                xdata, ydata = xdata.get_data(), ydata.get_data()
                self.pd.set_data("scatter_index", array([xdata[x_ndx]]))
                self.pd.set_data("scatter_index2", array([ydata[y_ndx]]))
                self.pd.set_data("scatter_value",
                                 array([self._image_value.data[y_ndx, x_ndx]]))
                self.pd.set_data("scatter_value2",
                                 array([self._image_value.data[y_ndx, x_ndx]]))
                self.pd.set_data("scatter_color",
                                 array([self._image_value.data[y_ndx, x_ndx]]))
                self.pd.set_data("scatter_color2",
                                 array([self._image_value.data[y_ndx, x_ndx]]))
        else:
            self.pd.set_data("scatter_value", array([]))
            self.pd.set_data("scatter_value2", array([]))
            self.pd.set_data("line_value", array([]))
            self.pd.set_data("line_value2", array([]))

    def _colormap_changed(self):
        self._cmap = default_colormaps.color_map_name_dict[self.colormap]
        if self.polyplot is not None:
            value_range = self.polyplot.color_mapper.range
            self.polyplot.color_mapper = self._cmap(value_range)
            value_range = self.cross_plot.color_mapper.range
            self.cross_plot.color_mapper = self._cmap(value_range)
            # FIXME: change when we decide how best to update plots using
            # the shared colormap in plot object
            self.cross_plot.plots["dot"][0].color_mapper = self._cmap(
                value_range)
            self.cross_plot2.plots["dot"][0].color_mapper = self._cmap(
                value_range)
            self.container.request_redraw()

    def _num_levels_changed(self):
        if self.num_levels > 3:
            self.polyplot.levels = self.num_levels
            self.lineplot.levels = self.num_levels
class TransformData(Filter):
    """Performs a linear transformation to input data using a
    tvtk.BoxWidget.  This does not work with
    ImageData/StructuredPoints/RectilinearGrid.
    """

    # The version of this class.  Used for persistence.
    __version__ = 0

    # The widget that we use to perform the transformation.
    widget = Instance(tvtk.ThreeDWidget, allow_none=False, record=True)

    # The filter we manage.
    filter = Instance(tvtk.Object, allow_none=False)

    # The transform.
    transform = Property

    # Update the data immediately or at the end of the interaction.
    update_mode = Trait('semi-interactive',
                        TraitMap({'interactive':'InteractionEvent',
                                  'semi-interactive': 'EndInteractionEvent'}),
                        desc='speed at which the data should be updated')

    input_info = PipelineInfo(datasets=['poly_data',
                                        'structured_grid',
                                        'unstructured_grid'],
                              attribute_types=['any'],
                              attributes=['any'])

    output_info = PipelineInfo(datasets=['poly_data',
                                         'structured_grid',
                                         'unstructured_grid'],
                               attribute_types=['any'],
                               attributes=['any'])

    ########################################
    # View related code.

    # Reset the transformation.
    reset = Button("Reset Transformation")

    view = View(Group(Group(Item('update_mode'),
                            ),
                      Group(Item('reset'),
                            Item(name='widget', style='custom', resizable=True),
                            show_labels=False
                            )
                      ),
                resizable=True
                )

    ########################################
    # Private traits.
    _transform = Instance(tvtk.Transform, allow_none=False)

    _first = Bool(True)

    _observer_id = Int(-1)

    ######################################################################
    # `object` interface.
    ######################################################################
    def __get_pure_state__(self):
        d = super(TransformData, self).__get_pure_state__()
        for name in ('_first', '_observer_id'):
            d.pop(name, None)
        d['matrix'] = cPickle.dumps(self._transform.matrix)
        return d

    def __set_pure_state__(self, state):
        mat = state.pop('matrix')
        super(TransformData, self).__set_pure_state__(state)
        state_pickler.set_state(self, state)
        self._transform.set_matrix(cPickle.loads(mat))
        self.widget.set_transform(self._transform)

    ######################################################################
    # `Filter` interface.
    ######################################################################
    def setup_pipeline(self):
        self._transform = tvtk.Transform()
        self.widget = tvtk.BoxWidget(place_factor=1.1)
        self.filter = tvtk.TransformFilter()
        super(TransformData, self).setup_pipeline()

    def update_pipeline(self):
        # Do nothing if there is no input.
        inputs = self.inputs
        if len(inputs) == 0:
            return

        inp = inputs[0].get_output_dataset()
        if inp.is_a('vtkImageData') or inp.is_a('vtkRectilinearGrid'):
            error('Transformation not supported for '\
                  'ImageData/StructuredPoints/RectilinearGrid')
            return

        # Set the input for the widget and place it if this hasn't
        # been done before.
        w = self.widget
        self.configure_input_data(w, inp)
        if self._first:
            w.place_widget()
            self._first = False

        # By default we set the input to the first output of the first
        # input.
        fil = self.filter
        self.configure_connection(fil, inputs[0])
        fil.transform = self._transform
        fil.update()
        self._set_outputs([fil])

    def update_data(self):
        # Do nothing if there is no input.
        if len(self.inputs) == 0:
            return

        self.filter.update()
        # Propagate the data_changed event.
        self.data_changed = True

    ######################################################################
    # Non-public interface.
    ######################################################################
    def _get_transform(self):
        return self._transform

    def _on_interaction_event(self, obj, event):
        tfm = self._transform
        self.widget.get_transform(tfm)
        f = self.filter
        f.transform = tfm
        f.update()
        self.render()
        recorder = self.recorder
        if recorder is not None:
            state = {}
            state['elements'] = tfm.matrix.__getstate__()['elements']
            name = recorder.get_script_id(self)
            recorder.record('%s.transform.matrix.__setstate__(%s)'\
                            %(name, state))
            recorder.record('%s.widget.set_transform(%s.transform)'\
                            %(name, name))
            recorder.record('%s.filter.update()'%name)

    def _widget_changed(self, old, new):
        if old is not None:
            old.on_trait_change(self.render, remove=True)
            old.remove_observer(self._observer_id)
            self.widgets.remove(old)
        new.on_trait_change(self.render)
        self._observer_id = new.add_observer(self.update_mode_,
                                             self._on_interaction_event)
        self.widgets.append(new)
        if len(self.inputs) > 0:
            self.configure_input(new, self.inputs[0].outputs[0])

    def _filter_changed(self, old, new):
        if old is not None:
            old.on_trait_change(self.render, remove=True)
        new.on_trait_change(self.render)
        transform = self.transform
        if transform is not None:
            new.transform = transform
        if len(self.inputs) > 0:
            self.configure_connection(new, self.inputs[0])
            self.outputs = [new]

    def _reset_fired(self):
        self._transform.identity()
        self.widget.place_widget()
        self.filter.update()
        self.render()

    def _update_mode_changed(self, old, new):
        w = self.widget
        if w is not None:
            w.remove_observer(self._observer_id)
            self._observer_id = w.add_observer(self.update_mode_,
                                               self._on_interaction_event)
            self.render()
class Model(HasTraits):

    #Traits view definitions:
    traits_view = View(Group(
        Item('function'),
        HGroup(Item('npts_x', label="Number X Points"),
               Item('npts_y', label="Number Y Points")),
        HGroup(Item('min_x', label="Min X value"),
               Item('max_x', label="Max X value")),
        HGroup(Item('min_y', label="Min Y value"),
               Item('max_y', label="Max Y value"))),
                       buttons=["OK", "Cancel"])

    function = Str("tanh(x**2+y)*cos(y)*jn(0,x+y*2)")

    npts_x = CInt(400)
    npts_y = CInt(200)

    min_x = CFloat(-2 * pi)
    max_x = CFloat(2 * pi)
    min_y = CFloat(-1.5 * pi)
    max_y = CFloat(1.5 * pi)

    xs = Array
    ys = Array
    zs = Array

    minz = Float
    maxz = Float

    model_changed = Event

    def __init__(self, *args, **kwargs):
        super(Model, self).__init__(*args, **kwargs)
        self.compute_model()

    def compute_model(self):
        # The xs and ys used for the image plot range need to be the
        # edges of the cells.
        self.xs = linspace(self.min_x, self.max_x, self.npts_x + 1)
        self.ys = linspace(self.min_y, self.max_y, self.npts_y + 1)

        # The grid of points at which we will evaluate the 2D function
        # is located at cell centers, so use halfsteps from the
        # min/max values (which are edges)
        xstep = (self.max_x - self.min_x) / self.npts_x
        #ystep = (self.max_y - self.min_y) / self.npts_y
        gridx = linspace(self.min_x + xstep / 2, self.max_x - xstep / 2,
                         self.npts_x)
        gridy = linspace(self.min_y + xstep / 2, self.max_y - xstep / 2,
                         self.npts_y)
        x, y = meshgrid(gridx, gridy)
        try:
            d = dict(x=x, y=y)
            exec "from scipy import *" in d
            exec "from scipy.special import *" in d
            self.zs = eval(self.function, d)
            self.minz = nanmin(self.zs)
            self.maxz = nanmax(self.zs)
            self.model_changed = True
            self._function = self.function
        except:
            self.set(function=self._function, trait_change_notify=False)

    def _anytrait_changed(self, name, value):
        if name in [
                'function', 'npts_x', 'npts_y', 'min_x', 'max_x', 'min_y',
                'max_y'
        ]:
            self.compute_model()
示例#29
0
    values = List()

    button_enabled = Bool(True)

    traits_view = View(
        Item("play_button", style="simple"),
        Item("play_button", style="custom"),
        Item("play_button", style="readonly"),
        Item("play_button", style="text"),
    )


simple_view = View(
    UItem("play_button", editor=ButtonEditor(label_value="play_button_label")),
    Item("play_button_label"),
    resizable=True,
)


custom_view = View(
    UItem("play_button", editor=ButtonEditor(label_value="play_button_label")),
    Item("play_button_label"),
    resizable=True,
    style="custom",
)


@requires_toolkit([ToolkitName.qt, ToolkitName.wx])
class TestButtonEditor(BaseTestMixin, unittest.TestCase, UnittestTools):
示例#30
0
class Workflow(HasStrictTraits):

    workflow = List(WorkflowItem)
    selected = Instance(WorkflowItem)
    version = Str

    modified = Bool
    debug = Bool

    #     default_scale = util.ScaleEnum

    # a view for the entire workflow's list of operations
    operations_traits = View(Item('workflow',
                                  editor=VerticalNotebookEditor(
                                      view='operation_traits',
                                      page_name='.name',
                                      page_description='.friendly_id',
                                      page_icon='.icon',
                                      delete=True,
                                      page_deletable='.deletable',
                                      selected='selected',
                                      multiple_open=False),
                                  show_label=False),
                             scrollable=True)

    # a view showing the selected workflow item's current view
    selected_view_traits = View(Item(
        'selected',
        editor=InstanceEditor(view='current_view_traits'),
        style='custom',
        show_label=False),
                                Spring(),
                                Item('apply_calls',
                                     style='readonly',
                                     visible_when='debug'),
                                Item('plot_calls',
                                     style='readonly',
                                     visible_when='debug'),
                                kind='panel',
                                scrollable=True)

    # the view for the center pane
    plot_view = View(
        Item('selected',
             editor=InstanceEditor(view='current_plot_view'),
             style='custom',
             show_label=False))

    recv_thread = Instance(threading.Thread)
    send_thread = Instance(threading.Thread)
    log_thread = Instance(threading.Thread)
    remote_process_thread = Instance(threading.Thread)
    message_q = Instance(Queue, ())

    # the Pipe connection object to pass to the matplotlib canvas
    child_matplotlib_conn = Any

    # count the number of times the remote process calls apply() or plot().
    # useful for debugging
    apply_calls = Int(0)
    plot_calls = Int(0)

    def __init__(self, remote_connection, **kwargs):
        super(Workflow, self).__init__(**kwargs)

        child_workflow_conn, self.child_matplotlib_conn, log_q = remote_connection

        self.recv_thread = threading.Thread(target=self.recv_main,
                                            name="local workflow recv",
                                            args=[child_workflow_conn])
        self.recv_thread.daemon = True
        self.recv_thread.start()

        self.send_thread = threading.Thread(target=self.send_main,
                                            name="local workflow send",
                                            args=[child_workflow_conn])
        self.send_thread.daemon = True
        self.send_thread.start()

        self.log_thread = threading.Thread(target=self.log_main,
                                           name="log listener thread",
                                           args=[log_q])
        self.log_thread.daemon = True
        self.log_thread.start()

    def recv_main(self, child_conn):
        while child_conn.poll(None):
            try:
                (msg, payload) = child_conn.recv()
            except EOFError:
                return

            logging.debug("LocalWorkflow.recv_main :: {}".format(msg))

            try:
                if msg == Msg.UPDATE_WI:
                    (idx, name, new) = payload
                    wi = self.workflow[idx]

                    if not wi.trait(name).status:
                        raise RuntimeError(
                            "Tried to set a local non-status wi trait")

                    with wi.lock:
                        wi.trait_set(**{name: new})

                elif msg == Msg.UPDATE_OP:
                    (idx, name, new) = payload
                    wi = self.workflow[idx]

                    if not wi.operation.trait(name).status:
                        raise RuntimeError(
                            "Tried to set a local non-status trait")

                    with wi.lock:
                        wi.operation.trait_set(**{name: new})

                elif msg == Msg.UPDATE_VIEW:
                    (idx, view_id, name, new) = payload
                    wi = self.workflow[idx]
                    view = next((x for x in wi.views if x.id == view_id))

                    if not view.trait(name).status:
                        raise RuntimeError(
                            "Tried to set a local non-status trait")

                    with wi.lock:
                        view.trait_set(**{name: new})

                elif msg == Msg.APPLY_CALLED:
                    self.apply_calls = payload

                elif msg == Msg.PLOT_CALLED:
                    self.plot_calls = payload

                else:
                    raise RuntimeError("Bad message from remote")

            except Exception:
                log_exception()

    def send_main(self, child_conn):
        try:
            while True:
                msg = self.message_q.get()
                child_conn.send(msg)
        except Exception:
            log_exception()

    def log_main(self, log_q):
        # from http://plumberjack.blogspot.com/2010/09/using-logging-with-multiprocessing.html

        while True:
            try:
                record = log_q.get()
                if record is None:  # We send this as a sentinel to tell the listener to quit.
                    break
                logger = logging.getLogger(record.name)
                logger.handle(
                    record)  # No level or filter logic applied - just do it!
            except (KeyboardInterrupt, SystemExit):
                raise
            except:
                print('Whoops! Problem:', file=sys.stderr)
                traceback.print_exc(file=sys.stderr)

    def shutdown_remote_process(self):
        self.message_q.put((Msg.SHUTDOWN, None))

    @on_trait_change('workflow')
    def _on_new_workflow(self, obj, name, old, new):
        logging.debug("LocalWorkflow._on_new_workflow")

        self.selected = None

        # send the new workflow to the child process
        self.message_q.put((Msg.NEW_WORKFLOW, self.workflow))

    @on_trait_change('workflow_items')
    def _on_workflow_add_remove_items(self, event):
        logging.debug(
            "LocalWorkflow._on_workflow_add_remove_items :: {}".format(
                (event.index, event.removed, event.added)))

        idx = event.index
        self.modified = True

        # remove deleted items from the linked list
        if event.removed:
            assert len(event.removed) == 1
            removed = event.removed[0]
            if removed.previous_wi:
                removed.previous_wi.next_wi = removed.next_wi

            if removed.next_wi:
                removed.next_wi.previous_wi = removed.previous_wi

            self.message_q.put((Msg.REMOVE_ITEMS, idx))

            if removed == self.selected:
                self.selected = None

        # add new items to the linked list
        if event.added:
            assert len(event.added) == 1

            if idx > 0:
                # populate the new wi with metadata from the old one
                self.workflow[idx].channels = list(self.workflow[idx -
                                                                 1].channels)
                self.workflow[idx].conditions = dict(
                    self.workflow[idx - 1].conditions)
                self.workflow[idx].metadata = dict(self.workflow[idx -
                                                                 1].metadata)
                self.workflow[idx].statistics = dict(
                    self.workflow[idx - 1].statistics)

                self.workflow[idx - 1].next_wi = self.workflow[idx]
                self.workflow[idx].previous_wi = self.workflow[idx - 1]

            if idx < len(self.workflow) - 1:
                self.workflow[idx].next_wi = self.workflow[idx + 1]
                self.workflow[idx + 1].previous_wi = self.workflow[idx]

            self.message_q.put((Msg.ADD_ITEMS, (idx, event.added[0])))

    @on_trait_change('selected')
    def _on_selected_changed(self, obj, name, old, new):
        logging.debug("LocalWorkflow._on_selected_changed :: {}".format(
            (obj, name, old, new)))

        if new is None:
            idx = -1
        else:
            idx = self.workflow.index(new)

        self.message_q.put((Msg.SELECT, idx))

    @on_trait_change('workflow:operation:+')
    def _operation_changed(self, obj, name, old, new):
        logging.debug("LocalWorkflow._operation_changed :: {}".format(
            (obj, name, old, new)))

        if not obj.trait(name).transient and not obj.trait(name).status:
            wi = next((x for x in self.workflow if x.operation == obj))
            idx = self.workflow.index(wi)
            self.message_q.put((Msg.UPDATE_OP, (idx, name, new)))
            self.modified = True

    @on_trait_change('workflow:operation:changed')
    def _operation_changed_event(self, obj, _, new):
        logging.debug("LocalWorkflow._operation_changed_event:: {}".format(
            (obj, new)))

        (_, (name, new)) = new

        wi = next((x for x in self.workflow if x.operation == obj))
        idx = self.workflow.index(wi)
        self.message_q.put((Msg.UPDATE_OP, (idx, name, new)))
        self.modified = True

    @on_trait_change('workflow:views:+')
    def _view_changed(self, obj, name, old, new):
        logging.debug("LocalWorkflow._view_changed :: {}".format(
            (obj, name, old, new)))

        if not obj.trait(name).transient and not obj.trait(name).status:
            wi = next((x for x in self.workflow if obj in x.views))
            idx = self.workflow.index(wi)
            self.message_q.put((Msg.UPDATE_VIEW, (idx, obj.id, name, new)))
            self.modified = True

    @on_trait_change('workflow:views:changed')
    def _view_changed_event(self, obj, _, new):
        logging.debug("LocalWorkflow._view_changed_event:: {}".format(
            (obj, new)))

        (_, (_, name, new)) = new

        wi = next((x for x in self.workflow if obj in x.views))
        idx = self.workflow.index(wi)
        self.message_q.put((Msg.UPDATE_VIEW, (idx, obj.id, name, new)))
        self.modified = True

    @on_trait_change('workflow:current_view')
    def _on_current_view_changed(self, obj, name, old, new):
        logging.debug("LocalWorkflow._on_current_view_changed :: {}".format(
            (obj, name, old, new)))

        idx = self.workflow.index(obj)
        view = obj.current_view
        self.message_q.put((Msg.CHANGE_CURRENT_VIEW, (idx, view)))

    @on_trait_change('workflow:current_plot')
    def _on_current_plot_changed(self, obj, name, old, new):
        logging.debug("LocalWorkflow._on_current_plot_changed :: {}".format(
            (obj, name, old, new)))

        idx = self.workflow.index(obj)
        plot = obj.current_plot
        self.message_q.put((Msg.CHANGE_CURRENT_PLOT, (idx, plot)))

    @on_trait_change('workflow:operation:do_estimate')
    def _on_estimate(self, obj, name, old, new):
        logging.debug("LocalWorkflow._on_estimate :: {}".format(
            (obj, name, old, new)))

        wi = next((x for x in self.workflow if x.operation == obj))
        idx = self.workflow.index(wi)
        self.message_q.put((Msg.ESTIMATE, idx))