Exemple #1
0
class ShearCrack(BMCSLeafNode, Vis2D):
    '''Class representing the geometry of a crack using
    a piecewise linear representation
    '''

    node_name = 'shear crack geometry'

    x = tr.Array(np.float_,
                 value=[0.2, 0.15, 0.1], GEO=True)
    y = tr.Array(np.float_,
                 value=[0.0, 0.15, 0.2], GEO=True)

    viz2d_classes = {
        'shear_crack': ShearCrackViz2D
    }

    tree_view = View(
        HGroup(
            Include('actions')
        )
    )
class short_rate(trapi.HasTraits):
    name = trapi.Str
    rate = trapi.Float
    time_list = trapi.Array(dtype=np.float, shape=(1, 5))
    disc_list = trapi.Array(dtype=np.float, shape=(1, 5))
    update = trapi.Button

    def _update_fired(self):
        self.disc_list = np.exp(-self.rate * self.time_list)

    v = trui.View(trui.Group(trui.Item(name='name'),
                             trui.Item(name='rate'),
                             trui.Item(name='time_list',
                                       label='Insert Time List Here'),
                             trui.Item('update', show_label=False),
                             trui.Item(name='disc_list',
                                       label='Press Update for Factors'),
                             show_border=True,
                             label='Calculate Discount Factors'),
                  buttons=[trui.OKButton, trui.CancelButton],
                  resizable=True)
class TimeFunction(bu.InteractiveModel):
    name = 'Time function'
    n_i = bu.Int(0,
                 input=True,
                 desc='number of data points between data points')
    '''Number of steps between two values
    '''

    values = tr.Array(np.float_, value=[0, 1])
    '''Values of the time function.
    '''

    ipw_view = bu.View(bu.Item('n_i', latex=r'n_i', minmax=(0, 100)))

    t_step = tr.Property(tr.Float, depends_on='+input')
    '''Step size.
    '''
    @tr.cached_property
    def _get_t_step(self):
        n_values = len(self.values)
        return (self.n_i + 1) * n_values

    tf = tr.Property(depends_on='data_points')

    def _get_tf(self):
        n_values = len(self.values)
        t_values = np.linspace(0, 1, n_values)
        return interpolate.interp1d(t_values, self.values)

    def __call__(self, arg):
        return self.tf(arg)

    def update_plot(self, ax):
        n_values = len(self.values)
        t = np.linspace(0, 1, (self.n_i) * (n_values - 1) + n_values)
        v = self.tf(t)
        ax.plot(t, v, '-o')
Exemple #4
0
class DataAxis(t.HasTraits):
    name = t.Str()
    units = t.Str()
    scale = t.Float()
    offset = t.Float()
    size = t.CInt()
    low_value = t.Float()
    high_value = t.Float()
    value = t.Range('low_value', 'high_value')
    low_index = t.Int(0)
    high_index = t.Int()
    slice = t.Instance(slice)
    navigate = t.Bool(t.Undefined)
    index = t.Range('low_index', 'high_index')
    axis = t.Array()
    continuous_value = t.Bool(False)

    def __init__(self,
                 size,
                 index_in_array=None,
                 name=t.Undefined,
                 scale=1.,
                 offset=0.,
                 units=t.Undefined,
                 navigate=t.Undefined):
        super(DataAxis, self).__init__()
        self.name = name
        self.units = units
        self.scale = scale
        self.offset = offset
        self.size = size
        self.high_index = self.size - 1
        self.low_index = 0
        self.index = 0
        self.update_axis()
        self.navigate = navigate
        self.axes_manager = None
        self.on_trait_change(self.update_axis, ['scale', 'offset', 'size'])
        self.on_trait_change(self.update_value, 'index')
        self.on_trait_change(self.set_index_from_value, 'value')
        self.on_trait_change(self._update_slice, 'navigate')
        self.on_trait_change(self.update_index_bounds, 'size')
        # The slice must be updated even if the default value did not
        # change to correctly set its value.
        self._update_slice(self.navigate)

    @property
    def index_in_array(self):
        if self.axes_manager is not None:
            return self.axes_manager._axes.index(self)
        else:
            raise AttributeError(
                "This DataAxis does not belong to an AxesManager"
                " and therefore its index_in_array attribute "
                " is not defined")

    @property
    def index_in_axes_manager(self):
        if self.axes_manager is not None:
            return self.axes_manager._get_axes_in_natural_order().\
                   index(self)
        else:
            raise AttributeError(
                "This DataAxis does not belong to an AxesManager"
                " and therefore its index_in_array attribute "
                " is not defined")

    def _get_positive_index(self, index):
        if index < 0:
            index = self.size + index
            if index < 0:
                raise IndexError("index out of bounds")
        return index

    def _get_index(self, value):
        if isinstance(value, float):
            return self.value2index(value)
        else:
            return value

    def _slice_me(self, slice_):
        """Returns a slice to slice the corresponding data axis and 
        change the offset and scale of the DataAxis acordingly.
        
        Parameters
        ----------
        slice_ : {float, int, slice}
        
        Returns
        -------
        my_slice : slice
        
        """
        i2v = self.index2value
        v2i = self.value2index

        if isinstance(slice_, slice):
            start = slice_.start
            stop = slice_.stop
            step = slice_.step
        else:
            if isinstance(slice_, float):
                start = v2i(slice_)
            else:
                start = self._get_positive_index(slice_)
            stop = start + 1
            step = None

        if isinstance(step, float):
            step = int(round(step / self.scale))
        if isinstance(start, float):
            try:
                start = v2i(start)
            except ValueError:
                # The value is below the axis limits
                # we slice from the start.
                start = None
        if isinstance(stop, float):
            try:
                stop = v2i(stop)
            except ValueError:
                # The value is above the axes limits
                # we slice up to the end.
                stop = None

        if step == 0:
            raise ValueError("slice step cannot be zero")

        my_slice = slice(start, stop, step)

        if start is None:
            if step > 0 or step is None:
                start = 0
            else:
                start = self.size - 1
        self.offset = i2v(start)
        if step is not None:
            self.scale *= step

        return my_slice

    def _get_name(self):
        name = (self.name if self.name is not t.Undefined else
                ("Unnamed " + ordinal(self.index_in_axes_manager)))
        return name

    def __repr__(self):
        text = '<%s axis, size: %i' % (
            self._get_name(),
            self.size,
        )
        if self.navigate is True:
            text += ", index: %i" % self.index
        text += ">"
        return text

    def __str__(self):
        return self._get_name() + " axis"

    def connect(self, f, trait='value'):
        self.on_trait_change(f, trait)

    def disconnect(self, f, trait='value'):
        self.on_trait_change(f, trait, remove=True)

    def update_index_bounds(self):
        self.high_index = self.size - 1

    def update_axis(self):
        self.axis = generate_axis(self.offset, self.scale, self.size)
        if len(self.axis) != 0:
            self.low_value, self.high_value = (self.axis.min(),
                                               self.axis.max())

    def _update_slice(self, value):
        if value is False:
            self.slice = slice(None)
        else:
            self.slice = None

    def get_axis_dictionary(self):
        adict = {
            'name': self.name,
            'scale': self.scale,
            'offset': self.offset,
            'size': self.size,
            'units': self.units,
            'index_in_array': self.index_in_array,
            'navigate': self.navigate
        }
        return adict

    def copy(self):
        return DataAxis(**self.get_axis_dictionary())

    def update_value(self):
        self.value = self.axis[self.index]

    def value2index(self, value, rounding=round):
        """Return the closest index to the given value if between the limit.

        Parameters
        ----------
        value : float

        Returns
        -------
        int

        Raises
        ------
        ValueError if value is out of the axis limits.

        """
        if value is None:
            return None
        else:
            index = int(rounding((value - self.offset) / self.scale))
            if self.size > index >= 0:
                return index
            else:
                raise ValueError("The value is out of the axis limits")

    def index2value(self, index):
        return self.axis[index]

    def set_index_from_value(self, value):
        self.index = self.value2index(value)
        # If the value is above the limits we must correct the value
        if self.continuous_value is False:
            self.value = self.index2value(self.index)

    def calibrate(self, value_tuple, index_tuple, modify_calibration=True):
        scale = (value_tuple[1] - value_tuple[0]) /\
        (index_tuple[1] - index_tuple[0])
        offset = value_tuple[0] - scale * index_tuple[0]
        if modify_calibration is True:
            self.offset = offset
            self.scale = scale
        else:
            return offset, scale

    traits_view = \
    tui.View(
        tui.Group(
            tui.Group(
                tui.Item(name='name'),
                tui.Item(name='size', style='readonly'),
                tui.Item(name='index_in_array', style='readonly'),
                tui.Item(name='index'),
                tui.Item(name='value', style='readonly'),
                tui.Item(name='units'),
                tui.Item(name='navigate', label = 'navigate'),
            show_border = True,),
            tui.Group(
                tui.Item(name='scale'),
                tui.Item(name='offset'),
            label = 'Calibration',
            show_border = True,),
        label = "Data Axis properties",
        show_border = True,),
    title = 'Axis configuration',
    )
Exemple #5
0
class ShmTrackingInterface(T.HasStrictTraits):

    dwi_images = T.DelegatesTo('all_inputs')
    all_inputs = T.Instance(InputData, args=())
    min_signal = T.DelegatesTo('all_inputs')
    seed_roi = nifti_file
    seed_density = T.Array(dtype='int', shape=(3, ), value=[1, 1, 1])

    smoothing_kernel_type = T.Enum(None, all_kernels.keys())
    smoothing_kernel = T.Instance(T.HasTraits)

    @T.on_trait_change('smoothing_kernel_type')
    def set_smoothing_kernel(self):
        if self.smoothing_kernel_type is not None:
            kernel_factory = all_kernels[self.smoothing_kernel_type]
            self.smoothing_kernel = kernel_factory()
        else:
            self.smoothing_kernel = None

    interpolator = T.Enum('NearestNeighbor', all_interpolators.keys())
    model_type = T.Enum('SlowAdcOpdf', all_shmodels.keys())
    sh_order = T.Int(4)
    Lambda = T.Float(0, desc="Smoothing on the odf")
    sphere_coverage = T.Int(5)
    min_peak_spacing = T.Range(0., 1, np.sqrt(.5), desc="as a dot product")
    min_relative_peak = T.Range(0., 1, .25)

    probabilistic = T.Bool(False, label='Probabilistic (Residual Bootstrap)')
    bootstrap_input = T.Bool(False)
    bootstrap_vector = T.Array(dtype='int', value=[])

    # integrator = Enum('Boundry', all_integrators.keys())
    seed_largest_peak = T.Bool(False,
                               desc="Ignore sub-peaks and start follow "
                               "the largest peak at each seed")
    start_direction = T.Array(dtype='float',
                              shape=(3, ),
                              value=[0, 0, 1],
                              desc="Prefered direction from seeds when "
                              "multiple directions are available. "
                              "(Mostly) doesn't matter when 'seed "
                              "largest peak' and 'track two directions' "
                              "are both True",
                              label="Start direction (RAS)")
    track_two_directions = T.Bool(False)
    fa_threshold = T.Float(1.0)
    max_turn_angle = T.Range(0., 90, 0)

    stop_on_target = T.Bool(False)
    targets = T.List(nifti_file, [])

    # will be set later
    voxel_size = T.Array(dtype='float', shape=(3, ))
    affine = T.Array(dtype='float', shape=(4, 4))
    shape = T.Tuple((0, 0, 0))

    # set for io
    save_streamlines_to = T.File('')
    save_counts_to = nifti_file

    # io methods
    def save_streamlines(self, streamlines, save_streamlines_to):
        trk_hdr = empty_header()
        voxel_order = orientation_to_string(nib.io_orientation(self.affine))
        trk_hdr['voxel_order'] = voxel_order
        trk_hdr['voxel_size'] = self.voxel_size
        trk_hdr['vox_to_ras'] = self.affine
        trk_hdr['dim'] = self.shape
        trk_tracks = ((ii, None, None) for ii in streamlines)
        write(save_streamlines_to, trk_tracks, trk_hdr)
        pickle.dump(self, open(save_streamlines_to + '.p', 'wb'))

    def save_counts(self, streamlines, save_counts_to):
        counts = density_map(streamlines, self.shape, self.voxel_size)
        if counts.max() < 2**15:
            counts = counts.astype('int16')
        nib.save(nib.Nifti1Image(counts, self.affine), save_counts_to)

    # tracking methods
    def track_shm(self, debug=False):
        if self.sphere_coverage > 7 or self.sphere_coverage < 1:
            raise ValueError("sphere coverage must be between 1 and 7")
        verts, edges, faces = create_half_unit_sphere(self.sphere_coverage)
        verts, pot = disperse_charges(verts, 10, .3)

        data, voxel_size, affine, fa, bvec, bval = self.all_inputs.read_data()
        self.voxel_size = voxel_size
        self.affine = affine
        self.shape = fa.shape

        model_type = all_shmodels[self.model_type]
        model = model_type(self.sh_order, bval, bvec, self.Lambda)
        model.set_sampling_points(verts, edges)

        data = np.asarray(data, dtype='float', order='C')
        if self.smoothing_kernel is not None:
            kernel = self.smoothing_kernel.get_kernel()
            convolve(data, kernel, out=data)

        normalize_data(data, bval, self.min_signal, out=data)
        dmin = data.min()
        data = data[..., lazy_index(bval > 0)]
        if self.bootstrap_input:
            if self.bootstrap_vector.size == 0:
                n = data.shape[-1]
                self.bootstrap_vector = np.random.randint(n, size=n)
            H = hat(model.B)
            R = lcr_matrix(H)
            data = bootstrap_data_array(data, H, R, self.bootstrap_vector)
            data.clip(dmin, out=data)

        mask = fa > self.fa_threshold
        targets = [read_roi(tgt, shape=self.shape) for tgt in self.targets]
        if self.stop_on_target:
            for target_mask in targets:
                mask = mask & ~target_mask

        seed_mask = read_roi(self.seed_roi, shape=self.shape)
        seeds = seeds_from_mask(seed_mask, self.seed_density, voxel_size)

        if ((self.interpolator == 'NearestNeighbor' and not self.probabilistic
             and not debug)):
            using_optimze = True
            peak_finder = NND_ClosestPeakSelector(model, data, mask,
                                                  voxel_size)
        else:
            using_optimze = False
            interpolator_type = all_interpolators[self.interpolator]
            interpolator = interpolator_type(data, voxel_size, mask)
            peak_finder = ClosestPeakSelector(model, interpolator)

        # Set peak_finder parameters for start steps
        peak_finder.angle_limit = 90
        model.peak_spacing = self.min_peak_spacing
        if self.seed_largest_peak:
            model.min_relative_peak = 1
        else:
            model.min_relative_peak = self.min_relative_peak

        data_ornt = nib.io_orientation(self.affine)
        best_start = reorient_vectors(self.start_direction, 'ras', data_ornt)
        start_steps = closest_start(seeds, peak_finder, best_start)

        if self.probabilistic:
            interpolator = ResidualBootstrapWrapper(interpolator,
                                                    model.B,
                                                    min_signal=dmin)
            peak_finder = ClosestPeakSelector(model, interpolator)
        elif using_optimze and self.seed_largest_peak:
            peak_finder.reset_cache()

        # Reset peak_finder parameters for tracking
        peak_finder.angle_limit = self.max_turn_angle
        model.peak_spacing = self.min_peak_spacing
        model.min_relative_peak = self.min_relative_peak

        integrator = BoundryIntegrator(voxel_size, overstep=.1)
        streamlines = generate_streamlines(peak_finder, integrator, seeds,
                                           start_steps)
        if self.track_two_directions:
            start_steps = -start_steps
            streamlinesB = generate_streamlines(peak_finder, integrator, seeds,
                                                start_steps)
            streamlines = merge_streamlines(streamlines, streamlinesB)

        for target_mask in targets:
            streamlines = target(streamlines, target_mask, voxel_size)

        return streamlines
Exemple #6
0
class FETS2DMITC(FETSEval):
    r'''MITC3 shell finite element:
        See https://www.sesamx.io/blog/standard_linear_triangular_shell_element/
        See http://dx.doi.org/10.1016/j.compstruc.2014.02.005
    '''

    # vtk_r = tr.Array(np.float_, value=[[1, 0, 0], [0, 1, 0], [0, 0, 1]])
    # vtk_cells = [[0, 1, 2]]
    # vtk_cell_types = 'Triangle'
    # vtk_cell = [0, 1, 2]
    # vtk_cell_type = 'Triangle'
    # vtk_expand_operator = tr.Array(np.float_, value=DELTA23_ab)

    # =========================================================================
    # Surface integrals using numerical integration
    # =========================================================================
    # j is gauss point index, p is point coords in natural coords (zeta_1, zeta_2, zeta_3)
    eta_jp = tr.Array('float_')
    r'''Integration points within a triangle.
    '''
    def _eta_jp_default(self):
        # We applay the 7-point Gauss integration to integrate exactly on the plane defined by rr and ss
        # [r, s, t] at each Gauss point (r, s, t) are natural coords in the shell element r,s in plane
        # and t along thickness
        # 2 Gauss points along thickness t
        # 7 Gauss points on the plane of the element
        return np.array(
            [[1. / 3., 1. / 3., 1. / 3.]], dtype='f'
        )  # should be return np.array([[1. / 3., 1. / 3., 0]], dtype='f')

    w_m = tr.Array('float_')
    r'''Weight factors for numerical integration.'''

    def _w_m_default(self):
        print('w_m called!!')
        return np.array([1], dtype='f')

    # TODO, different node thickness in each node according to the original
    #  implementation can be easily integrated, but here the same thickness
    #  is used for simplicity.
    a = tr.Float(1.0, label='thickness')

    n_m = tr.Property(depends_on='w_m')
    r'''Number of integration points.'''

    @tr.cached_property
    def _get_n_m(self):
        return len(self.w_m)

    n_nodal_dofs = tr.Int(5)

    dh_imr = tr.Property(depends_on='eta_jp')
    r'''Derivatives of the shape functions in the integration points.'''

    @tr.cached_property
    def _get_dh_imr(self):
        # Same for all Gauss points
        dh_ri = np.array(
            [
                [1, 0, -1],  # dh1/d_r, dh2/d_r, dh3/d_r
                [0, 1, -1],  # dh1/d_s, dh2/d_s, dh3/d_s
                [0, 0, 0]
            ],  # dh1/d_t, dh2/d_t, dh3/d_t
            dtype=np.float_)

        dh_mri = np.tile(dh_ri, (self.n_m, 1, 1))

        # dh_mri = np.flip(dh_mri, 2)
        print('dh_imr called!')
        return np.einsum('mri->imr', dh_mri)

    dht_imr = tr.Property(depends_on='eta_jp')
    r'''Derivatives of the (shape functions * t) in the integration points.
    '''

    @tr.cached_property
    def _get_dht_imr(self):
        # m: gauss points, r: r, s, t, and i: h1, h2, h3
        eta_jp = self.eta_jp
        dht_mri = np.array(
            [
                [
                    [t, 0, -t],  # (t*dh1)/d_r, (t*dh2)/d_r, (t*dh3)/d_r
                    [0, t, -t],  # (t*dh1)/d_s, (t*dh2)/d_s, (t*dh3)/d_s
                    [r, s, 1 - r - s]
                ]  # (t*dh1)/d_t, (t*dh2)/d_t, (t*dh3)/d_t
                for r, s, t in zip(eta_jp[:, 0], eta_jp[:, 1], eta_jp[:, 2])
            ],
            dtype=np.float_)

        # dht_mri = np.flip(dht_mri, 2)
        return np.einsum('mri->imr', dht_mri)
Exemple #7
0
class ModelInteract(tr.HasTraits):

    models = tr.List([
    ])

    py_vars = tr.List(tr.Str)
    map_py2sp = tr.Dict

    d = tr.Float(0.03, GEO=True)
    h = tr.Float(0.8, GEO=True)

    # define the free parameters as traits with default, min and max values
    w_max = tr.Float(1.0)
    t = tr.Float(0.0001, min=1e-5, max=1)
    tau = tr.Float(0.5, interact=True)
    L_b = tr.Float(200, interact=True)
    E_f = tr.Float(100000, interact=True)
    A_f = tr.Float(20, interact=True)
    p = tr.Float(40, interact=True)
    E_m = tr.Float(26000, interact=True)
    A_m = tr.Float(100, interact=True)

    n_steps = tr.Int(50)

    sliders = tr.Property

    @tr.cached_property
    def _get_sliders(self):
        traits = self.traits(interact=True)
        vals = self.trait_get(interact=True)
        slider_names = self.py_vars[1:]
        max_vals = {name: getattr(traits, 'max', vals[name] * 2)
                    for name in slider_names}
        t_slider = {'t': ipw.FloatSlider(1e-5, min=1e-5, max=1, step=0.05,
                                         description=r'\(t\)')}
        param_sliders = {name: ipw.FloatSlider(value=vals[name],
                                               min=1e-5,
                                               max=max_vals[name],
                                               step=max_vals[name] /
                                               self.n_steps,
                                               description=r'\(%s\)' % self.map_py2sp[name].name)
                         for (name, _) in traits.items()
                         }
        t_slider.update(param_sliders)
        return t_slider

    w_range = tr.Property(tr.Array(np.float_), depends_on='w_max')

    @tr.cached_property
    def _get_w_range(self):
        return np.linspace(0, self.w_max, 50)

    x_range = tr.Property(tr.Array(np.float_), depends_on='L_b')

    @tr.cached_property
    def _get_x_range(self):
        return np.linspace(-self.L_b, 0, 100)

    model_plots = tr.Property(tr.List)

    @tr.cached_property
    def _get_model_plots(self):
        return [PlotModel(itr=self, model=m) for m in self.models]

    def init_fields(self):
        self.fig, ((self.ax_po, self.ax_u), (self.ax_eps, self.ax_tau)) = plt.subplots(
            2, 2, figsize=(9, 5), tight_layout=True
        )
        values = self.trait_get(interact=True)
        params = list(values[py_var] for py_var in self.py_vars[1:])
        for mp in self.model_plots:
            mp.init_fields(*params)
            mp.init_Pw(*params)
        self.ax_po.set_xlim(0, self.w_max * 1.05)

    def clear_fields(self):
        clear_plot(self.ax_po, self.ax_u, self.ax_eps, self.ax_tau)

    def update_fields(self, t, **values):
        w = t * self.w_max
        self.trait_set(**values)
        params = list(values[py_var] for py_var in self.py_vars[1:])
        L_b = self.L_b
        self.clear_fields()
        for mp in self.model_plots:
            mp.update_fields(w, *params)
            mp.update_Pw(w, *params)

        P_max = np.max(np.array([m.P_max for m in self.model_plots]))
        self.ax_po.set_ylim(0, P_max * 1.05)
        self.ax_po.set_xlim(0, self.w_max * 1.05)
        u_min = np.min(np.array([m.u_min for m in self.model_plots]))
        u_max = np.max(np.array([m.u_max for m in self.model_plots] + [1]))
        self.ax_u.set_ylim(u_min, u_max * 1.1)
        self.ax_u.set_xlim(xmin=-1.05 * L_b, xmax=0.05 * L_b)
        eps_min = np.min(np.array([m.eps_min for m in self.model_plots]))
        eps_max = np.max(np.array([m.eps_max for m in self.model_plots]))
        self.ax_eps.set_ylim(eps_min, eps_max * 1.1)
        self.ax_eps.set_xlim(xmin=-1.05 * L_b, xmax=0.05 * L_b)
        self.ax_tau.set_ylim(0, self.tau * 1.1)
        self.ax_tau.set_xlim(xmin=-1.05 * L_b, xmax=0.05 * L_b)
        self.fig.canvas.draw_idle()

    def set_w_max_fields(self, w_max):
        self.w_max = w_max
        values = {name: slider.value for name, slider in self.sliders.items()}
        self.update_fields(**values)

    def interact_fields(self):
        self.init_fields()
        self.on_w_max_change = self.update_fields
        sliders = self.sliders
        out = ipw.interactive_output(self.update_fields, sliders)
        self.widget_layout(out)

    #=========================================================================
    # Interaction on the pull-out curve spatial plot
    #=========================================================================
    def init_geometry(self):
        self.fig, (self.ax_po, self.ax_geo) = plt.subplots(
            1, 2, figsize=(8, 3.4))  # , tight_layout=True)
        values = self.trait_get(interact=True)
        params = list(values[py_var] for py_var in self.py_vars[1:])
        h = self.h
        x_C = np.array([[-1, 0], [0, 0], [0, h], [-1, h]], dtype=np.float_)
        self.line_C, = self.ax_geo.fill(*x_C.T, color='gray', alpha=0.3)
        for mp in self.model_plots:
            mp.line_aw, = self.ax_geo.fill([], [], color='white', alpha=1)
            mp.line_F, = self.ax_geo.fill([], [], color='black', alpha=0.8)
            mp.line_F0, = self.ax_geo.fill([], [], color='white', alpha=1)
            mp.init_Pw(*params)
        self.ax_po.set_xlim(0, self.w_max * 1.05)

    def clear_geometry(self):
        clear_plot(self.ax_po, self.ax_geo)

    def update_geometry(self, t, **values):
        w = t * self.w_max
        self.clear_geometry()
        self.trait_set(**values)
        params = list(values[py_var] for py_var in self.py_vars[1:])
        h = self.h
        d = self.d
        L_b = self.L_b
        f_top = h / 2 + d / 2
        f_bot = h / 2 - d / 2
        self.ax_geo.set_xlim(
            xmin=-1.05 * L_b, xmax=max(0.05 * L_b, 1.1 * self.w_max))
        x_C = np.array([[-L_b, 0], [0, 0], [0, h], [-L_b, h]], dtype=np.float_)
        self.line_C.set_xy(x_C)
        for mp in self.model_plots:
            a_val = mp.model.get_aw_pull(w, *params)
            width = d * 0.5
            x_a = np.array([[a_val, f_bot - width], [0, f_bot - width],
                            [0, f_top + width], [a_val, f_top + width]],
                           dtype=np.float_)
            mp.line_aw.set_xy(x_a)

            w_L_b = mp.model.get_w_L_b(w, *params)
            x_F = np.array([[-L_b + w_L_b, f_bot], [w, f_bot],
                            [w, f_top], [-L_b + w_L_b, f_top]], dtype=np.float_)
            mp.line_F.set_xy(x_F)
            x_F0 = np.array([[-L_b, f_bot], [-L_b + w_L_b, f_bot],
                             [-L_b + w_L_b, f_top], [-L_b, f_top]], dtype=np.float_)
            mp.line_F0.set_xy(x_F0)

            mp.update_Pw(w, *params)

        P_max = np.max(np.array([mp.P_max for mp in self.model_plots]))
        self.ax_po.set_ylim(0, P_max * 1.1)
        self.ax_po.set_xlim(0, self.w_max * 1.05)
        self.fig.canvas.draw_idle()

    def set_w_max(self, w_max):
        self.w_max = w_max
        values = {name: slider.value for name, slider in self.sliders.items()}
        self.on_w_max_change(**values)

    on_w_max_change = tr.Callable

    def interact_geometry(self):
        self.init_geometry()
        self.on_w_max_change = self.update_geometry
        sliders = self.sliders
        out = ipw.interactive_output(self.update_geometry, sliders)
        self.widget_layout(out)

    def widget_layout(self, out):
        sliders = self.sliders
        layout = ipw.Layout(grid_template_columns='1fr 1fr')
        param_sliders_list = [sliders[py_var] for py_var in self.py_vars[1:]]
        t_slider = sliders['t']
        grid = ipw.GridBox(param_sliders_list, layout=layout)
        w_max_text = ipw.FloatText(
            value=self.w_max,
            description=r'w_max',
            disabled=False
        )
        out_w_max = ipw.interactive_output(self.set_w_max,
                                           {'w_max': w_max_text})

        hbox = ipw.HBox([t_slider, w_max_text])
        box = ipw.VBox([hbox, grid, out, out_w_max])
        display(box)
Exemple #8
0
class TimeLoop(tr.HasStrictTraits):

    tline = tr.Instance(TLine)
    '''Time line object specifying the start, end, time step and current time
    '''
    def _tline_default(self):
        return TLine(min=0.0, max=1.0, step=1.0)

    ts = tr.Instance(ITStepperEval)
    '''State object delivering the predictor and corrector
    '''

    bc_mngr = tr.Instance(BCondMngr, ())
    '''Boundary condition manager.
    '''

    bc_list = tr.List([])
    '''List of boundary conditions.
    '''

    def _bc_list_changed(self):
        self.bc_mngr.bcond_list = self.bc_list

    step_tolerance = tr.Float(1e-8)
    '''Time step tolerance.
    '''

    k_max = tr.Int(300)
    '''Maximum number of iterations.
    '''

    tolerance = tr.Float(1e-3)
    '''Tolerance of the residuum norm. 
    '''

    t_n1 = tr.Float(0, input=True)
    '''Target time for the next increment.
    '''

    t_n = tr.Float(0, input=True)
    '''Time of the last equilibrium state. 
    '''

    d_t = tr.Float(0, input=True)
    '''Current time increment size.
    '''

    paused = tr.Bool(False)
    restart = tr.Bool(True)
    stop = tr.Bool(False)

    def init(self):
        self.stop = False
        if self.paused:
            self.paused = False
            return
        if self.restart:
            self.tline.val = 0
            # self.setup()
            self.restart = False
        self.bc_mngr.setup(None)
        for rt in self.response_traces:
            rt.setup(self)

    algorithmic = tr.Bool(True)

    def eval(self):
        update_state = False
        K = SysMtxAssembly()
        self.bc_mngr.apply_essential(K)
        U_n = np.zeros((self.ts.mesh.n_dofs, ), dtype=np.float_)
        dU = np.copy(U_n)
        U_k = np.copy(U_n)
        F_ext = np.zeros_like(U_n)
        algorithmic = self.algorithmic
        pos_def = True

        while (self.t_n1 - self.tline.max) <= self.step_tolerance:

            print('current time %f' % self.t_n1, end=' ')
            self.d_t = self.tline.step
            k = 0
            step_flag = 'predictor'

            while k < self.k_max:

                if self.stop:
                    return U_n

                K.reset_mtx()
                K_arr, F_int, n_F_int = self.ts.get_corr_pred(
                    U_k, dU, self.t_n, self.t_n1, update_state, algorithmic)
                if update_state:
                    update_state = False

                K.sys_mtx_arrays.append(K_arr)

                F_ext[:] = 0.0
                self.bc_mngr.apply(step_flag, None, K, F_ext, self.t_n,
                                   self.t_n1)
                R = F_ext - F_int
                K.apply_constraints(R)
                if n_F_int == 0.0:
                    n_F_int = 1.0
                norm = np.linalg.norm(R, ord=None)  # / n_F_int
                if norm < self.tolerance:
                    print('converged in %d iterations' % (k + 1))
                    update_state = True
                    self.record_response(U_k, F_int, self.t_n1)
                    break
                dU, pos_def = K.solve(check_pos_def=algorithmic)
                if algorithmic and not pos_def:
                    algorithmic = False
                    print('switched to secant')
                    continue
                U_k += dU
                k += 1
                step_flag = 'corrector'

            U_n = np.copy(U_k)
            self.t_n = self.t_n1
            self.t_n1 = self.t_n + self.d_t
            self.tline.val = min(self.t_n, self.tline.max)

        return U_n

    write_dir = tr.Directory
    F_int_record = tr.List(tr.Array(np.float_))
    U_record = tr.List(tr.Array(np.float_))
    F_ext_record = tr.List(tr.Array(np.float_))
    t_record = tr.List

    response_traces = tr.List()

    def record_response(self, U_k, F_int, t):

        self.F_int_record.append(np.copy(F_int))
        self.U_record.append(np.copy(U_k))
        self.t_record.append(self.t_n1)

        for rt in self.response_traces:
            rt.update(U_k, t)
        return

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

    def get_time_idx(self, vot):
        return int(self.get_time_idx_arr(vot))
Exemple #9
0
class DataAxis(t.HasTraits):
    name = t.Str()
    units = t.Str()
    scale = t.Float()
    offset = t.Float()
    size = t.CInt()
    low_value = t.Float()
    high_value = t.Float()
    value = t.Range('low_value', 'high_value')
    low_index = t.Int(0)
    high_index = t.Int()
    slice = t.Instance(slice)
    navigate = t.Bool(t.Undefined)
    index = t.Range('low_index', 'high_index')
    axis = t.Array()
    continuous_value = t.Bool(False)

    def __init__(self,
                 size,
                 index_in_array=None,
                 name=t.Undefined,
                 scale=1.,
                 offset=0.,
                 units=t.Undefined,
                 navigate=t.Undefined):
        super(DataAxis, self).__init__()
        self.name = name
        self.units = units
        self.scale = scale
        self.offset = offset
        self.size = size
        self.high_index = self.size - 1
        self.low_index = 0
        self.index = 0
        self.update_axis()
        self.navigate = navigate
        self.axes_manager = None
        self.on_trait_change(self.update_axis,
                             ['scale', 'offset', 'size'])
        self.on_trait_change(self.update_value, 'index')
        self.on_trait_change(self.set_index_from_value, 'value')
        self.on_trait_change(self._update_slice, 'navigate')
        self.on_trait_change(self.update_index_bounds, 'size')
        # The slice must be updated even if the default value did not
        # change to correctly set its value.
        self._update_slice(self.navigate)

    @property
    def index_in_array(self):
        if self.axes_manager is not None:
            return self.axes_manager._axes.index(self)
        else:
            raise AttributeError(
                "This DataAxis does not belong to an AxesManager"
                " and therefore its index_in_array attribute "
                " is not defined")

    @property
    def index_in_axes_manager(self):
        if self.axes_manager is not None:
            return self.axes_manager._get_axes_in_natural_order().\
                index(self)
        else:
            raise AttributeError(
                "This DataAxis does not belong to an AxesManager"
                " and therefore its index_in_array attribute "
                " is not defined")

    def _get_positive_index(self, index):
        if index < 0:
            index = self.size + index
            if index < 0:
                raise IndexError("index out of bounds")
        return index

    def _get_index(self, value):
        if isfloat(value):
            return self.value2index(value)
        else:
            return value

    def _get_array_slices(self, slice_):
        """Returns a slice to slice the corresponding data axis without
        changing the offset and scale of the DataAxis.

        Parameters
        ----------
        slice_ : {float, int, slice}

        Returns
        -------
        my_slice : slice

        """
        v2i = self.value2index

        if isinstance(slice_, slice):
            start = slice_.start
            stop = slice_.stop
            step = slice_.step
        else:
            if isfloat(slice_):
                start = v2i(slice_)
            else:
                start = self._get_positive_index(slice_)
            stop = start + 1
            step = None

        if isfloat(step):
            step = int(round(step / self.scale))
        if isfloat(start):
            try:
                start = v2i(start)
            except ValueError:
                # The value is below the axis limits
                # we slice from the start.
                start = None
        if isfloat(stop):
            try:
                stop = v2i(stop)
            except ValueError:
                # The value is above the axes limits
                # we slice up to the end.
                stop = None

        if step == 0:
            raise ValueError("slice step cannot be zero")

        return slice(start, stop, step)

    def _slice_me(self, slice_):
        """Returns a slice to slice the corresponding data axis and
        change the offset and scale of the DataAxis acordingly.

        Parameters
        ----------
        slice_ : {float, int, slice}

        Returns
        -------
        my_slice : slice

        """
        i2v = self.index2value

        my_slice = self._get_array_slices(slice_)

        start, stop, step = my_slice.start, my_slice.stop, my_slice.step

        if start is None:
            if step > 0 or step is None:
                start = 0
            else:
                start = self.size - 1
        self.offset = i2v(start)
        if step is not None:
            self.scale *= step

        return my_slice

    def _get_name(self):
        if self.name is t.Undefined:
            if self.axes_manager is None:
                name = "Unnamed"
            else:
                name = "Unnamed " + ordinal(self.index_in_axes_manager)
        else:
            name = self.name
        return name

    def __repr__(self):
        text = '<%s axis, size: %i' % (self._get_name(),
                                       self.size,)
        if self.navigate is True:
            text += ", index: %i" % self.index
        text += ">"
        return text.encode('utf8')

    def __str__(self):
        return self._get_name() + " axis"

    def connect(self, f, trait='value'):
        self.on_trait_change(f, trait)

    def disconnect(self, f, trait='value'):
        self.on_trait_change(f, trait, remove=True)

    def update_index_bounds(self):
        self.high_index = self.size - 1

    def update_axis(self):
        self.axis = generate_axis(self.offset, self.scale, self.size)
        if len(self.axis) != 0:
            self.low_value, self.high_value = (
                self.axis.min(), self.axis.max())

    def _update_slice(self, value):
        if value is False:
            self.slice = slice(None)
        else:
            self.slice = None

    def get_axis_dictionary(self):
        adict = {
            'name': self.name,
            'scale': self.scale,
            'offset': self.offset,
            'size': self.size,
            'units': self.units,
            'navigate': self.navigate
        }
        return adict

    def copy(self):
        return DataAxis(**self.get_axis_dictionary())

    def __copy__(self):
        return self.copy()

    def __deepcopy__(self, memo):
        cp = self.copy()
        return cp

    def update_value(self):
        self.value = self.axis[self.index]

    def value2index(self, value, rounding=round):
        """Return the closest index to the given value if between the limit.

        Parameters
        ----------
        value : number or numpy array

        Returns
        -------
        index : integer or numpy array

        Raises
        ------
        ValueError if any value is out of the axis limits.

        """
        if value is None:
            return None

        if isinstance(value, np.ndarray):
            if rounding is round:
                rounding = np.round
            elif rounding is math.ceil:
                rounding = np.ceil
            elif rounding is math.floor:
                rounding = np.floor

        index = rounding((value - self.offset) / self.scale)

        if isinstance(value, np.ndarray):
            index = index.astype(int)
            if np.all(self.size > index) and np.all(index >= 0):
                return index
            else:
                raise ValueError("A value is out of the axis limits")
        else:
            index = int(index)
            if self.size > index >= 0:
                return index
            else:
                raise ValueError("The value is out of the axis limits")

    def index2value(self, index):
        if isinstance(index, np.ndarray):
            return self.axis[index.ravel()].reshape(index.shape)
        else:
            return self.axis[index]

    def set_index_from_value(self, value):
        self.index = self.value2index(value)
        # If the value is above the limits we must correct the value
        if self.continuous_value is False:
            self.value = self.index2value(self.index)

    def calibrate(self, value_tuple, index_tuple, modify_calibration=True):
        scale = (value_tuple[1] - value_tuple[0]) /\
            (index_tuple[1] - index_tuple[0])
        offset = value_tuple[0] - scale * index_tuple[0]
        if modify_calibration is True:
            self.offset = offset
            self.scale = scale
        else:
            return offset, scale

    def value_range_to_indices(self, v1, v2):
        """Convert the given range to index range.

        When an out of the axis limits, the endpoint is used instead.

        Parameters
        ----------
        v1, v2 : float
            The end points of the interval in the axis units. v2 must be
            greater than v1.

        """
        if v1 > v2:
            raise ValueError("v2 must be greater than v1.")

        if v1 is not None and v1 > self.low_value and v1 <= self.high_value:
            i1 = self.value2index(v1)
        else:
            i1 = 0
        if v2 is not None and v2 < self.high_value and v2 >= self.low_value:
            i2 = self.value2index(v2)
        else:
            i2 = self.size - 1
        return i1, i2
class short_rate(trapi.HasTraits):
    name = trapi.Str
    rate = trapi.Float
    time_list = trapi.Array(dtype = np.float,shape = (5,))
    def get_discount_factors(self):
        return np.exp(- self.rate * self.time_list)
Exemple #11
0
class InputParameter(trapi.HasTraits):
    """Class the is used to input all of the user parameters through a guy"""
    tickers_input = trapi.Str
    time_windows_input = trapi.Array(trapi.Int, (1, nbr_max_time_windows))
    data_source = trapi.Enum("Yahoo", "Bloomberg", "Telemaco")
    date_start = trapi.Date
    date_end = trapi.Date
    get_data_button = trapi.Button
    plot_chart_button = trapi.Button
    corr_data = pd.DataFrame
    correlpairs = trapi.List
    selected_correl_pair_indices = trapi.List
    corr_pairs_combinations = trapi.List
    v = trui.View(trui.HGroup(trui.Item(name='tickers_input', style='custom'),
                              trui.VGroup(
                                  trui.Item(name='date_start'),
                                  trui.Item(name='date_end'),
                                  trui.Item(name='time_windows_input'),
                                  trui.Item(name='data_source'),
                                  trui.Item(name='get_data_button',
                                            label='Process Data',
                                            show_label=False),
                                  trui.Item('correlpairs',
                                            show_label=False,
                                            editor=correl_pair_editor),
                                  trui.Item(name='plot_chart_button',
                                            label='Plot Selected Data',
                                            show_label=False),
                              ),
                              show_border=True,
                              label='Input Data'),
                  resizable=True,
                  title='Correlation Tool',
                  height=screen_height,
                  width=screen_width,
                  icon='corr.png',
                  image='corr.png')

    def _plot_chart_button_fired(self):
        """Method to plot the selected data"""
        # Read TableEditor to see what the user has chosen to
        data_to_plot = []
        for i in range(0, len(self.correlpairs)):
            if i == len(self.correlpairs) - 1:
                pair_name = ['BASKET CORREL', 'BASKET CORREL']
            else:
                pair_name = self.correlpairs[i].correl_pair.split('-')

            if self.correlpairs[i].time_window_1:
                data_to_plot.append(
                    (pair_name[0].strip(), pair_name[1].strip(),
                     self.time_windows_input[0][0]))
            if self.correlpairs[i].time_window_2:
                data_to_plot.append(
                    (pair_name[0].strip(), pair_name[1].strip(),
                     self.time_windows_input[0][1]))
            if self.correlpairs[i].time_window_3:
                data_to_plot.append(
                    (pair_name[0].strip(), pair_name[1].strip(),
                     self.time_windows_input[0][2]))
            if self.correlpairs[i].time_window_4:
                data_to_plot.append(
                    (pair_name[0].strip(), pair_name[1].strip(),
                     self.time_windows_input[0][3]))
            if self.correlpairs[i].time_window_5:
                data_to_plot.append(
                    (pair_name[0].strip(), pair_name[1].strip(),
                     self.time_windows_input[0][4]))

        # Plot
        pl.plot_data(self.corr_data[0], self.corr_data[1], data_to_plot)

    def check_data_retrieval_error(self, raw_data, tickers_list):
        """Check whether there was an error retrieving data"""
        # Check whether data was retrieved successfully:
        if self.data_source == 'Yahoo':
            if len(tickers_list) > 1:
                empty_col = []
                for column_name in raw_data.columns:
                    if raw_data[column_name].isna().all():
                        empty_col.append(column_name)
                        raw_data[column_name].drop
                if empty_col:
                    message(
                        'There was a problem loading data for the following underlyings:\n'
                        + '\n'.join(empty_col))
                    return [x for x in tickers_list if x not in empty_col]
                else:
                    return tickers_list
            else:
                return tickers_list

        elif self.data_source == 'Bloomberg':
            if len(tickers_list) > 1:
                if len(raw_data.columns) < len(tickers_list):
                    und_errors = np.setdiff1d(tickers_list, raw_data.columns)
                    message(
                        'There was a problem loading data for the following underlyings:\n'
                        + '\n'.join(und_errors))
                    return [x for x in tickers_list if x not in und_errors]
                else:
                    return tickers_list
            else:
                return tickers_list

    def _get_data_button_fired(self):
        """Method to download the relevant data and then compute the relevant correlations"""
        tickers_list = self.tickers_input.strip().split('\n')

        time_windows = self.time_windows_input[0, :].astype(int)

        # Get raw data
        raw_data = dr.get_relevant_data(tickers_list, self.date_start,
                                        self.date_end, self.data_source)

        # Check whether there was an error retrieving data
        tickers_list = self.check_data_retrieval_error(raw_data, tickers_list)
        if len(tickers_list) <= 1:
            message(
                'You need at least two underlyings to compute correlations')
            return

        # Process raw data
        log_returns = cc.process_raw_data(raw_data)

        # Filter log returns
        log_returns = cc.filter_log_returns(log_returns)

        # Compute pairwise correlations
        self.corr_data = cc.get_correlations(log_returns, time_windows)

        # Generate TableEditor
        for i in range(0, len(time_windows)):
            correl_pair_editor.columns[i + 1].label = str(time_windows[i])
        self.corr_pairs_combinations = [
            pair[0] + ' - ' + pair[1]
            for pair in it.combinations(tickers_list, 2)
        ]
        self.corr_pairs_combinations.append('BASKET CORREL')
        self.correlpairs = [
            generate_correl_pair(pair) for pair in self.corr_pairs_combinations
        ]
Exemple #12
0
class TimeLoop(HasStrictTraits):

    tline = tr.Instance(TLine)
    '''Time line object specifying the start, end, time step and current time
    '''
    def _tline_default(self):
        return TLine(min=0.0, max=1.0, step=1.0)

    ts = tr.Instance(DOTSGrid)
    '''State object delivering the predictor and corrector
    '''

    bc_mngr = tr.Instance(BCondMngr, ())
    '''Boundary condition manager.
    '''

    bc_list = tr.List([])
    '''List of boundary conditions.
    '''

    def _bc_list_changed(self):
        self.bc_mngr.bcond_list = self.bc_list

    step_tolerance = tr.Float(1e-8)
    '''Time step tolerance.
    '''

    KMAX = tr.Int(300)
    '''Maximum number of iterations.
    '''

    tolerance = tr.Float(1e-3)
    '''Tolerance of the residuum norm. 
    '''

    t_n1 = tr.Float(0, input=True)
    '''Target time for the next increment.
    '''

    t_n = tr.Float(0, input=True)
    '''Time of the last equilibrium state. 
    '''

    d_t = tr.Float(0, input=True)
    '''Current time increment size.
    '''

    def eval(self):

        update_state = False
        tloop.bc_mngr.setup(None)
        K = SysMtxAssembly()
        self.bc_mngr.apply_essential(K)
        U_n = np.zeros((self.ts.mesh.n_dofs, ), dtype=np.float_)
        dU = np.copy(U_n)
        U_k = np.copy(U_n)
        F_ext = np.zeros_like(U_n)

        while (self.t_n1 - self.tline.max) <= self.step_tolerance:

            print 'current time %f' % self.t_n1,

            self.d_t = self.tline.step

            k = 0
            step_flag = 'predictor'

            while k < self.KMAX:

                K.reset_mtx()
                K_arr, F_int, n_F_int = self.ts.get_corr_pred(
                    U_k, dU, self.t_n, self.t_n1, update_state)
                if update_state:
                    update_state = False

                K.sys_mtx_arrays.append(K_arr)

                F_ext[:] = 0.0
                self.bc_mngr.apply(step_flag, None, K, F_ext, self.t_n,
                                   self.t_n1)
                R = F_ext - F_int
                K.apply_constraints(R)
                if n_F_int == 0.0:
                    n_F_int = 1.0
                norm = np.linalg.norm(R, ord=None)  # / n_F_int
                if norm < self.tolerance:  # convergence satisfied
                    print 'converged in %d iterations' % (k + 1)
                    update_state = True
                    self.F_int_record.append(F_int)
                    self.U_record.append(np.copy(U_k))
                    break  # update_switch -> on
                dU = K.solve()
                U_k += dU
                k += 1
                step_flag = 'corrector'

            U_n = np.copy(U_k)
            self.t_n = self.t_n1
            self.record_response(U_k, self.t_n)
            self.t_n1 = self.t_n + self.d_t
            self.tline.val = min(self.t_n, self.tline.max)

        return U_n

    ug = tr.WeakRef
    write_dir = tr.Directory
    F_int_record = tr.List(tr.Array(np.float_))
    U_record = tr.List(tr.Array(np.float_))
    F_ext_record = tr.List(tr.Array(np.float_))
    t_record = tr.List(np.float_)
    record_dofs = tr.Array(np.int_)

    def record_response(self, U, t):
        n_c = self.ts.fets.n_nodal_dofs
        U_Ia = U.reshape(-1, n_c)
        U_Eia = U_Ia[self.ts.I_Ei]
        eps_Enab = np.einsum('Einabc,Eic->Enab', self.ts.B_Einabc, U_Eia)
        sig_Enab = np.einsum('abef,Emef->Emab', self.ts.mats.D_abcd, eps_Enab)
        U_vector_field = np.einsum('Ia,ab->Ib', U_Eia.reshape(-1, n_c),
                                   delta23_ab)
        self.ug.point_data.vectors = U_vector_field
        self.ug.point_data.vectors.name = 'displacement'
        eps_Encd = np.einsum('...ab,ac,bd->...cd', eps_Enab, delta23_ab,
                             delta23_ab)
        eps_Encd_tensor_field = eps_Encd.reshape(-1, 9)
        self.ug.point_data.tensors = eps_Encd_tensor_field
        self.ug.point_data.tensors.name = 'strain'
        fname = os.path.join(self.write_dir, 'step_%008.4f' % t)
        write_data(self.ug, fname.replace('.', '_'))
Exemple #13
0
class DOTSGrid(BMCSLeafNode):
    '''Domain time steppsr on a grid mesh
    '''
    x_0 = tr.Tuple(0., 0., input=True)
    L_x = tr.Float(200, input=True, MESH=True)
    L_y = tr.Float(100, input=True, MESH=True)
    n_x = tr.Int(100, input=True, MESH=True)
    n_y = tr.Int(30, input=True, MESH=True)
    integ_factor = tr.Float(1.0, input=True, MESH=True)
    fets = tr.Instance(IFETSEval, input=True, MESH=True)

    D1_abcd = tr.Array(np.float_, input=True)
    '''Symmetric operator distributing the 
    derivatives of the shape functions into the 
    tensor field
    '''
    def _D1_abcd_default(self):
        delta = np.identity(2)
        # symmetrization operator
        D1_abcd = 0.5 * (np.einsum('ac,bd->abcd', delta, delta) +
                         np.einsum('ad,bc->abcd', delta, delta))
        return D1_abcd

    mesh = tr.Property(tr.Instance(FEGrid), depends_on='+input')

    @tr.cached_property
    def _get_mesh(self):
        return FEGrid(coord_min=self.x_0,
                      coord_max=(self.x_0[0] + self.L_x,
                                 self.x_0[1] + self.L_y),
                      shape=(self.n_x, self.n_y),
                      fets_eval=self.fets)

    cached_grid_values = tr.Property(tr.Tuple, depends_on='+input')

    @tr.cached_property
    def _get_cached_grid_values(self):
        x_Ia = self.mesh.X_Id
        n_I, n_a = x_Ia.shape
        dof_Ia = np.arange(n_I * n_a, dtype=np.int_).reshape(n_I, -1)
        I_Ei = self.mesh.I_Ei
        x_Eia = x_Ia[I_Ei, :]
        dof_Eia = dof_Ia[I_Ei]
        x_Ema = np.einsum('im,Eia->Ema', self.fets.N_im, x_Eia)
        J_Emar = np.einsum('imr,Eia->Emar', self.fets.dN_imr, x_Eia)
        J_Enar = np.einsum('inr,Eia->Enar', self.fets.dN_inr, x_Eia)
        det_J_Em = np.linalg.det(J_Emar)
        inv_J_Emar = np.linalg.inv(J_Emar)
        inv_J_Enar = np.linalg.inv(J_Enar)
        B_Eimabc = np.einsum('abcd,imr,Eidr->Eimabc', self.D1_abcd,
                             self.fets.dN_imr, inv_J_Emar)
        B_Einabc = np.einsum('abcd,inr,Eidr->Einabc', self.D1_abcd,
                             self.fets.dN_inr, inv_J_Enar)
        BB_Emicjdabef = np.einsum('Eimabc,Ejmefd, Em, m->Emicjdabef', B_Eimabc,
                                  B_Eimabc, det_J_Em, self.fets.w_m)
        return (BB_Emicjdabef, B_Eimabc, dof_Eia, x_Eia, dof_Ia, I_Ei,
                B_Einabc, det_J_Em)

    BB_Emicjdabef = tr.Property()
    '''Quadratic form of the kinematic mapping.
    '''

    def _get_BB_Emicjdabef(self):
        return self.cached_grid_values[0]

    B_Eimabc = tr.Property()
    '''Kinematic mapping between displacements and strains in every
    integration point.
    '''

    def _get_B_Eimabc(self):
        return self.cached_grid_values[1]

    B_Einabc = tr.Property()
    '''Kinematic mapping between displacement and strain in every
    visualization point
    '''

    def _get_B_Einabc(self):
        return self.cached_grid_values[6]

    dof_Eia = tr.Property()
    '''Mapping [element, node, direction] -> degree of freedom.
    '''

    def _get_dof_Eia(self):
        return self.cached_grid_values[2]

    x_Eia = tr.Property()
    '''Mapping [element, node, direction] -> value of coordinate.
    '''

    def _get_x_Eia(self):
        return self.cached_grid_values[3]

    dof_Ia = tr.Property()
    '''[global node, direction] -> degree of freedom
    '''

    def _get_dof_Ia(self):
        return self.cached_grid_values[4]

    I_Ei = tr.Property()
    '''[element, node] -> global node
    '''

    def _get_I_Ei(self):
        return self.cached_grid_values[5]

    det_J_Em = tr.Property()
    '''Jacobi determinant in every element and integration point.
    '''

    def _get_det_J_Em(self):
        return self.cached_grid_values[7]

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

    @tr.cached_property
    def _get_state_arrays(self):
        return {
            name: np.zeros((
                self.mesh.n_active_elems,
                self.fets.n_m,
            ) + mats_sa_shape,
                           dtype=np.float_)
            for name, mats_sa_shape in list(
                self.mats.state_array_shapes.items())
        }

    def get_corr_pred(self, U, dU, t_n, t_n1, update_state, algorithmic):
        '''Get the corrector and predictor for the given increment
        of unknown .
        '''
        n_c = self.fets.n_nodal_dofs
        U_Ia = U.reshape(-1, n_c)
        U_Eia = U_Ia[self.I_Ei]
        eps_Emab = np.einsum('Eimabc,Eic->Emab', self.B_Eimabc, U_Eia)
        dU_Ia = dU.reshape(-1, n_c)
        dU_Eia = dU_Ia[self.I_Ei]
        deps_Emab = np.einsum('Eimabc,Eic->Emab', self.B_Eimabc, dU_Eia)
        D_Emabef, sig_Emab = self.mats.get_corr_pred(eps_Emab, deps_Emab, t_n,
                                                     t_n1, update_state,
                                                     algorithmic,
                                                     **self.state_arrays)
        K_Eicjd = self.integ_factor * np.einsum('Emicjdabef,Emabef->Eicjd',
                                                self.BB_Emicjdabef, D_Emabef)
        n_E, n_i, n_c, n_j, n_d = K_Eicjd.shape
        K_E = K_Eicjd.reshape(-1, n_i * n_c, n_j * n_d)
        dof_E = self.dof_Eia.reshape(-1, n_i * n_c)
        K_subdomain = SysMtxArray(mtx_arr=K_E, dof_map_arr=dof_E)
        f_Eic = self.integ_factor * np.einsum(
            'm,Eimabc,Emab,Em->Eic', self.fets.w_m, self.B_Eimabc, sig_Emab,
            self.det_J_Em)
        f_Ei = f_Eic.reshape(-1, n_i * n_c)
        F_dof = np.bincount(dof_E.flatten(), weights=f_Ei.flatten())
        F_int = F_dof
        norm_F_int = np.linalg.norm(F_int)
        return K_subdomain, F_int, norm_F_int
Exemple #14
0
class EEGSensor(t.HasTraits):
    preferences = t.Any()
    connected = t.Bool(False)
    serial_port = t.Instance(serial.Serial)

    com_port = t.Int()  # If None, we just search for it.

    def _com_port_default(self):
        """ Get default com port from preferences. """
        if self.preferences:
            return int(
                self.preferences.get('sensor.com_port', COM_SEARCH_START))
        return t.undefined

    def _com_port_changed(self, val):
        """ Save any COM port changes to preferences. """
        if self.preferences:
            return self.preferences.set('sensor.com_port', val)

    channels = t.Int(CHANNELS)
    timeseries = t.Array(dtype='float', value=np.zeros([1, CHANNELS + 1]))
    history = t.List()
    data_changed = t.Event()

    # Below, these separate properties and buttons for each channel are a bit
    #  verbose, but it seems to be the most clear way to implement this.
    channel_1_enabled = t.Bool(False)
    channel_2_enabled = t.Bool(False)
    channel_3_enabled = t.Bool(False)
    channel_4_enabled = t.Bool(False)
    channel_5_enabled = t.Bool(False)
    channel_6_enabled = t.Bool(False)
    channel_7_enabled = t.Bool(False)
    channel_8_enabled = t.Bool(False)

    channel_1_on = t.Button()
    channel_2_on = t.Button()
    channel_3_on = t.Button()
    channel_4_on = t.Button()
    channel_5_on = t.Button()
    channel_6_on = t.Button()
    channel_7_on = t.Button()
    channel_8_on = t.Button()

    channel_1_off = t.Button()
    channel_2_off = t.Button()
    channel_3_off = t.Button()
    channel_4_off = t.Button()
    channel_5_off = t.Button()
    channel_6_off = t.Button()
    channel_7_off = t.Button()
    channel_8_off = t.Button()

    # Properties
    history_length = t.Property(t.Int, depends_on="data_changed")

    def _get_history_length(self):
        return len(self.history)

    timeseries_length = t.Property(t.Int, depends_on="data_changed")

    def _get_timeseries_length(self):
        return self.timeseries.shape[0]

    @t.on_trait_change(','.join(['channel_%d_on' % i for i in range(1, 9)] +
                                ['channel_%d_off' % i for i in range(1, 9)]))
    def toggle_channels(self, name, new):
        if not self.connected:
            return
        deactivate_codes = ['1', '2', '3', '4', '5', '6', '7', '8']
        activate_codes = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i']
        if name.endswith('_off'):
            cmd = deactivate_codes[int(name[-len('_off') - 1]) - 1]
        elif name.endswith('_on'):
            cmd = activate_codes[int(name[-len('_on') - 1]) - 1]
        else:
            raise ValueError()
        self.serial_port.write(cmd + '\n')
        # self.serial_port.write('b\n')
        time.sleep(.100)
        # self.serial_port.flushInput()
        # time.sleep(.50)

    def connect(self):
        if self.connected:
            self.disconnect()

        assert self.serial_port is None

        # If no com port is selected, search for it... this search code could
        #  be drastically sped up by analyzing a listing of actual COM ports.
        try:
            if self.com_port is None:
                for i in range(COM_SEARCH_START, COM_SEARCH_END + 1):
                    try:
                        port = 'COM%d' % i
                        self.serial_port = serial.Serial(
                            port, BAUD, timeout=STARTUP_TIMEOUT)
                        if self.serial_port.read(1) == '':
                            self.serial_port.close()
                            self.serial_port = None
                            continue
                        else:
                            # Assume it's the right one...
                            self.serial_port.write('s\n')  # Reset.
                            self.serial_port.write(
                                'b\n')  # Start sending binary.
                            self.serial_port.read(
                                5)  # Make sure we can read something
                            # Okay, we're convinced.
                            self.com_port = i
                            self.connected = True
                            self.serial_port.timeout = RUN_TIMEOUT
                            break
                    except serial.SerialException, e:
                        logging.warn("Couldn't open %s: %s" % (port, str(e)))
                else:
                    logging.warn("Couldn't find a functioning serial port." %
                                 (port, str(e)))

            else:  # A specific COM port is requested.
Exemple #15
0
class FETS3D8H(FETS3D, InjectSymbExpr):

    symb_class = FETS3D8HSymbExpr

    dof_r = tr.Array(np.float_,
                     value=[
                         [-1, -1, -1],
                         [1, -1, -1],
                         [-1, 1, -1],
                         [1, 1, -1],
                         [-1, -1, 1],
                         [1, -1, 1],
                         [-1, 1, 1],
                         [1, 1, 1],
                     ])

    geo_r = tr.Array(np.float_,
                     value=[
                         [-1, -1, -1],
                         [1, -1, -1],
                         [-1, 1, -1],
                         [1, 1, -1],
                         [-1, -1, 1],
                         [1, -1, 1],
                         [-1, 1, 1],
                         [1, 1, 1],
                     ])
    vtk_r = tr.Array(np.float_,
                     value=[
                         [-1, -1, -1],
                         [1, -1, -1],
                         [-1, 1, -1],
                         [1, 1, -1],
                         [-1, -1, 1],
                         [1, -1, 1],
                         [-1, 1, 1],
                         [1, 1, 1],
                     ])
    n_nodal_dofs = 3

    delta = np.identity(n_nodal_dofs)

    vtk_cells = [[0, 1, 3, 2, 4, 5, 7, 6]]
    vtk_cell_types = 'Hexahedron'
    vtk_cell = [0, 1, 3, 2, 4, 5, 7, 6]
    vtk_cell_type = 'Hexahedron'

    vtk_expand_operator = tr.Array(np.float_, value=np.identity(3))

    # numerical integration points (IP) and weights
    xi_m = tr.Array(
        np.float_,
        value=[
            [-1.0 / np.sqrt(3.0), -1.0 / np.sqrt(3.0), -1.0 / np.sqrt(3.0)],
            [1.0 / np.sqrt(3.0), -1.0 / np.sqrt(3.0), -1.0 / np.sqrt(3.0)],
            [-1.0 / np.sqrt(3.0), 1.0 / np.sqrt(3.0), -1.0 / np.sqrt(3.0)],
            [1.0 / np.sqrt(3.0), 1.0 / np.sqrt(3.0), -1.0 / np.sqrt(3.0)],
            [-1.0 / np.sqrt(3.0), -1.0 / np.sqrt(3.0), 1.0 / np.sqrt(3.0)],
            [1.0 / np.sqrt(3.0), -1.0 / np.sqrt(3.0), 1.0 / np.sqrt(3.0)],
            [-1.0 / np.sqrt(3.0), 1.0 / np.sqrt(3.0), 1.0 / np.sqrt(3.0)],
            [1.0 / np.sqrt(3.0), 1.0 / np.sqrt(3.0), 1.0 / np.sqrt(3.0)],
        ])

    w_m = tr.Array(value=[1, 1, 1, 1, 1, 1, 1, 1], dtype=np.float_)

    n_m = tr.Property

    def _get_n_m(self):
        return len(self.w_m)

    N_im = tr.Property()
    '''Shape function values in integration poindots.
    '''

    @tr.cached_property
    def _get_N_im(self):
        N_im = self.symb.get_N_xi_i(self.xi_m.T)
        return N_im

    dN_imr = tr.Property()
    '''Shape function derivatives in integration points.
    '''

    @tr.cached_property
    def _get_dN_imr(self):
        N_rim = self.symb.get_dN_xi_ai(self.xi_m.T)
        return np.einsum('rim->imr', N_rim)

    dN_inr = tr.Property()
    '''Shape function derivatives in visualization points.
    '''

    @tr.cached_property
    def _get_dN_inr(self):
        N_rin = self.symb.get_dN_xi_ai(self.dof_r.T)
        return np.einsum('rin->inr', N_rin)

    I_sym_abcd = tr.Array(np.float)

    def _I_sym_abcd_default(self):
        return 0.5 * \
            (np.einsum('ac,bd->abcd', delta, delta) +
             np.einsum('ad,bc->abcd', delta, delta))

    plot_backend = 'k3d'

    def update_plot(self, axes):
        ax = axes
        import numpy as np
        v = np.linspace(-1, 1, 10)
        x, y, z = np.meshgrid(v, v, v)
        X_aIJK = np.array([x, y, z], dtype=np.float_)
        xmin, xmax, ymin, ymax, zmin, zmax = -1, 1, -1, 1, -1, 1
        N_IJK = fets.symb.get_N_xi_i(X_aIJK)[0, ...]
        N_IJK.shape
        plt_iso = k3d.marching_cubes(N_IJK[0, ...],
                                     compression_level=9,
                                     xmin=xmin,
                                     xmax=xmax,
                                     ymin=ymin,
                                     ymax=ymax,
                                     zmin=zmin,
                                     zmax=zmax,
                                     level=0.5,
                                     flat_shading=False)
        k3d_plot += plt_iso
        k3d_plot.display()
class MATS3DSlideStrain(MATS3DEval):
    r'''
    Isotropic damage model.
    '''
    node_name = 'Slide3D'

    n_a = tr.Array(np.float_, value=[0, 1, 0])

    slide_displ = bu.Instance(Slide34, ())

    slide_displ_ = tr.Property(depends_on='+MAT')
    '''Reconfigure slide with the derived stiffness parameters'''
    @tr.cached_property
    def _get_slide_displ_(self):
        self.slide_displ.trait_set(E_N=self.E, E_T=self.E_T)
        return self.slide_displ

    tree = ['slide_displ']

    ipw_view = bu.View(bu.Item('n_a'), bu.Item('slide_displ'))

    state_var_shapes = tr.Property

    @tr.cached_property
    def _get_state_var_shapes(self):
        return self.slide_displ_.state_var_shapes

    r'''
    Shapes of the state variables
    to be stored in the global array at the level 
    of the domain.
    '''

    def get_eps_N(self, eps_ij, n_i):
        eps_N = np.einsum('...ij,...i,...j->...', eps_ij, n_i, n_i)
        return eps_N

    def get_eps_T(self, eps_ij, n_i):
        delta_ij = np.identity(3)
        eps_T = 0.5 * (
            np.einsum('...i,...jk,...ij->...k', n_i, delta_ij, eps_ij) +
            np.einsum('...j,...ik,...ij->...k', n_i, delta_ij, eps_ij) -
            2 * np.einsum('...i,...j,...k,...ij->...k', n_i, n_i, n_i, eps_ij))
        return eps_T

    def get_eps_T_p(self, eps_T_p, eps_T):
        director_vector = [0, 0, 1]
        eps_T_p = np.einsum('...,...i->...i', eps_T_p, director_vector)
        return eps_T_p

    E_T = tr.Property(depends_on='MAT')

    @tr.cached_property
    def _get_E_T(self):
        n_i = self.n_a
        delta_ij = np.identity(3)
        D_ijkl = self.D_abef
        operator = 0.5 * (np.einsum('i,jk,l->ijkl', n_i, delta_ij, n_i) +
                          np.einsum('j,ik,l->jikl', n_i, delta_ij, n_i) -
                          2 * np.einsum('i,j,k,l->ijkl', n_i, n_i, n_i, n_i))
        E_T = np.einsum('ijkl,ijkl->', D_ijkl, operator)
        return E_T

    def get_corr_pred(self, eps_Emab_n1, tn1, **state):
        r'''
        Corrector predictor computation.
        '''
        n_i = self.n_a
        eps_ij = eps_Emab_n1
        eps_N = np.einsum('...ij,...i,...j->...', eps_ij, n_i, n_i)
        eps_T = self.get_eps_T(eps_ij, n_i)
        eps_T = np.sqrt(np.einsum('...i,...i->...', eps_T, eps_T))
        eps_NT_Ema = np.concatenate(
            [np.transpose(eps_N), np.transpose(eps_T)], axis=-1)
        print('eps_NT_Ema', eps_NT_Ema.shape)
        print(self.state_var_shapes)
        se = self.slide_displ_
        sig_NT_Ema, D_Emab = se.get_corr_pred(eps_NT_Ema, tn1, **state)

        eps_N_p, eps_T_p_x, eps_T_p_y = state['w_pi'], state['s_pi_x'], state[
            's_pi_y']
        eps_T = self.get_eps_T(eps_ij, n_i)
        eps_T_p_i = self.get_eps_T_p(eps_T_p_x, eps_T)
        omega_N_Em, omega_T_Em = state['omega_N'], state['omega_T']
        print(eps_ij.shape)

        phi_Emab = np.zeros_like(eps_ij)
        phi_Emab[:, 1, 1] = 0.
        phi_Emab[:, 2, 2] = np.sqrt(1 - omega_T_Em)
        phi_Emab[:, 0, 0] = np.sqrt(1 - omega_N_Em)

        beta_Emijkl = np.einsum('...ik,...jl->...ijkl', phi_Emab,
                                np.transpose(phi_Emab, (1, 0)))

        eps_ij_p = (np.einsum('i,...j->...ij', n_i, eps_T_p_i) +
                    np.einsum('...i,j->...ij', eps_T_p_i,n_i)) + \
                    np.einsum('...,i,j->...ij',eps_N_p, n_i, n_i)

        D_abef = self.D_abef

        D_Emabcd = np.einsum('...ijkl,klrs,...rstu->...ijtu', beta_Emijkl,
                             D_abef, beta_Emijkl)

        sigma_Emab = np.einsum('...ijkl,...kl->...ij', D_Emabcd,
                               (eps_Emab_n1 - eps_ij_p))

        return sigma_Emab, D_Emabcd
Exemple #17
0
class FETS1D52ULRH(FETSEval):
    '''
    Fe Bar 2 nodes, deformation
    '''

    debug_on = True

    A_m = Float(1, desc='matrix area [mm2]')
    A_f = Float(1, desc='reinforcement area [mm2]')
    P_b = Float(1, desc='perimeter of the bond interface [mm]')

    # Dimensional mapping
    dim_slice = slice(0, 1)

    n_nodal_dofs = Int(2)

    dof_r = Array(value=[[-1], [1]])
    geo_r = Array(value=[[-1], [1]])
    vtk_r = Array(value=[[-1.], [1.]])
    vtk_cells = [[0, 1]]
    vtk_cell_types = 'Line'

    dots_class = Type

    n_dof_r = Property
    '''Number of node positions associated with degrees of freedom. 
    '''
    @cached_property
    def _get_n_dof_r(self):
        return len(self.dof_r)

    n_e_dofs = Property
    '''Number of element degrees
    '''

    @cached_property
    def _get_n_e_dofs(self):
        return self.n_nodal_dofs * self.n_dof_r

    def _get_ip_coords(self):
        offset = 1e-6
        return np.array([[-1 + offset, 0., 0.], [1 - offset, 0., 0.]])

    def _get_ip_weights(self):
        return np.array([1., 1.], dtype=float)

    # Integration parameters
    #
    ngp_r = 2

    def get_N_geo_mtx(self, r_pnt):
        '''
        Return geometric shape functions
        @param r_pnt:
        '''
        r = r_pnt[0]
        N_mtx = np.array([[0.5 - r / 2., 0.5 + r / 2.]])
        return N_mtx

    def get_dNr_geo_mtx(self, r_pnt):
        '''
        Return the matrix of shape function derivatives.
        Used for the conrcution of the Jacobi matrix.
        '''
        return np.array([[-1. / 2, 1. / 2]])

    def get_N_mtx(self, r_pnt):
        '''
        Return shape functions
        @param r_pnt:local coordinates
        '''
        return self.get_N_geo_mtx(r_pnt)

    def get_dNr_mtx(self, r_pnt):
        '''
        Return the derivatives of the shape functions
        '''
        return self.get_dNr_geo_mtx(r_pnt)

    xi_m = Array(value=[[-1], [1]], dtype=np.float)
    r_m = Array(value=[[-1], [1]], dtype=np.float_)
    w_m = Array(value=[1, 1], dtype=np.float_)

    Nr_i_geo = List([
        (1 - r_) / 2.0,
        (1 + r_) / 2.0,
    ])

    dNr_i_geo = List([
        -1.0 / 2.0,
        1.0 / 2.0,
    ])

    Nr_i = Nr_i_geo
    dNr_i = dNr_i_geo

    N_mi_geo = Property()

    @cached_property
    def _get_N_mi_geo(self):
        return self.get_N_mi(sp.Matrix(self.Nr_i_geo, dtype=np.float_))

    dN_mid_geo = Property()

    @cached_property
    def _get_dN_mid_geo(self):
        return self.get_dN_mid(sp.Matrix(self.dNr_i_geo, dtype=np.float_))

    N_mi = Property()

    @cached_property
    def _get_N_mi(self):
        return self.get_N_mi(sp.Matrix(self.Nr_i, dtype=np.float_))

    dN_mid = Property()

    @cached_property
    def _get_dN_mid(self):
        return self.get_dN_mid(sp.Matrix(self.dNr_i, dtype=np.float_))

    def get_N_mi(self, Nr_i):
        return np.array([Nr_i.subs(r_, r) for r in self.r_m], dtype=np.float_)

    def get_dN_mid(self, dNr_i):
        dN_mdi = np.array([[dNr_i.subs(r_, r)] for r in self.r_m],
                          dtype=np.float_)
        return np.einsum('mdi->mid', dN_mdi)

    n_m = Property(depends_on='w_m')

    @cached_property
    def _get_n_m(self):
        return len(self.w_m)

    A_C = Property(depends_on='A_m,A_f')

    @cached_property
    def _get_A_C(self):
        return np.array((self.A_f, self.P_b, self.A_m), dtype=np.float_)

    def get_B_EmisC(self, J_inv_Emdd):
        fets_eval = self

        n_dof_r = fets_eval.n_dof_r
        n_nodal_dofs = fets_eval.n_nodal_dofs

        n_m = fets_eval.n_gp
        n_E = J_inv_Emdd.shape[0]
        n_s = 3
        #[ d, i]
        r_ip = fets_eval.ip_coords[:, :-2].T
        # [ d, n ]
        geo_r = fets_eval.geo_r.T
        # [ d, n, i ]
        dNr_geo = geo_r[:, :, None] * np.array([1, 1]) * 0.5
        # [ i, n, d ]
        dNr_geo = np.einsum('dni->ind', dNr_geo)

        # shape function for the unknowns
        # [ d, n, i]
        Nr = 0.5 * (1. + geo_r[:, :, None] * r_ip[None, :])
        dNr = 0.5 * geo_r[:, :, None] * np.array([1, 1])

        # [ i, n, d ]
        Nr = np.einsum('dni->ind', Nr)
        dNr = np.einsum('dni->ind', dNr)
        Nx = Nr
        # [ n_e, n_ip, n_dof_r, n_dim_dof ]
        dNx = np.einsum('eidf,inf->eind', J_inv_Emdd, dNr)

        B = np.zeros((n_E, n_m, n_dof_r, n_s, n_nodal_dofs), dtype='f')
        B_N_n_rows, B_N_n_cols, N_idx = [1, 1], [0, 1], [0, 0]
        B_dN_n_rows, B_dN_n_cols, dN_idx = [0, 2], [0, 1], [0, 0]
        B_factors = np.array([-1, 1], dtype='float_')
        B[:, :, :, B_N_n_rows,
          B_N_n_cols] = (B_factors[None, None, :] * Nx[:, :, N_idx])
        B[:, :, :, B_dN_n_rows, B_dN_n_cols] = dNx[:, :, :, dN_idx]

        return B

    def _get_B_EimsC(self, dN_Eimd, sN_Cim):

        n_E, _, _, _ = dN_Eimd.shape
        n_C, n_i, n_m = sN_Cim.shape
        n_s = 3
        B_EimsC = np.zeros((n_E, n_i, n_m, n_s, n_C), dtype='f')
        B_EimsC[..., [1, 1], [0, 1]] = sN_Cim[[0, 1], :, :]
        B_EimsC[..., [0, 2], [0, 1]] = dN_Eimd[:, [0, 1], :, :]

        return B_EimsC

    shape_function_values = tr.Property(tr.Tuple)
    '''The values of the shape functions and their derivatives at the IPs
    '''

    @tr.cached_property
    def _get_shape_function_values(self):
        N_mi = np.array([
            N_xi_i.subs(list(zip([xi_1, xi_2, xi_3], xi))) for xi in self.xi_m
        ],
                        dtype=np.float_)
        N_im = np.einsum('mi->im', N_mi)
        dN_mir_arr = [
            np.array(dN_xi_ir.subs(list(zip([xi_1], xi)))).astype(np.float_)
            for xi in self.xi_m
        ]
        dN_mir = np.array(dN_mir_arr, dtype=np.float)
        dN_nir_arr = [
            np.array(dN_xi_ir.subs(list(zip([xi_1], xi)))).astype(np.float_)
            for xi in self.vtk_r
        ]
        dN_nir = np.array(dN_nir_arr, dtype=np.float)
        dN_imr = np.einsum('mir->imr', dN_mir)
        dN_inr = np.einsum('nir->inr', dN_nir)
        return (N_im, dN_imr, dN_inr)

    N_im = tr.Property()
    '''Shape function values in integration poindots.
    '''

    def _get_N_im(self):
        return self.shape_function_values[0]

    dN_imr = tr.Property()
    '''Shape function derivatives in integration poindots.
    '''

    def _get_dN_imr(self):
        return self.shape_function_values[1]

    dN_inr = tr.Property()
    '''Shape function derivatives in visualization poindots.
    '''

    def _get_dN_inr(self):
        return self.shape_function_values[2]

    I_sym_abcd = tr.Array(np.float)

    def _I_sym_abcd_default(self):
        delta = np.identity(3)
        return 0.5 * \
            (np.einsum('ac,bd->abcd', delta, delta) +
             np.einsum('ad,bc->abcd', delta, delta))
Exemple #18
0
class FETS2D3U1M(FETSEval):
    r'''Triangular, three-node element.
    '''

    vtk_r = tr.Array(np.float_, value=[[1, 0, 0], [0, 1, 0], [0, 0, 1]])
    vtk_cells = [[0, 1, 2]]
    vtk_cell_types = 'Triangle'
    vtk_cell = [0, 1, 2]
    vtk_cell_type = 'Triangle'

    vtk_expand_operator = tr.Array(np.float_, value=DELTA23_ab)

    # =========================================================================
    # Surface integrals using numerical integration
    # =========================================================================
    # i is gauss point index, p is point coords in natural coords (zeta_1, zeta_2, zeta_3)
    eta_ip = tr.Array('float_')
    r'''Integration points within a triangle.
    '''
    def _eta_ip_default(self):
        # here, just one integration point in the middle of the triangle (zeta_1 = 1/3, zeta_2 = 1/3, zeta_3 = 1/3)
        return np.array([[1. / 3., 1. / 3., 1. / 3.]], dtype='f')

    w_m = tr.Array('float_')
    r'''Weight factors for numerical integration.
    '''

    def _w_m_default(self):
        return np.array([1. / 2.], dtype='f')

    n_m = tr.Int(1)
    r'''Number of integration points.
    '''

    @tr.cached_property
    def _get_w_m(self):
        return len(self.w_m)

    n_nodal_dofs = tr.Int(3)

    # N_im = tr.Property(depends_on='eta_ip')
    # r'''Shape function values in integration points.
    # '''
    # @tr.cached_property
    # def _get_N_im(self):
    #     eta = self.eta_ip
    #     return np.array([eta[:, 0], eta[:, 1], 1 - eta[:, 0] - eta[:, 1]],
    #                     dtype='f')

    dN_imr = tr.Property(depends_on='eta_ip')
    r'''Derivatives of the shape functions in the integration points.
    '''

    @tr.cached_property
    def _get_dN_imr(self):
        dN_mri = np.array(
            [
                [
                    [1, 0, -1],  # dN1/d_zeta1, dN2/d_zeta1, dN3/d_zeta1
                    [0, 1, -1]
                ],  # dN1/d_zeta2, dN2/d_zeta2, dN3/d_zeta2
            ],
            dtype=np.float_)
        return np.einsum('mri->imr', dN_mri)

    dN_inr = tr.Property(depends_on='eta_ip')
    r'''Derivatives of the shape functions in the integration points.
    '''

    @tr.cached_property
    def _get_dN_inr(self):
        return self.dN_imr

    vtk_expand_operator = tr.Array(value=[1, 1, 0])
    vtk_node_cell_data = tr.Array
    vtk_ip_cell_data = tr.Array
Exemple #19
0
class DataAxis(t.HasTraits):
    name = t.Str()
    units = t.Str()
    scale = t.Float()
    offset = t.Float()
    size = t.CInt()
    low_value = t.Float()
    high_value = t.Float()
    value = t.Range('low_value', 'high_value')
    low_index = t.Int(0)
    high_index = t.Int()
    slice = t.Instance(slice)
    navigate = t.Bool(t.Undefined)
    index = t.Range('low_index', 'high_index')
    axis = t.Array()
    continuous_value = t.Bool(False)

    def __init__(self,
                 size,
                 index_in_array=None,
                 name=t.Undefined,
                 scale=1.,
                 offset=0.,
                 units=t.Undefined,
                 navigate=t.Undefined):
        super(DataAxis, self).__init__()
        self.events = Events()
        self.events.index_changed = Event("""
            Event that triggers when the index of the `DataAxis` changes

            Triggers after the internal state of the `DataAxis` has been
            updated.

            Arguments:
            ---------
            obj : The DataAxis that the event belongs to.
            index : The new index
            """,
                                          arguments=["obj", 'index'])
        self.events.value_changed = Event("""
            Event that triggers when the value of the `DataAxis` changes

            Triggers after the internal state of the `DataAxis` has been
            updated.

            Arguments:
            ---------
            obj : The DataAxis that the event belongs to.
            value : The new value
            """,
                                          arguments=["obj", 'value'])
        self._suppress_value_changed_trigger = False
        self._suppress_update_value = False
        self.name = name
        self.units = units
        self.scale = scale
        self.offset = offset
        self.size = size
        self.high_index = self.size - 1
        self.low_index = 0
        self.index = 0
        self.update_axis()
        self.navigate = navigate
        self.axes_manager = None
        self.on_trait_change(self.update_axis, ['scale', 'offset', 'size'])
        self.on_trait_change(self._update_slice, 'navigate')
        self.on_trait_change(self.update_index_bounds, 'size')
        # The slice must be updated even if the default value did not
        # change to correctly set its value.
        self._update_slice(self.navigate)

    def _index_changed(self, name, old, new):
        self.events.index_changed.trigger(obj=self, index=self.index)
        if not self._suppress_update_value:
            new_value = self.axis[self.index]
            if new_value != self.value:
                self.value = new_value

    def _value_changed(self, name, old, new):
        old_index = self.index
        new_index = self.value2index(new)
        if self.continuous_value is False:  # Only values in the grid alowed
            if old_index != new_index:
                self.index = new_index
                if new == self.axis[self.index]:
                    self.events.value_changed.trigger(obj=self, value=new)
            elif old_index == new_index:
                new_value = self.index2value(new_index)
                if new_value == old:
                    self._suppress_value_changed_trigger = True
                    try:
                        self.value = new_value
                    finally:
                        self._suppress_value_changed_trigger = False

                elif new_value == new and not\
                        self._suppress_value_changed_trigger:
                    self.events.value_changed.trigger(obj=self, value=new)
        else:  # Intergrid values are alowed. This feature is deprecated
            self.events.value_changed.trigger(obj=self, value=new)
            if old_index != new_index:
                self._suppress_update_value = True
                self.index = new_index
                self._suppress_update_value = False

    @property
    def index_in_array(self):
        if self.axes_manager is not None:
            return self.axes_manager._axes.index(self)
        else:
            raise AttributeError(
                "This DataAxis does not belong to an AxesManager"
                " and therefore its index_in_array attribute "
                " is not defined")

    @property
    def index_in_axes_manager(self):
        if self.axes_manager is not None:
            return self.axes_manager._get_axes_in_natural_order().\
                index(self)
        else:
            raise AttributeError(
                "This DataAxis does not belong to an AxesManager"
                " and therefore its index_in_array attribute "
                " is not defined")

    def _get_positive_index(self, index):
        if index < 0:
            index = self.size + index
            if index < 0:
                raise IndexError("index out of bounds")
        return index

    def _get_index(self, value):
        if isfloat(value):
            return self.value2index(value)
        else:
            return value

    def _get_array_slices(self, slice_):
        """Returns a slice to slice the corresponding data axis without
        changing the offset and scale of the DataAxis.

        Parameters
        ----------
        slice_ : {float, int, slice}

        Returns
        -------
        my_slice : slice

        """
        v2i = self.value2index

        if isinstance(slice_, slice):
            start = slice_.start
            stop = slice_.stop
            step = slice_.step
        else:
            if isfloat(slice_):
                start = v2i(slice_)
            else:
                start = self._get_positive_index(slice_)
            stop = start + 1
            step = None

        if isfloat(step):
            step = int(round(step / self.scale))
        if isfloat(start):
            try:
                start = v2i(start)
            except ValueError:
                if start > self.high_value:
                    # The start value is above the axis limit
                    raise IndexError(
                        "Start value above axis high bound for  axis %s."
                        "value: %f high_bound: %f" %
                        (repr(self), start, self.high_value))
                else:
                    # The start value is below the axis limit,
                    # we slice from the start.
                    start = None
        if isfloat(stop):
            try:
                stop = v2i(stop)
            except ValueError:
                if stop < self.low_value:
                    # The stop value is below the axis limits
                    raise IndexError(
                        "Stop value below axis low bound for  axis %s."
                        "value: %f low_bound: %f" %
                        (repr(self), stop, self.low_value))
                else:
                    # The stop value is below the axis limit,
                    # we slice until the end.
                    stop = None

        if step == 0:
            raise ValueError("slice step cannot be zero")

        return slice(start, stop, step)

    def _slice_me(self, slice_):
        """Returns a slice to slice the corresponding data axis and
        change the offset and scale of the DataAxis acordingly.

        Parameters
        ----------
        slice_ : {float, int, slice}

        Returns
        -------
        my_slice : slice

        """
        i2v = self.index2value

        my_slice = self._get_array_slices(slice_)

        start, stop, step = my_slice.start, my_slice.stop, my_slice.step

        if start is None:
            if step is None or step > 0:
                start = 0
            else:
                start = self.size - 1
        self.offset = i2v(start)
        if step is not None:
            self.scale *= step

        return my_slice

    def _get_name(self):
        if self.name is t.Undefined:
            if self.axes_manager is None:
                name = "Unnamed"
            else:
                name = "Unnamed " + ordinal(self.index_in_axes_manager)
        else:
            name = self.name
        return name

    def __repr__(self):
        text = '<%s axis, size: %i' % (
            self._get_name(),
            self.size,
        )
        if self.navigate is True:
            text += ", index: %i" % self.index
        text += ">"
        return text

    def __str__(self):
        return self._get_name() + " axis"

    def update_index_bounds(self):
        self.high_index = self.size - 1

    def update_axis(self):
        self.axis = generate_axis(self.offset, self.scale, self.size)
        if len(self.axis) != 0:
            self.low_value, self.high_value = (self.axis.min(),
                                               self.axis.max())

    def _update_slice(self, value):
        if value is False:
            self.slice = slice(None)
        else:
            self.slice = None

    def get_axis_dictionary(self):
        adict = {
            'name': self.name,
            'scale': self.scale,
            'offset': self.offset,
            'size': self.size,
            'units': self.units,
            'navigate': self.navigate
        }
        return adict

    def copy(self):
        return DataAxis(**self.get_axis_dictionary())

    def __copy__(self):
        return self.copy()

    def __deepcopy__(self, memo):
        cp = self.copy()
        return cp

    def value2index(self, value, rounding=round):
        """Return the closest index to the given value if between the limit.

        Parameters
        ----------
        value : number or numpy array

        Returns
        -------
        index : integer or numpy array

        Raises
        ------
        ValueError if any value is out of the axis limits.

        """
        if value is None:
            return None

        if isinstance(value, np.ndarray):
            if rounding is round:
                rounding = np.round
            elif rounding is math.ceil:
                rounding = np.ceil
            elif rounding is math.floor:
                rounding = np.floor

        index = rounding((value - self.offset) / self.scale)

        if isinstance(value, np.ndarray):
            index = index.astype(int)
            if np.all(self.size > index) and np.all(index >= 0):
                return index
            else:
                raise ValueError("A value is out of the axis limits")
        else:
            index = int(index)
            if self.size > index >= 0:
                return index
            else:
                raise ValueError("The value is out of the axis limits")

    def index2value(self, index):
        if isinstance(index, np.ndarray):
            return self.axis[index.ravel()].reshape(index.shape)
        else:
            return self.axis[index]

    def calibrate(self, value_tuple, index_tuple, modify_calibration=True):
        scale = (value_tuple[1] - value_tuple[0]) /\
            (index_tuple[1] - index_tuple[0])
        offset = value_tuple[0] - scale * index_tuple[0]
        if modify_calibration is True:
            self.offset = offset
            self.scale = scale
        else:
            return offset, scale

    def value_range_to_indices(self, v1, v2):
        """Convert the given range to index range.

        When an out of the axis limits, the endpoint is used instead.

        Parameters
        ----------
        v1, v2 : float
            The end points of the interval in the axis units. v2 must be
            greater than v1.

        """
        if v1 is not None and v2 is not None and v1 > v2:
            raise ValueError("v2 must be greater than v1.")

        if v1 is not None and self.low_value < v1 <= self.high_value:
            i1 = self.value2index(v1)
        else:
            i1 = 0
        if v2 is not None and self.high_value > v2 >= self.low_value:
            i2 = self.value2index(v2)
        else:
            i2 = self.size - 1
        return i1, i2

    def update_from(self, axis, attributes=["scale", "offset", "units"]):
        """Copy values of specified axes fields from the passed AxesManager.

        Parameters
        ----------
        axis : DataAxis
            The DataAxis instance to use as a source for values.
        attributes : iterable container of strings.
            The name of the attribute to update. If the attribute does not
            exist in either of the AxesManagers, an AttributeError will be
            raised.
        Returns
        -------
        A boolean indicating whether any changes were made.

        """
        any_changes = False
        changed = {}
        for f in attributes:
            if getattr(self, f) != getattr(axis, f):
                changed[f] = getattr(axis, f)
        if len(changed) > 0:
            self.trait_set(**changed)
            any_changes = True
        return any_changes
class MATS2DMplDamageEEQ(MATSXDMicroplaneDamageJir, MATS2DEval):

    implements(IMATSEval)

    #-----------------------------------------------
    # number of microplanes - currently fixed for 3D
    #-----------------------------------------------
    n_mp = Constant(28)

    _alpha_list = Property(depends_on='n_mp')

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

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

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

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

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

    #-------------------------------------------------------------------------
    # Cached elasticity tensors
    #-------------------------------------------------------------------------
    stress_state = tr.Enum("plane_stress", "plane_strain", input=True)

    #-------------------------------------------------------------------------
    # Material parameters
    #-------------------------------------------------------------------------
    E = tr.Float(34e+3,
                 label="E",
                 desc="Young's Modulus",
                 auto_set=False,
                 input=True)

    nu = tr.Float(0.2,
                  label='nu',
                  desc="Poison ratio",
                  auto_set=False,
                  input=True)

    def _get_lame_params(self):
        la = self.E * self.nu / ((1. + self.nu) * (1. - 2. * self.nu))
        # second Lame parameter (shear modulus)
        mu = self.E / (2. + 2. * self.nu)
        return la, mu

    D_ab = tr.Property(tr.Array, depends_on='+input')
    '''Elasticity matrix (shape: (3,3))
    '''

    @tr.cached_property
    def _get_D_ab(self):
        if self.stress_state == 'plane_stress':
            return self._get_D_ab_plane_stress()
        elif self.stress_state == 'plane_strain':
            return self._get_D_ab_plane_strain()

    def _get_D_ab_plane_stress(self):
        '''
        Elastic Matrix - Plane Stress
        '''
        E = self.E
        nu = self.nu
        D_stress = np.zeros([3, 3])
        D_stress[0, 0] = E / (1.0 - nu * nu)
        D_stress[0, 1] = E / (1.0 - nu * nu) * nu
        D_stress[1, 0] = E / (1.0 - nu * nu) * nu
        D_stress[1, 1] = E / (1.0 - nu * nu)
        D_stress[2, 2] = E / (1.0 - nu * nu) * (1.0 / 2.0 - nu / 2.0)
        return D_stress

    def _get_D_ab_plane_strain(self):
        '''
        Elastic Matrix - Plane Strain
        '''
        E = self.E
        nu = self.nu
        D_strain = np.zeros([3, 3])
        D_strain[0, 0] = E * (1.0 - nu) / (1.0 + nu) / (1.0 - 2.0 * nu)
        D_strain[0, 1] = E / (1.0 + nu) / (1.0 - 2.0 * nu) * nu
        D_strain[1, 0] = E / (1.0 + nu) / (1.0 - 2.0 * nu) * nu
        D_strain[1, 1] = E * (1.0 - nu) / (1.0 + nu) / (1.0 - 2.0 * nu)
        D_strain[2, 2] = E * (1.0 - nu) / (1.0 + nu) / (2.0 - 2.0 * nu)
        return D_strain

    map2d_ijkl2a = tr.Array(np.int_,
                            value=[[[[0, 0], [0, 0]], [[2, 2], [2, 2]]],
                                   [[[2, 2], [2, 2]], [[1, 1], [1, 1]]]])
    map2d_ijkl2b = tr.Array(np.int_,
                            value=[[[[0, 2], [2, 1]], [[0, 2], [2, 1]]],
                                   [[[0, 2], [2, 1]], [[0, 2], [2, 1]]]])

    D_abef = tr.Property(tr.Array, depends_on='+input')

    @tr.cached_property
    def _get_D_abef(self):
        return self.D_ab[self.map2d_ijkl2a, self.map2d_ijkl2b]
Exemple #21
0
class GCS(t.HasTraits):
    """
    This is the ground control station GUI class. 
    
    For usage, for example if telemetry radio is on COM8 and the GCS Pixhawk is
    on COM7:
    >>> gcs = GCS()
    >>> gcs.setup_uav_link("COM8")
    >>> gcs.poll_uav()
    >>> gcs.setup_gcs_link("COM7")
    >>> gcs.poll_gcs()
    >>> gcs.configure_traits()
    >>> gcs.close()
    """
    # Connections
    dialect = t.Str("gcs_pixhawk")
    show_errors = t.Bool(True)

    # ON GCS: Outgoing
    mission_message = t.Enum(set_mission_mode.keys(), label="Mission Type")
    sweep_angle = t.Float(label="Angle (degrees)")
    sweep_alt_start = t.Float(label="Start Altitude (m)")
    sweep_alt_end = t.Float(label="End Altitude (m)")
    sweep_alt_step = t.Float(label="Number of Altitude Steps")

    mavlink_message = t.Enum(mavlink_msgs, label="Mavlink Message")
    mavlink_message_filt = t.Enum(mavlink_msgs_filt, label="Mavlink Message")
    mavlink_message_params = t.Str(label="params")
    mavlink_message_args = t.Str(', '.join(
        mavlink_msgs_attr[mavlink_msgs_filt[0]]['args'][1:]),
                                 label="Arguments")

    # ON GCS: Incoming
    # Tether
    tether_length = t.Float(t.Undefined, label='Length (m)')
    tether_tension = t.Float(t.Undefined, label='Tension (N)')
    tether_velocity = t.Float(t.Undefined, label="Velocity")

    # ON GCS: Incoming
    # GCS Pixhawk
    gcs_eph = t.Float(t.Undefined)
    gcs_epv = t.Float(t.Undefined)
    gcs_satellites_visible = t.Int(t.Undefined)
    gcs_fix_type = t.Int(t.Undefined)

    gcs_airspeed = t.Float(t.Undefined)
    gcs_groundspeed = t.Float(t.Undefined)
    gcs_heading = t.Float(t.Undefined)
    gcs_velocity = t.Array(shape=(3, ))

    # Location inputs
    gcs_alt = t.Float(t.Undefined)
    gcs_lat = t.Float(t.Undefined)
    gcs_lon = t.Float(t.Undefined)

    # Attitude inputs
    gcs_pitch = t.Float(t.Undefined)
    gcs_roll = t.Float(t.Undefined)
    gcs_yaw = t.Float(t.Undefined)
    gcs_pitchspeed = t.Float(t.Undefined)
    gcs_yawspeed = t.Float(t.Undefined)
    gcs_rollspeed = t.Float(t.Undefined)

    # Battery Inputs
    gcs_current = t.Float(t.Undefined)
    gcs_level = t.Float(t.Undefined)
    gcs_voltage = t.Float(t.Undefined)

    # GCS connectinos
    gcs = t.Any(t.Undefined)
    gcs_polling = t.Bool(False)
    gcs_msg_thread = t.Instance(threading.Thread)
    gcs_error = t.Int(0)
    gcs_port = t.Str(t.Undefined)
    gcs_baud = t.Int(t.Undefined)

    # ON DRONE: Incoming
    # Mission Status
    mission_status = t.Enum(mission_status.keys())

    # Probe
    probe_u = t.Float(t.Undefined, label="u (m/s)")
    probe_v = t.Float(t.Undefined, label="v (m/s)")
    probe_w = t.Float(t.Undefined, label="w (m/s)")

    # Vehicle inputs
    uav_modename = t.Str(t.Undefined)
    uav_armed = t.Bool(t.Undefined)
    uav_eph = t.Float(t.Undefined)
    uav_epv = t.Float(t.Undefined)
    uav_satellites_visible = t.Int(t.Undefined)
    uav_fix_type = t.Int(t.Undefined)

    uav_airspeed = t.Float(t.Undefined)
    uav_groundspeed = t.Float(t.Undefined)
    uav_heading = t.Float(t.Undefined)
    uav_velocity = t.Array(shape=(3, ))

    # Location inputs
    uav_alt = t.Float(t.Undefined)
    uav_lat = t.Float(t.Undefined)
    uav_lon = t.Float(t.Undefined)

    # Attitude inputs
    uav_pitch = t.Float(t.Undefined)
    uav_roll = t.Float(t.Undefined)
    uav_yaw = t.Float(t.Undefined)
    uav_pitchspeed = t.Float(t.Undefined)
    uav_yawspeed = t.Float(t.Undefined)
    uav_rollspeed = t.Float(t.Undefined)

    # Battery Inputs
    uav_current = t.Float(t.Undefined)
    uav_level = t.Float(t.Undefined)
    uav_voltage = t.Float(t.Undefined)

    # Vehicle Connections
    uav = t.Any(t.Undefined)
    uav_polling = t.Bool(False)
    uav_msg_thread = t.Instance(threading.Thread)
    uav_error = t.Int(0)
    uav_port = t.Str(t.Undefined)
    uav_baud = t.Int(t.Undefined)

    # GCS connectinos
    gcs = t.Any(t.Undefined)
    gcs_polling = t.Bool(False)
    gcs_msg_thread = t.Instance(threading.Thread)
    gcs_error = t.Int(0)
    gcs_port = t.Str(t.Undefined)
    gcs_baud = t.Int(t.Undefined)

    # ui Buttons and display groups
    update_mission = t.Button("Update")
    send_mavlink_message = t.Button("Send")
    filtered = t.Bool(True)

    group_input = tui.Group(
        tui.Item(name="mission_status", enabled_when='False'),
        tui.Item(name="mission_message"),
        tui.Item(name="sweep_angle",
                 visible_when='mission_message=="SCHEDULE_SWEEP"'),
        tui.Item(name="sweep_alt_start",
                 visible_when='mission_message=="SCHEDULE_SWEEP"'),
        tui.Item(name="sweep_alt_end",
                 visible_when='mission_message=="SCHEDULE_SWEEP"'),
        tui.Item(name="sweep_alt_step",
                 visible_when='mission_message=="SCHEDULE_SWEEP"'),
        tui.Item(name="update_mission"),
        tui.Item("_"),
        tui.Item("filtered"),
        tui.Item("mavlink_message", visible_when='filtered==False'),
        tui.Item("mavlink_message_filt", visible_when='filtered'),
        tui.Item("mavlink_message_args",
                 enabled_when='False',
                 editor=tui.TextEditor(),
                 height=-40),
        tui.Item("mavlink_message_params"),
        tui.Item("send_mavlink_message"),
        tui.Item("_"),
        tui.Item(name="tether_tension", enabled_when='False'),
        tui.Item(name="tether_length", enabled_when='False'),
        tui.Item(name="tether_velocity", enabled_when='False'),
        tui.Item("_"),
        orientation="vertical",
        show_border=True,
        label="On GCS")
    group_uav = tui.Group(tui.Item(name="uav_modename", enabled_when='False'),
                          tui.Item(name="uav_airspeed", enabled_when='False'),
                          tui.Item(name="uav_groundspeed",
                                   enabled_when='False'),
                          tui.Item(name='uav_armed', enabled_when='False'),
                          tui.Item(name='uav_alt', enabled_when='False'),
                          tui.Item(name='uav_lat', enabled_when='False'),
                          tui.Item(name='uav_lon', enabled_when='False'),
                          tui.Item(name='uav_velocity', enabled_when='False'),
                          tui.Item(name='uav_pitch', enabled_when='False'),
                          tui.Item(name='uav_roll', enabled_when='False'),
                          tui.Item(name='uav_yaw', enabled_when='False'),
                          tui.Item(name='uav_current', enabled_when='False'),
                          tui.Item(name='uav_level', enabled_when='False'),
                          tui.Item(name='uav_voltage', enabled_when='False'),
                          tui.Item("_"),
                          tui.Item(name='probe_u', enabled_when='False'),
                          tui.Item(name='probe_v', enabled_when='False'),
                          tui.Item(name='probe_w', enabled_when='False'),
                          orientation='vertical',
                          show_border=True,
                          label="Incoming")
    group_gcs = tui.Group(tui.Item(name="gcs_airspeed", enabled_when='False'),
                          tui.Item(name="gcs_groundspeed",
                                   enabled_when='False'),
                          tui.Item(name='gcs_alt', enabled_when='False'),
                          tui.Item(name='gcs_lat', enabled_when='False'),
                          tui.Item(name='gcs_lon', enabled_when='False'),
                          tui.Item(name='gcs_velocity', enabled_when='False'),
                          tui.Item(name='gcs_pitch', enabled_when='False'),
                          tui.Item(name='gcs_roll', enabled_when='False'),
                          tui.Item(name='gcs_yaw', enabled_when='False'),
                          tui.Item(name='gcs_current', enabled_when='False'),
                          tui.Item(name='gcs_level', enabled_when='False'),
                          tui.Item(name='gcs_voltage', enabled_when='False'),
                          orientation='vertical',
                          show_border=True,
                          label="GCS")
    traits_view = tui.View(tui.Group(group_input,
                                     group_uav,
                                     group_gcs,
                                     orientation='horizontal'),
                           resizable=True)

    def _update_mission_fired(self):
        """ This will fire when the update_mission button is clicked
        
        In that case we send one of our custom MAVLINK messages, either
        set_mission_mode or schedule_sweep
        
        """
        mode = set_mission_mode[self.mission_message]
        if mode >= 0:
            self.uav.mav.set_mission_mode_send(mode)
        else:
            self.uav.mav.schedule_sweep_send(self.sweep_angle,
                                             self.sweep_alt_start,
                                             self.sweep_alt_end,
                                             self.sweep_alt_step)

    def _mavlink_message_changed(self):
        """ This will fire when the dropdown is changed
        """
        self.mavlink_message_args = ', '.join(
            mavlink_msgs_attr[self.mavlink_message]['args'][1:])

    def _mavlink_message_filt_changed(self):
        """ This will fire when the filtered dropdown is changed
        """
        self.mavlink_message_args = ', '.join(
            mavlink_msgs_attr[self.mavlink_message_filt]['args'][1:])

    def _send_mavlink_message_fired(self):
        """ This will fire when the send_mavlink_message button is clicked
        
        In that case we pass on the mavlink message that the user is trying
        to send. 
        """
        func = mavlink_msgs_attr[self.mavlink_message]['name']
        args = [float(m) for m in self.mavlink_message_params.split(',')]
        getattr(self.uav.mav, func)(*args)

    def setup_uav_link(self, uav_port, uav_baud=56700):
        """
        This sets up the connection to the UAV. 
        
        Parameters
        -----------
        uav_port : str
            Serial port where UAV is connected (via telemetry radio)
        uav_baud: int, optional
            The baud rate. Default is 56700
        """
        mavutil.set_dialect(self.dialect)
        self.uav = mavutil.mavlink_connection(uav_port, uav_baud)
        self.uav_port = uav_port
        self.uav_baud = uav_baud

    def setup_gcs_link(self, gcs_port, gcs_baud=115200):
        """
        This sets up the connection to the GCS Pixhawk. 
        
        Parameters
        -----------
        uav_port : str
            Serial port where GCS Pixhawk is connected (via usb cable)
        uav_baud: int, optional
            The baud rate. Default is 115200
        """
        mavutil.set_dialect(self.dialect)
        self.gcs = mavutil.mavlink_connection(gcs_port, gcs_baud)
        self.gcs_port = gcs_port
        self.gcs_baud = gcs_baud

    def poll_uav(self):
        """
        This runs a new thread that listens for messages from the UAV and
        parses them for the GCS
        """
        self.uav_polling = True

        def worker():
            # Make sure we are connected
            m = self.uav
            m.mav.heartbeat_send(mavutil.mavlink.MAV_TYPE_GCS,
                                 mavutil.mavlink.MAV_AUTOPILOT_INVALID, 0, 0,
                                 0)
            print("Waiting for heartbeat from %s" % m.address)
            self.uav.wait_heartbeat()
            print "Found Heardbeat, continuing"

            i = 0
            while self.uav_polling:
                #                print "uav_polling round", i
                i += 1
                try:
                    s = m.recv(16 * 1024)
                except Exception:
                    time.sleep(0.1)
                # prevent a dead serial port from causing the CPU to spin. The user hitting enter will
                # cause it to try and reconnect
                if len(s) == 0:
                    time.sleep(0.1)

                if 'windows' in platform.architecture()[-1].lower():
                    # strip nsh ansi codes
                    s = s.replace("\033[K", "")

                if m.first_byte:
                    m.auto_mavlink_version(s)
                msgs = m.mav.parse_buffer(s)
                if msgs:
                    for msg in msgs:
                        if getattr(m, '_timestamp', None) is None:
                            m.post_message(msg)
                        if msg.get_type() == "BAD_DATA":
                            if self.show_errors:
                                print "MAV error: %s" % msg
                            self.uav_error += 1
                        else:
                            self.parse_uav_msg(msg)
            print "uav_polling Stopped"
            self.uav_polling = False

        self.uav_msg_thread = threading.Thread(target=worker)
        self.uav_msg_thread.start()

    def poll_gcs(self):
        """
        This runs a new thread that listens for messages from the GCS Pixhawk
        and parses them for the GCS, it also forwards relevant messages to the
        UAV
        """
        self.gcs_polling = True

        def worker():
            # Make sure we are connected
            m = self.gcs
            m.mav.heartbeat_send(mavutil.mavlink.MAV_TYPE_GCS,
                                 mavutil.mavlink.MAV_AUTOPILOT_INVALID, 0, 0,
                                 0)
            print("Waiting for heartbeat from %s" % m.address)
            self.gcs.wait_heartbeat()
            print "Found Heardbeat, continuing"
            i = 0
            while self.gcs_polling:
                #                print "gcs_polling round", i
                i += 1
                try:
                    s = m.recv(16 * 1024)
                except Exception:
                    time.sleep(0.1)
                # prevent a dead serial port from causing the CPU to spin. The user hitting enter will
                # cause it to try and reconnect
                if len(s) == 0:
                    time.sleep(0.1)

                if 'windows' in platform.architecture()[-1].lower():
                    # strip nsh ansi codes
                    s = s.replace("\033[K", "")

                if m.first_byte:
                    m.auto_mavlink_version(s)
                msgs = m.mav.parse_buffer(s)
                if msgs:
                    for msg in msgs:
                        if getattr(m, '_timestamp', None) is None:
                            m.post_message(msg)
                        if msg.get_type() == "BAD_DATA":
                            if self.show_errors:
                                print "MAV error: %s" % msg
                            self.gcs_error += 1
                        else:
                            self.parsefwd_gcs_msg(msg)
            print "gcs_polling Stopped"
            self.gcs_polling = False

        self.gcs_msg_thread = threading.Thread(target=worker)
        self.gcs_msg_thread.start()

    def parse_uav_msg(self, m):
        """
        This parses a message received from the UAV and stores the values
        in the class attributes so that the GUI will update
        """
        #        print "Parsing Message"
        typ = m.get_type()
        if typ == 'GLOBAL_POSITION_INT':
            (self.uav_lat, self.uav_lon) = (m.lat / 1.0e7, m.lon / 1.0e7)
            self.uav_velocity = (m.vx / 100.0, m.vy / 100.0, m.vz / 100.0)
        elif typ == 'GPS_RAW':
            pass  # better to just use global position int
            # (self.lat, self.lon) = (m.lat, m.lon)
            # self.__on_change('location')
        elif typ == 'GPS_RAW_INT':
            # (self.lat, self.lon) = (m.lat / 1.0e7, m.lon / 1.0e7)
            self.uav_eph = m.eph
            self.uav_epv = m.epv
            self.uav_satellites_visible = m.satellites_visible
            self.uav_fix_type = m.fix_type
        elif typ == "VFR_HUD":
            self.uav_heading = m.heading
            self.uav_alt = m.alt
            self.uav_airspeed = m.airspeed
            self.uav_groundspeed = m.groundspeed
        elif typ == "ATTITUDE":
            self.uav_pitch = m.pitch
            self.uav_yaw = m.yaw
            self.uav_roll = m.roll
            self.uav_pitchspeed = m.pitchspeed
            self.uav_yawspeed = m.yawspeed
            self.uav_rollspeed = m.rollspeed
        elif typ == "SYS_STATUS":
            self.uav_voltage = m.voltage_battery
            self.uav_current = m.current_battery
            self.uav_level = m.battery_remaining
        elif typ == "HEARTBEAT":
            pass
#        print "Parsing Message DONE"

    def fwd_msg_to_uav(self, m):
        """This forwards messages from the GCS Pixhawk to the UAV if there is
        a UAV connected"""
        if self.uav is not t.Undefined:
            self.uav.write(m.get_msgbuf())

    def parsefwd_gcs_msg(self, m):
        """
        This parses a message received from the GCS Pixhawk, stores the values
        in the class attributes so that the GUI will update, and forwards 
        relevant messages to the UAV
        """
        #        print "Parsing Message"
        typ = m.get_type()
        if typ == 'GLOBAL_POSITION_INT':
            (self.gcs_lat, self.gcs_lon) = (m.lat / 1.0e7, m.lon / 1.0e7)
            self.gcs_velocity = (m.vx / 100.0, m.vy / 100.0, m.vz / 100.0)
            # Forward message
            self.fwd_msg_to_uav(m)
        elif typ == 'GPS_RAW':
            # better to just use global position int
            # (self.lat, self.lon) = (m.lat, m.lon)
            # self.__on_change('location')
            # Forward message
            self.fwd_msg_to_uav(m)
        elif typ == 'GPS_RAW_INT':
            # (self.lat, self.lon) = (m.lat / 1.0e7, m.lon / 1.0e7)
            self.gcs_eph = m.eph
            self.gcs_epv = m.epv
            self.gcs_satellites_visible = m.satellites_visible
            self.gcs_fix_type = m.fix_type
            # Forward message
            self.fwd_msg_to_uav(m)
        elif typ == "VFR_HUD":
            self.gcs_heading = m.heading
            self.gcs_alt = m.alt
            self.gcs_airspeed = m.airspeed
            self.gcs_groundspeed = m.groundspeed
            # Forward message
            self.fwd_msg_to_uav(m)
        elif typ == "ATTITUDE":
            self.gcs_pitch = m.pitch
            self.gcs_yaw = m.yaw
            self.gcs_roll = m.roll
            self.gcs_pitchspeed = m.pitchspeed
            self.gcs_yawspeed = m.yawspeed
            self.gcs_rollspeed = m.rollspeed
            # Forward message
            self.fwd_msg_to_uav(m)
        elif typ == "SYS_STATUS":
            self.gcs_voltage = m.voltage_battery
            self.gcs_current = m.current_battery
            self.gcs_level = m.battery_remaining
        elif typ == "HEARTBEAT":
            # Forward message
            self.fwd_msg_to_uav(m)


#        print "Parsing Message DONE"

    def close(self, *args, **kwargs):
        """
        This closes down the serial connections and stop the GUI polling
        """
        print 'Closing down connection'
        try:
            self.uav_polling = False
            self.uav.close()
        except:
            pass
        try:
            self.gcs_polling = False
            self.gcs.close()
        except:
            pass
class LinAlgSolve(tr.HasStrictTraits):
    '''Example of a linear equation system

    Solve the system of equations of the form

    :math
        A u = b_0 - b_t

    To define the boundary conditions prescribing the 
    values on the left-hand-side a sequential
    inclusion of the condition is managed by this class.
    Thus, the registration of the condition is performed
    first to register the variables affected by the 
    problem.
    '''
    o_I = tr.Array(np.int_)

    n_dofs = tr.Property(depends_on='dof_map')

    @tr.cached_property
    def _get_n_dofs(self):
        return np.max(self.o_I) + 1

    A = tr.Array(np.float_)

    R_t = tr.Property(tr.Array(np.float), depends_on='dof_map')

    @tr.cached_property
    def _get_R_t(self):
        return np.zeros((self.n_dofs,), np.float_)

    R_0 = tr.Property(tr.Array(np.float), depends_on='dof_map')

    @tr.cached_property
    def _get_R_0(self):
        return np.zeros((self.n_dofs,), np.float_)

    # The dependency graph

    constraints = tr.List
    '''Constraints are stored as a list of arrays.
    '''

    def register_constraint(self, a_U, U_a=0, tf=lambda t: t,
                            b_alpha=[], alpha_b=[]):
        '''Register the prescribed values of u as linear 
        transformations - mappings
        '''
        self.constraints.append((a_U, U_a, tf, b_alpha, alpha_b))

    t_n1 = tr.Float(1.0)

    U_arr = tr.Property(depends_on='t_n1')

    @tr.cached_property
    def _get_U_arr(self):
        '''Get the value of the constraint for the current step.
        '''
        carr = np.array(self.constraints)
        U_arr = carr[:, 1]
        tfarr = carr[:, 2]
        val_arr = np.array(
            [tf(u)
             for tf, u in zip(tfarr, U_arr)], dtype=np.float_)
        return val_arr

    def apply_constraints(self):
        carr = np.array(self.constraints)
        a_arr = np.array(carr[:, 0], dtype=np.int_)
        A_aa = self.A[a_arr, a_arr]
        self.A[a_arr, :] = 0
        self.A[:, a_arr] = 0
        self.A[a_arr, a_arr] = A_aa
        self.R_0[:] = np.einsum('i,ij->j', self.U_arr, self.A[a_arr, :])

    def solve(self):
        '''Solve the system
        '''
        return np.linalg.solve(self.A, self.R_0 - self.R_t)
Exemple #23
0
class TStepBC(TStep):

    tloop_type = tr.Type(TLoopImplicit)

    primary_var_changed = tr.Event

    def __init__(self, *args, **kw):
        super().__init__(*args, **kw)
        self.fe_domain

    #=========================================================================
    # Time and state
    #=========================================================================

    t_n = tr.Float(0.0)
    '''Fundamental state time used for time dependent essential BC'
    '''
    U_n = tr.Property(tr.Array(np.float_),
                      depends_on='model_structure_changed')
    '''Fundamental value of the primary (control variable)
    '''
    @tr.cached_property
    def _get_U_n(self):
        return np.zeros_like(self.U_k)

    '''Current fundamental value of the primary variable.
    '''
    U_k = tr.Property(tr.Array(np.float_),
                      depends_on='model_structure_changed')
    '''Fundamental value of the primary (control variable)
    '''
    @tr.cached_property
    def _get_U_k(self):

        U_var_shape = self.fe_domain.U_var_shape
        return np.zeros(U_var_shape, dtype=np.float_).flatten()

    model_structure_changed = tr.Event

    bc = tr.List
    r'''Boundary conditions
    '''
    record = tr.Dict
    r'''Recorded variables
    '''

    # Boundary condition manager
    #
    bcond_mngr = tr.Property(tr.Instance(BCondMngr),
                             depends_on='bc,bc_items,model_structure_changed')

    @tr.cached_property
    def _get_bcond_mngr(self):
        return BCondMngr(bcond_list=self.bc)

    def init_state(self):
        '''Initialize state.
        '''
        self.t_n = 0.0
        self.t_n1 = 0.0
        self.model_structure_changed = True

    step_flag = tr.Enum('predictor', 'corrector')
    '''Step flag to control the inclusion of essential BC'
    '''
    @tr.on_trait_change('model_structure_changed')
    def _reset(self):
        self.step_flag = 'predictor'

    K = tr.Property(
        tr.Instance(SysMtxAssembly),
        depends_on='model_structure_changed'
    )
    '''System matrix with registered essencial boundary conditions.
    '''
    @tr.cached_property
    def _get_K(self):
        K = SysMtxAssembly()
        self.bcond_mngr.setup(None)
        self.bcond_mngr.register(K)
        return K

    #=========================================================================
    # Spatial domain
    #=========================================================================
    domains = tr.List([])
    r'''Spatial domain represented by a finite element discretization.
    providing the kinematic mapping between the linear algebra (vector and
    matrix) and field representation of the primary variables.
    '''

    fe_domain = tr.Property(depends_on='model_structure_changed')

    @tr.cached_property
    def _get_fe_domain(self):
        domains = [
            DomainState(tstep=self, xdomain=xdomain, tmodel=tmodel)
            for xdomain, tmodel in self.domains
        ]
        return XDomain(domains)

    corr_pred = tr.Property(depends_on='primary_var_changed,t_n1')

    @tr.cached_property
    def _get_corr_pred(self):
        self.K.reset_mtx()
        f_Eis, K_ks, dof_Es = np.array(
            [s.get_corr_pred(self.U_k, self.t_n, self.t_n1)
             for s in self.fe_domain]
        ).T
        self.K.sys_mtx_arrays = list(K_ks)  # improve
        F_ext = np.zeros_like(self.U_k)
        self.bcond_mngr.apply(
            self.step_flag, None, self.K, F_ext, self.t_n, self.t_n1
        )
        F_int = np.bincount(
            np.hstack(np.hstack(dof_Es)),
            weights=np.hstack(np.hstack(f_Eis))
        )
        R = F_ext - F_int
        self.K.apply_constraints(R)
        if self.debug:
            print('t_n1', self.t_n1)
            print('U_k\n', self.U_k)
            print('F_int\n', F_int)
            print('F_ext\n', F_ext)
        return R, self.K, F_int

    def make_iter(self):
        '''Perform a single iteration
        '''
        d_U_k, pos_def = self.K.solve(check_pos_def=True)
        if self.debug:
            print('positive definite', pos_def)
        self.U_k[:] += d_U_k
        self.primary_var_changed = True
        self.step_flag = 'corrector'

    def make_incr(self):
        '''Update the control, primary and state variables..
        '''
        self.U_n[:] = self.U_k[:]
        states = [d.record_state() for d in self.fe_domain]
        self.hist.record_timestep(self.t_n1, self.U_k, self.F_k, states)
        self.t_n = self.t_n1
        self.step_flag = 'predictor'

    def __str__(self):
        s = '\nt_n: %g, t_n1: %g' % (self.t_n, self.t_n1)
        s += '\nU_n' + str(self.U_n)
        s += '\nU_k' + str(self.U_k)
        return s

    R_norm = tr.Property

    def _get_R_norm(self):
        R = self.R
        return np.sqrt(np.einsum('...i,...i', R, R))

    R = tr.Property

    def _get_R(self):
        R, _, _ = self.corr_pred
        return R.flatten()

    dR = tr.Property

    def _get_dR(self):
        _, dR, _ = self.corr_pred
        return dR

    F_k = tr.Property

    def _get_F_k(self):
        _, _, F_k = self.corr_pred
        return F_k
Exemple #24
0
class CXDViz(tr.HasTraits):
    coords = tr.Array()
    arr = tr.Array()

    cropx = tr.Int()
    cropy = tr.Int()
    cropz = tr.Int()

    def __init__(self):
        self.imd = tvtk.ImageData()
        self.sg = tvtk.StructuredGrid()
        pass

    def set_geometry(self, params, shape):
        lam = params.lamda
        tth = params.delta
        gam = params.gamma
        dpx = params.dpx
        dpy = params.dpy
        dth = params.dth
        dx = 1.0 / shape[0]
        dy = 1.0 / shape[1]
        dz = 1.0 / shape[2]
        dQdpx = np.zeros(3)
        dQdpy = np.zeros(3)
        dQdth = np.zeros(3)
        Astar = np.zeros(3)
        Bstar = np.zeros(3)
        Cstar = np.zeros(3)

        dQdpx[0] = -m.cos(tth) * m.cos(gam)
        dQdpx[1] = 0.0
        dQdpx[2] = +m.sin(tth) * m.cos(gam)

        dQdpy[0] = m.sin(tth) * m.sin(gam)
        dQdpy[1] = -m.cos(gam)
        dQdpy[2] = m.cos(tth) * m.sin(gam)

        dQdth[0] = -m.cos(tth) * m.cos(gam) + 1.0
        dQdth[1] = 0.0
        dQdth[2] = m.sin(tth) * m.cos(gam)

        Astar[0] = 2 * m.pi / lam * dpx * dQdpx[0]
        Astar[1] = 2 * m.pi / lam * dpx * dQdpx[1]
        Astar[2] = 2 * m.pi / lam * dpx * dQdpx[2]

        Bstar[0] = (2 * m.pi / lam) * dpy * dQdpy[0]
        Bstar[1] = (2 * m.pi / lam) * dpy * dQdpy[1]
        Bstar[2] = (2 * m.pi / lam) * dpy * dQdpy[2]

        Cstar[0] = (2 * m.pi / lam) * dth * dQdth[0]
        Cstar[1] = (2 * m.pi / lam) * dth * dQdth[1]
        Cstar[2] = (2 * m.pi / lam) * dth * dQdth[2]

        denom = np.dot(Astar, np.cross(Bstar, Cstar))
        A = 2 * m.pi * np.cross(Bstar, Cstar) / denom
        B = 2 * m.pi * np.cross(Cstar, Astar) / denom
        C = 2 * m.pi * np.cross(Astar, Bstar) / denom

        self.T = np.zeros(9)
        self.T.shape = (3, 3)
        space = 'direct'
        if space == 'recip':
            self.T[:, 0] = Astar
            self.T[:, 1] = Bstar
            self.T[:, 2] = Cstar
            self.dx = 1.0
            self.dy = 1.0
            self.dz = 1.0
        elif space == 'direct':
            self.T = np.array((A, B, C))
            self.dx = dx
            self.dy = dy
            self.dz = dz
        else:
            pass

    def update_coords(self):
        dims = list(self.arr[self.cropobj].shape)

        r = np.mgrid[(dims[0] - 1) * self.dx:-self.dx:-self.dx, \
            0:dims[1] * self.dy:self.dy, 0:dims[2] * self.dz:self.dz]

        r.shape = 3, dims[0] * dims[1] * dims[2]
        r = r.transpose()

        print r.shape
        print self.T.shape

        self.coords = np.dot(r, self.T)

    def set_array(self, array, logentry=None):
        self.arr = array
        if len(self.arr.shape) < 3:
            newdims = list(self.arr.shape)
            for i in range(3 - len(newdims)):
                newdims.append(1)
            self.arr.shape = tuple(newdims)

    def set_crop(self, cropx, cropy, cropz):
        dims = list(self.arr.shape)
        if len(dims) == 2:
            dims.append(1)

        if dims[0] > cropx and cropx > 0:
            self.cropx = cropx
        else:
            self.cropx = dims[0]

        if dims[1] > cropy and cropy > 0:
            self.cropy = cropy
        else:
            self.cropy = dims[1]

        if dims[2] > cropz and cropz > 0:
            self.cropz = cropz
        else:
            self.cropz = dims[2]

        start1 = dims[0] / 2 - self.cropx / 2
        end1 = dims[0] / 2 + self.cropx / 2
        if start1 == end1:
            end1 = end1 + 1
        start2 = dims[1] / 2 - self.cropy / 2
        end2 = dims[1] / 2 + self.cropy / 2
        if start2 == end2:
            end2 = end2 + 1
        start3 = dims[2] / 2 - self.cropz / 2
        end3 = dims[2] / 2 + self.cropz / 2
        if start3 == end3:
            end3 = end3 + 1

        self.cropobj = (slice(start1, end1, None), slice(start2, end2, None),
                        slice(start3, end3, None))

    def get_structured_grid(self, **args):
        self.update_coords()
        dims = list(self.arr[self.cropobj].shape)
        self.sg.points = self.coords
        if args.has_key("mode"):
            if args["mode"] == "Phase":
                arr1 = self.arr[self.cropobj].ravel()
                arr = (np.arctan2(arr1.imag, arr1.real))
            else:
                arr = np.abs(self.arr[self.cropobj].ravel())
        else:
            arr = self.arr[self.cropobj].ravel()
        if (arr.dtype == np.complex128 or arr.dtype == np.complex64):
            self.sg.point_data.scalars = np.abs(arr)
            self.sg.point_data.scalars.name = "Amp"
            ph = tvtk.DoubleArray()
            ph.from_array(np.arctan2(arr.imag, arr.real))
            ph.name = "Phase"
            self.sg.point_data.add_array(ph)
        else:
            self.sg.point_data.scalars = arr
        self.sg.dimensions = (dims[2], dims[1], dims[0])
        self.sg.extent = 0, dims[2] - 1, 0, dims[1] - 1, 0, dims[0] - 1
        return self.sg

    def get_image_data(self, **args):
        self.set_crop(self.cropx, self.cropy, self.cropz)
        dims = list(self.arr[self.cropobj].shape)
        if len(dims) == 2:
            dims.append(1)
        self.imd.dimensions = tuple(dims)
        self.imd.extent = 0, dims[2] - 1, 0, dims[1] - 1, 0, dims[0] - 1
        self.imd.point_data.scalars = self.arr[self.cropobj].ravel()
        return self.imd

    def write_structured_grid(self, filename, **args):
        print 'in WriteStructuredGrid'
        sgwriter = tvtk.StructuredGridWriter()
        sgwriter.file_type = 'binary'
        if filename.endswith(".vtk"):
            sgwriter.file_name = filename
        else:
            sgwriter.file_name = filename + '.vtk'

        sgwriter.set_input_data(self.get_structured_grid())
        print sgwriter.file_name
        sgwriter.write()
Exemple #25
0
class FETS2D4Q(FETS2D):
    dof_r = tr.Array(np.float_,
                     value=[[-1, -1], [1, -1], [1, 1], [-1, 1]])
    geo_r = tr.Array(np.float_,
                     value=[[-1, -1], [1, -1], [1, 1], [-1, 1]])
    vtk_r = tr.Array(np.float_,
                     value=[[-1, -1], [1, -1], [1, 1], [-1, 1]])
    n_nodal_dofs = 2
    vtk_r = tr.Array(np.float_, value=[[-1, -1], [1, -1], [1, 1],
                                       [-1, 1]])
    vtk_cells = [[0, 1, 2, 3]]
    vtk_cell_types = 'Quad'
    vtk_cell = [0, 1, 2, 3]
    vtk_cell_type = 'Quad'

    vtk_expand_operator = tr.Array(np.float_, value=DELTA23_ab)

    # numerical integration points (IP) and weights
    xi_m = tr.Array(np.float_,
                    value=[[-1.0 / np.sqrt(3.0), -1.0 / np.sqrt(3.0)],
                           [1.0 / np.sqrt(3.0), -1.0 / np.sqrt(3.0)],
                           [1.0 / np.sqrt(3.0), 1.0 / np.sqrt(3.0)],
                           [-1.0 / np.sqrt(3.0), 1.0 / np.sqrt(3.0)]
                           ])

    w_m = tr.Array(value=[1, 1, 1, 1], dtype=np.float_)

    n_m = tr.Property

    def _get_n_m(self):
        return len(self.w_m)

    shape_function_values = tr.Property(tr.Tuple)
    '''The values of the shape functions and their derivatives at the IPs
    '''
    @tr.cached_property
    def _get_shape_function_values(self):
        N_mi = np.array([N_xi_i.subs(list(zip([xi_1, xi_2], xi)))
                         for xi in self.xi_m], dtype=np.float_)[...,0]
        N_im = np.einsum('mi->im', N_mi)
        dN_mir = np.array([dN_xi_ir.subs(list(zip([xi_1, xi_2], xi)))
                           for xi in self.xi_m], dtype=np.float_).reshape(4, 4, 2)
        dN_nir = np.array([dN_xi_ir.subs(list(zip([xi_1, xi_2], xi)))
                           for xi in self.vtk_r], dtype=np.float_).reshape(4, 4, 2)
        dN_imr = np.einsum('mir->imr', dN_mir)
        dN_inr = np.einsum('nir->inr', dN_nir)
        return (N_im, dN_imr, dN_inr)

    # shape_function_values = tr.Property(tr.Tuple)
    # '''The values of the shape functions and their derivatives at the IPs
    # '''
    # @tr.cached_property
    # def _get_shape_function_values(self):
    #     N_mi = get_N_xi_i(*self.xi_m.T)
    #     N_im = np.einsum('mi->im', N_mi)
    #     dN_mir = get_dN_xi_ir(*self.xi_m.T)
    #     dN_nir = get_dN_xi_ir(*self.xi_n.T)
    #     dN_imr = np.einsum('mir->imr', dN_mir)
    #     dN_inr = np.einsum('nir->inr', dN_nir)
    #     return (N_im, dN_imr, dN_inr)

    N_im = tr.Property()
    '''Shape function values in integration poindots.
    '''

    def _get_N_im(self):
        return self.shape_function_values[0]

    dN_imr = tr.Property()
    '''Shape function derivatives in integration poindots.
    '''

    def _get_dN_imr(self):
        return self.shape_function_values[1]

    dN_inr = tr.Property()
    '''Shape function derivatives in visualization poindots.
    '''

    def _get_dN_inr(self):
        return self.shape_function_values[2]
Exemple #26
0
class MomentCurvature(tr.HasStrictTraits):
    r'''Class returning the moment curvature relationship.
    '''

    b_z = tr.Any
    get_b_z = tr.Property

    @tr.cached_property
    def _get_get_b_z(self):
        return sp.lambdify(z, self.b_z, 'numpy')

    h = tr.Float

    model_params = tr.Dict({
        E_ct: 24000, E_cc: 25000,
        eps_cr: 0.001,
        eps_cy: -0.003,
        eps_cu: -0.01,
        mu: 0.33,
        eps_tu: 0.003
    })

    # Number of material points along the height of the cross section
    n_m = tr.Int(100)

    # Reinforcement
    z_j = tr.Array(np.float_, value=[10])
    A_j = tr.Array(np.float_, value=[[np.pi * (16 / 2.)**2]])
    E_j = tr.Array(np.float_, value=[[210000]])
    eps_sy_j = tr.Array(np.float_, value=[[500. / 210000.]])

    z_m = tr.Property(depends_on='n_m, h')

    @tr.cached_property
    def _get_z_m(self):
        return np.linspace(0, self.h, self.n_m)

    kappa_range = tr.Tuple(-0.001, 0.001, 101)

    kappa_t = tr.Property(tr.Array(np.float_), depends_on='kappa_range')

    @tr.cached_property
    def _get_kappa_t(self):
        return np.linspace(*self.kappa_range)

    get_eps_z = tr.Property(depends_on='model_params_items')

    @tr.cached_property
    def _get_get_eps_z(self):
        return sp.lambdify(
            (kappa, eps_bot, z), eps_z.subs(subs_eps), 'numpy'
        )

    get_sig_c_z = tr.Property(depends_on='model_params_items')

    @tr.cached_property
    def _get_get_sig_c_z(self):
        return sp.lambdify(
            (kappa, eps_bot, z), sig_c_z_lin.subs(self.model_params), 'numpy'
        )

    get_sig_s_eps = tr.Property(depends_on='model_params_items')

    @tr.cached_property
    def _get_get_sig_s_eps(self):
        return sp.lambdify((eps, E_s, eps_sy), sig_s_eps, 'numpy')

    # Normal force

    def get_N_s_tj(self, kappa_t, eps_bot_t):
        eps_z_tj = self.get_eps_z(
            kappa_t[:, np.newaxis], eps_bot_t[:, np.newaxis],
            self.z_j[np.newaxis, :]
        )
        sig_s_tj = self.get_sig_s_eps(eps_z_tj, self.E_j, self.eps_sy_j)
        return np.einsum('j,tj->tj', self.A_j, sig_s_tj)

    def get_N_c_t(self, kappa_t, eps_bot_t):
        z_tm = self.z_m[np.newaxis, :]
        b_z_m = self.get_b_z(z_tm)  # self.get_b_z(self.z_m) also OK
        N_z_tm = b_z_m * self.get_sig_c_z(
            kappa_t[:, np.newaxis], eps_bot_t[:, np.newaxis], z_tm
        )
        return np.trapz(N_z_tm, x=z_tm, axis=-1)

    def get_N_t(self, kappa_t, eps_bot_t):
        N_s_t = np.sum(self.get_N_s_tj(kappa_t, eps_bot_t), axis=-1)
        return self.get_N_c_t(kappa_t, eps_bot_t) + N_s_t

    # SOLVER: Get eps_bot to render zero force

    eps_bot_t = tr.Property()
    r'''Resolve the tensile strain to get zero normal force 
    for the prescribed curvature
    '''

    def _get_eps_bot_t(self):
        res = root(lambda eps_bot_t: self.get_N_t(self.kappa_t, eps_bot_t),
                   0.0000001 + np.zeros_like(self.kappa_t), tol=1e-6)
        return res.x

    # POSTPROCESSING

    eps_cr = tr.Property()

    def _get_eps_cr(self):
        return np.array([self.model_params[eps_cr]], dtype=np.float_)

    kappa_cr = tr.Property()

    def _get_kappa_cr(self):
        res = root(lambda kappa: self.get_N_t(kappa, self.eps_cr),
                   0.0000001 + np.zeros_like(self.eps_cr), tol=1e-10)
        return res.x

    # Bending moment

    M_s_t = tr.Property()

    def _get_M_s_t(self):
        eps_z_tj = self.get_eps_z(
            self.kappa_t[:, np.newaxis], self.eps_bot_t[:, np.newaxis],
            self.z_j[np.newaxis, :]
        )
        sig_z_tj = self.get_sig_s_eps(
            eps_z_tj, self.E_j, self.eps_sy_j)
        return -np.einsum('j,tj,j->t', self.A_j, sig_z_tj, self.z_j)

    M_c_t = tr.Property()

    def _get_M_c_t(self):
        z_tm = self.z_m[np.newaxis, :]
        b_z_m = self.get_b_z(z_tm)
        N_z_tm = b_z_m * self.get_sig_c_z(
            self.kappa_t[:, np.newaxis], self.eps_bot_t[:, np.newaxis], z_tm
        )
        return -np.trapz(N_z_tm * z_tm, x=z_tm, axis=-1)

    M_t = tr.Property()

    def _get_M_t(self):
        return self.M_c_t + self.M_s_t

    N_s_tj = tr.Property()

    def _get_N_s_tj(self):
        return self.get_N_s_tj(self.kappa_t, self.eps_bot_t)

    eps_tm = tr.Property()

    def _get_eps_tm(self):
        return self.get_eps_z(
            self.kappa_t[:, np.newaxis], self.eps_bot_t[:, np.newaxis],
            self.z_m[np.newaxis, :],
        )

    sig_tm = tr.Property()

    def _get_sig_tm(self):
        return self.get_sig_c_z(
            self.kappa_t[:, np.newaxis], self.eps_bot_t[:, np.newaxis],
            self.z_m[np.newaxis, :],
        )

    idx = tr.Int(0)

    M_norm = tr.Property()

    def _get_M_norm(self):
        # Section modulus @TODO optimize W for var b
        W = (self.b * self.h**2) / 6
        sig_cr = self.model_params[E_ct] * self.model_params[eps_cr]
        return W * sig_cr

    kappa_norm = tr.Property()

    def _get_kappa_norm(self):
        return self.kappa_cr

    def plot_norm(self, ax1, ax2):
        idx = self.idx
        ax1.plot(self.kappa_t / self.kappa_norm, self.M_t / self.M_norm)
        ax1.plot(self.kappa_t[idx] / self.kappa_norm,
                 self.M_t[idx] / self.M_norm, marker='o')
        ax2.barh(self.z_j, self.N_s_tj[idx, :],
                 height=2, color='red', align='center')
        #ax2.fill_between(eps_z_arr[idx,:], z_arr, 0, alpha=0.1);
        ax3 = ax2.twiny()
#        ax3.plot(self.eps_tm[idx, :], self.z_m, color='k', linewidth=0.8)
        ax3.plot(self.sig_tm[idx, :], self.z_m)
        ax3.axvline(0, linewidth=0.8, color='k')
        ax3.fill_betweenx(self.z_m, self.sig_tm[idx, :], 0, alpha=0.1)
        self._align_xaxis(ax2, ax3)

    def plot(self, ax1, ax2):
        idx = self.idx
        ax1.plot(self.kappa_t, self.M_t / (1e6))
        ax1.set_ylabel('Moment [kN.m]')
        ax1.set_xlabel('Curvature [$m^{-1}$]')
        ax1.plot(self.kappa_t[idx], self.M_t[idx] / (1e6), marker='o')
        ax2.barh(self.z_j, self.N_s_tj[idx, :],
                 height=6, color='red', align='center')
        #ax2.plot(self.N_s_tj[idx, :], self.z_j, color='red')
        #print('Z', self.z_j)
        #print(self.N_s_tj[idx, :])
        #ax2.fill_between(eps_z_arr[idx,:], z_arr, 0, alpha=0.1);
        ax3 = ax2.twiny()
#        ax3.plot(self.eps_tm[idx, :], self.z_m, color='k', linewidth=0.8)
        ax3.plot(self.sig_tm[idx, :], self.z_m)
        ax3.axvline(0, linewidth=0.8, color='k')
        ax3.fill_betweenx(self.z_m, self.sig_tm[idx, :], 0, alpha=0.1)
        self._align_xaxis(ax2, ax3)

    def _align_xaxis(self, ax1, ax2):
        """Align zeros of the two axes, zooming them out by same ratio"""
        axes = (ax1, ax2)
        extrema = [ax.get_xlim() for ax in axes]
        tops = [extr[1] / (extr[1] - extr[0]) for extr in extrema]
        # Ensure that plots (intervals) are ordered bottom to top:
        if tops[0] > tops[1]:
            axes, extrema, tops = [list(reversed(l))
                                   for l in (axes, extrema, tops)]

        # How much would the plot overflow if we kept current zoom levels?
        tot_span = tops[1] + 1 - tops[0]

        b_new_t = extrema[0][0] + tot_span * (extrema[0][1] - extrema[0][0])
        t_new_b = extrema[1][1] - tot_span * (extrema[1][1] - extrema[1][0])
        axes[0].set_xlim(extrema[0][0], b_new_t)
        axes[1].set_xlim(t_new_b, extrema[1][1])
Exemple #27
0
class FETriangularMesh(bu.Model):
    name = 'FETriangularMesh'

    X_Id = tr.Array(np.float_,
                    value=[[0, 0, 0], [2, 0, 0], [2, 2, 0], [1, 1, 0]])
    I_Fi = tr.Array(np.int_, value=[
        [0, 1, 3],
        [1, 2, 3],
    ])

    fets = tr.Instance(FETSEval)

    def _fets_default(self):
        return FETS2D3U1M()

    show_node_labels = bu.Bool(False)

    n_nodal_dofs = tr.DelegatesTo('fets')
    dof_offset = tr.Int(0)

    n_active_elems = tr.Property

    def _get_n_active_elems(self):
        return len(self.I_Fi)

    ipw_view = bu.View(bu.Item('show_node_labels'), )

    #=========================================================================
    # 3d Visualization
    #=========================================================================
    plot_backend = 'k3d'
    show_wireframe = bu.Bool(True)

    def setup_plot(self, pb):
        X_Id = self.X_Id.astype(np.float32)
        I_Fi = self.I_Fi.astype(np.uint32)

        fe_mesh = k3d.mesh(X_Id,
                           I_Fi,
                           color=0x999999,
                           opacity=1.0,
                           side='double')
        pb.plot_fig += fe_mesh
        pb.objects['mesh'] = fe_mesh

        if self.show_wireframe:
            k3d_mesh_wireframe = k3d.mesh(X_Id,
                                          I_Fi,
                                          color=0x000000,
                                          wireframe=True)
            pb.plot_fig += k3d_mesh_wireframe
            pb.objects['mesh_wireframe'] = k3d_mesh_wireframe

        if self.show_node_labels:
            self._add_nodes_labels_to_fig(pb, X_Id)

    NODES_LABELS = 'nodes_labels'

    def update_plot(self, pb):
        X_Id = self.X_Id.astype(np.float32)
        I_Fi = self.I_Fi.astype(np.uint32)

        mesh = pb.objects['mesh']
        mesh.vertices = X_Id
        mesh.indices = I_Fi
        if self.show_wireframe:
            wireframe = pb.objects['mesh_wireframe']
            wireframe.vertices = X_Id
            wireframe.indices = I_Fi

        if self.show_node_labels:
            if self.NODES_LABELS in pb.objects:
                pb.clear_object(self.NODES_LABELS)
            self._add_nodes_labels_to_fig(pb, X_Id)
        else:
            if self.NODES_LABELS in pb.objects:
                pb.clear_object(self.NODES_LABELS)

    def _add_nodes_labels_to_fig(self, pb, X_Id):
        text_list = []
        for I, X_d in enumerate(X_Id):
            k3d_text = k3d.text('%g' % I,
                                tuple(X_d),
                                label_box=False,
                                size=0.8,
                                color=0x00FF00)
            pb.plot_fig += k3d_text
            text_list.append(k3d_text)
        pb.objects[self.NODES_LABELS] = text_list
Exemple #28
0
class FETS2DMITC(FETSEval):
    r'''MITC3 shell finite element:
        See https://www.sesamx.io/blog/standard_linear_triangular_shell_element/
        See http://dx.doi.org/10.1016/j.compstruc.2014.02.005
    '''

    vtk_r = tr.Array(np.float_, value=[[1, 0, 0], [0, 1, 0], [0, 0, 1]])
    vtk_cells = [[0, 1, 2]]
    vtk_cell_types = 'Triangle'
    vtk_cell = [0, 1, 2]
    vtk_cell_type = 'Triangle'

    vtk_expand_operator = tr.Array(np.float_, value=DELTA23_ab)

    # =========================================================================
    # Surface integrals using numerical integration
    # =========================================================================
    # i is point indices, p is point coords in natural coords (zeta_1, zeta_2, zeta_3)
    eta_ip = tr.Array('float_')
    r'''Integration points within a triangle.
    '''
    def _eta_ip_default(self):
        # We applay the 7-point Gauss integration to integrate exactly on the plane defined by rr and ss
        # [r, s, t] at each Gauss point (r, s, t) are natural coords in the shell element r,s in plane
        # and t along thickness
        # 2 Gauss points along thickness t
        # 7 Gauss points on the plane of the element
        return np.array([[0.1012865073235, 0.1012865073235, -0.5773502691896],
                         [0.7974269853531, 0.1012865073235, -0.5773502691896],
                         [0.1012865073235, 0.7974269853531, -0.5773502691896],
                         [0.4701420641051, 0.0597158717898, -0.5773502691896],
                         [0.4701420641051, 0.4701420641051, -0.5773502691896],
                         [0.0597158717898, 0.4701420641051, -0.5773502691896],
                         [0.3333333333333, 0.3333333333333, -0.5773502691896],
                         [0.1012865073235, 0.1012865073235, 0.5773502691896],
                         [0.7974269853531, 0.1012865073235, 0.5773502691896],
                         [0.1012865073235, 0.7974269853531, 0.5773502691896],
                         [0.4701420641051, 0.0597158717898, 0.5773502691896],
                         [0.4701420641051, 0.4701420641051, 0.5773502691896],
                         [0.0597158717898, 0.4701420641051, 0.5773502691896],
                         [0.3333333333333, 0.3333333333333, 0.5773502691896]],
                        dtype='f')

    w_m = tr.Array('float_')
    r'''Weight factors for numerical integration.
    '''

    def _w_m_default(self):
        return np.array([
            0.0629695902724, 0.0629695902724, 0.0629695902724, 0.0661970763943,
            0.0661970763943, 0.0661970763943, 0.1125, 0.0629695902724,
            0.0629695902724, 0.0629695902724, 0.0661970763943, 0.0661970763943,
            0.0661970763943, 0.1125
        ],
                        dtype='f')

    # TODO, different node thickness in each node according to the original
    #  implementation can be easily integrated, but here the same thickness
    #  is used for simplicity.
    a = tr.Float(1.0, label='thickness')

    n_m = tr.Property(depends_on='w_m')
    r'''Number of integration points.
    '''

    @tr.cached_property
    def _get_n_m(self):
        return len(self.w_m)

    n_nodal_dofs = tr.Int(5)

    N_im = tr.Property(depends_on='eta_ip')
    r'''Shape function values in integration points.
    '''

    @tr.cached_property
    def _get_N_im(self):
        # Shouldn't be mi instead of im?
        eta = self.eta_ip
        return np.array([1 - eta[:, 0] - eta[:, 1], eta[:, 0], eta[:, 1]],
                        dtype='f')

    dh_imr = tr.Property(depends_on='eta_ip')
    r'''Derivatives of the shape functions in the integration points.
    '''

    @tr.cached_property
    def _get_dh_imr(self):
        # Same for all Gauss points
        dh_ri = np.array(
            [
                [-1, 1, 0],  # dh1/d_r, dh2/d_r, dh3/d_r
                [-1, 0, 1],  # dh1/d_s, dh2/d_s, dh3/d_s
                [0, 0, 0]
            ],  # dh1/d_t, dh2/d_t, dh3/d_t
            dtype=np.float_)
        dh_mri = np.tile(dh_ri, (self.n_m, 1, 1))

        return np.einsum('mri->imr', dh_mri)

    dht_imr = tr.Property(depends_on='eta_ip')
    r'''Derivatives of the (shape functions * t) in the integration points.
    '''

    @tr.cached_property
    def _get_dht_imr(self):
        # m: gauss points, r: r, s, t, and i: h1, h2, h3
        eta_ip = self.eta_ip
        dh_mri = np.array(
            [
                [
                    [-t, t, 0],  # (t*dh1)/d_r, (t*dh2)/d_r, (t*dh3)/d_r
                    [-t, 0, t],  # (t*dh1)/d_s, (t*dh2)/d_s, (t*dh3)/d_s
                    [1 - r - s, r, s]
                ]  # (t*dh1)/d_t, (t*dh2)/d_t, (t*dh3)/d_t
                for r, s, t in zip(eta_ip[:, 0], eta_ip[:, 1], eta_ip[:, 2])
            ],
            dtype=np.float_)
        return np.einsum('mri->imr', dh_mri)

    dh_inr = tr.Property(depends_on='eta_ip')
    r'''Derivatives of the shape functions in the integration points.
    '''

    @tr.cached_property
    def _get_dh_inr(self):
        return self.dh_imr

    def get_B(self):
        pass

    vtk_expand_operator = tr.Array(value=[1, 1, 0])
    vtk_node_cell_data = tr.Array
    vtk_ip_cell_data = tr.Array
class FETS2D4u4x(FETSEval):
    dof_r = tr.Array(value=[[-1, -1], [1, -1], [1, 1], [-1, 1]])
    geo_r = tr.Array(value=[[-1, -1], [1, -1], [1, 1], [-1, 1]])
    vtk_r = [[-1, -1], [1, -1], [1, 1], [-1, 1]]
    n_nodal_dofs = 2
Exemple #30
0
class MKappa(InteractiveModel, InjectSymbExpr):
    """Class returning the moment curvature relationship."""
    name = 'Moment-Curvature'

    symb_class = MKappaSymbolic
    cs_design = Instance(CrossSectionDesign, ())

    tree = ['cs_design']
    # Use PrototypedFrom only when the prototyped object is a class
    # (The prototyped attribute behaves similarly
    # to a delegated attribute, until it is explicitly
    # changed; from that point forward, the prototyped attribute
    # changes independently from its prototype.)
    # (it's kind of like tr.DelegatesTo('cs_design.cross_section_shape'))
    cross_section_shape = tr.DelegatesTo('cs_design')
    cross_section_shape_ = tr.DelegatesTo('cs_design')
    cross_section_layout = tr.DelegatesTo('cs_design')
    matrix_ = tr.DelegatesTo('cs_design')

    # Geometry
    H = tr.DelegatesTo('cross_section_shape_')

    DEPSTR = 'state_changed'

    n_m = Int(
        100,
        DSC=True,
        desc=
        'Number of discretization points along the height of the cross-section'
    )

    # @todo: fix the dependency - `H` should be replaced by _GEO
    z_m = tr.Property(depends_on=DEPSTR)

    @tr.cached_property
    def _get_z_m(self):
        return np.linspace(0, self.H, self.n_m)

    low_kappa = Float(0.0, BC=True, GEO=True)
    high_kappa = Float(0.00002, BC=True, GEO=True)
    n_kappa = Int(100, BC=True)
    step_kappa = tr.Property(Float, depends_on='low_kappa, high_kappa')

    @tr.cached_property
    def _get_step_kappa(self):
        return float((self.high_kappa - self.low_kappa) / self.n_kappa)

    kappa_slider = Float(0.0000001)

    ipw_view = View(
        Item(
            'low_kappa',
            latex=r'\text{Low}~\kappa'),  #, editor=FloatEditor(step=0.00001)),
        Item('high_kappa', latex=r'\text{High}~\kappa'
             ),  # , editor=FloatEditor(step=0.00001)),
        Item('n_kappa', latex='n_{\kappa}'),
        Item('plot_strain'),
        Item('solve_for_eps_bot_pointwise'),
        Item('n_m', latex='n_m'),
        Item('kappa_slider', latex='\kappa', readonly=True),
        # editor=FloatRangeEditor(low_name='low_kappa',
        #                         high_name='high_kappa',
        #                         n_steps_name='n_kappa')
        # ),
        time_editor=HistoryEditor(
            var='kappa_slider',
            min_var='low_kappa',
            max_var='high_kappa',
        ),
    )

    idx = tr.Property(depends_on='kappa_slider')

    apply_material_safety_factors = tr.Bool(False)

    @tr.cached_property
    def _get_idx(self):
        ks = self.kappa_slider
        idx = np.argmax(ks <= self.kappa_t)
        return idx

    kappa_t = tr.Property(tr.Array(np.float_), depends_on=DEPSTR)
    '''Curvature values for which the bending moment must be found
    '''

    @tr.cached_property
    def _get_kappa_t(self):
        return np.linspace(self.low_kappa, self.high_kappa, self.n_kappa)

    z_j = tr.Property

    def _get_z_j(self):
        return self.cross_section_layout.z_j

    A_j = tr.Property

    def _get_A_j(self):
        return self.cross_section_layout.A_j

    # Normal force in steel (tension and compression)
    def get_N_s_tj(self, kappa_t, eps_bot_t):
        # get the strain at the height of the reinforcement
        eps_z_tj = self.symb.get_eps_z(kappa_t[:, np.newaxis],
                                       eps_bot_t[:, np.newaxis],
                                       self.z_j[np.newaxis, :])
        # Get the crack bridging force in each reinforcement layer
        # given the corresponding crack-bridge law.
        N_s_tj = self.cross_section_layout.get_N_tj(eps_z_tj)
        return N_s_tj

    # TODO - [RC] avoid repeated evaluations of stress profile in
    #            N and M calculations for the same inputs as it
    #            is the case now.
    def get_sig_c_z(self, kappa_t, eps_bot_t, z_tm):
        """Get the stress profile over the height"""
        eps_z = self.symb.get_eps_z(kappa_t[:, np.newaxis],
                                    eps_bot_t[:, np.newaxis], z_tm)
        sig_c_z = self.matrix_.get_sig(eps_z)
        return sig_c_z

    # Normal force in concrete (tension and compression)
    def get_N_c_t(self, kappa_t, eps_bot_t):
        z_tm = self.z_m[np.newaxis, :]
        b_z_m = self.cross_section_shape_.get_b(z_tm)
        N_z_tm2 = b_z_m * self.get_sig_c_z(kappa_t, eps_bot_t, z_tm)
        return np.trapz(N_z_tm2, x=z_tm, axis=-1)

    def get_N_t(self, kappa_t, eps_bot_t):
        N_s_t = np.sum(self.get_N_s_tj(kappa_t, eps_bot_t), axis=-1)
        N_c_t = self.get_N_c_t(kappa_t, eps_bot_t)
        return N_c_t + N_s_t

    # SOLVER: Get eps_bot to render zero force

    # num_of_trials = tr.Int(30)

    eps_bot_t = tr.Property(depends_on=DEPSTR)
    r'''Resolve the tensile strain to get zero normal force for the prescribed curvature'''

    # @tr.cached_property
    # def _get_eps_bot_t(self):
    #     initial_step = (self.high_kappa - self.low_kappa) / self.num_of_trials
    #     for i in range(self.num_of_trials):
    #         print('Solution started...')
    #         res = root(lambda eps_bot_t: self.get_N_t(self.kappa_t, eps_bot_t),
    #                    0.0000001 + np.zeros_like(self.kappa_t), tol=1e-6)
    #         if res.success:
    #             print('success high_kappa: ', self.high_kappa)
    #             if i == 0:
    #                 print('Note: high_kappa success from 1st try! selecting a higher value for high_kappa may produce '
    #                       'a more reliable result!')
    #             return res.x
    #         else:
    #             print('failed high_kappa: ', self.high_kappa)
    #             self.high_kappa -= initial_step
    #             self.kappa_t = np.linspace(self.low_kappa, self.high_kappa, self.n_kappa)
    #
    #     print('No solution', res.message)
    #     return res.x

    # @tr.cached_property
    # def _get_eps_bot_t(self):
    #     res = root(lambda eps_bot_t: self.get_N_t(self.kappa_t, eps_bot_t),
    #                0.0000001 + np.zeros_like(self.kappa_t), tol=1e-6)
    #     if not res.success:
    #         raise SolutionNotFoundError('No solution', res.message)
    #     return res.x

    solve_for_eps_bot_pointwise = Bool(True, BC=True, GEO=True)

    @tr.cached_property
    def _get_eps_bot_t(self):
        if self.solve_for_eps_bot_pointwise:
            """ INFO: Instability in eps_bot solutions was caused by unsuitable init_guess value causing a convergence 
            to non-desired solutions. Solving the whole kappa_t array improved the init_guess after each
            calculated value, however, instability still there. The best results were obtained by taking the last 
            solution as the init_guess for the next solution like in the following.. """
            # One by one solution for kappa values
            eps_bot_sol_for_pos_kappa = self._get_eps_bot_piecewise_sol(
                kappa_pos=True)
            eps_bot_sol_for_neg_kappa = self._get_eps_bot_piecewise_sol(
                kappa_pos=False)
            res = np.concatenate(
                [eps_bot_sol_for_neg_kappa, eps_bot_sol_for_pos_kappa])
            return res
        else:
            # Array solution for the whole kappa_t
            res = root(lambda eps_bot_t: self.get_N_t(self.kappa_t, eps_bot_t),
                       0.0000001 + np.zeros_like(self.kappa_t),
                       tol=1e-6)
            if not res.success:
                print('No solution', res.message)
            return res.x

    def _get_eps_bot_piecewise_sol(self, kappa_pos=True):
        if kappa_pos:
            kappas = self.kappa_t[np.where(self.kappa_t >= 0)]
        else:
            kappas = self.kappa_t[np.where(self.kappa_t < 0)]

        res = []
        if kappa_pos:
            init_guess = 0.00001
            kappa_loop_list = kappas
        else:
            init_guess = -0.00001
            kappa_loop_list = reversed(kappas)

        for kappa in kappa_loop_list:
            sol = root(
                lambda eps_bot: self.get_N_t(np.array([kappa]), eps_bot),
                np.array([init_guess]),
                tol=1e-6).x[0]

            # This condition is to avoid having init_guess~0 which causes non-convergence
            if abs(sol) > 1e-5:
                init_guess = sol
            res.append(sol)

        if kappa_pos:
            return res
        else:
            return list(reversed(res))

    # POSTPROCESSING
    kappa_cr = tr.Property(depends_on=DEPSTR)
    '''Curvature at which a critical strain is attained at the eps_bot'''

    @tr.cached_property
    def _get_kappa_cr(self):
        res = root(lambda kappa: self.get_N_t(kappa, self.eps_cr),
                   0.0000001 + np.zeros_like(self.eps_cr),
                   tol=1e-10)
        if not res.success:
            print('No kappa_cr solution (for plot_norm() function)',
                  res.message)
        return res.x

    M_s_t = tr.Property(depends_on=DEPSTR)
    '''Bending moment (steel)
    '''

    @tr.cached_property
    def _get_M_s_t(self):
        if len(self.z_j) == 0:
            return np.zeros_like(self.kappa_t)

        eps_z_tj = self.symb.get_eps_z(self.kappa_t[:, np.newaxis],
                                       self.eps_bot_t[:, np.newaxis],
                                       self.z_j[np.newaxis, :])

        # Get the crack bridging force in each reinforcement layer
        # given the corresponding crack-bridge law.
        N_tj = self.cross_section_layout.get_N_tj(eps_z_tj)
        return -np.einsum('tj,j->t', N_tj, self.z_j)

    M_c_t = tr.Property(depends_on=DEPSTR)
    '''Bending moment (concrete)
    '''

    @tr.cached_property
    def _get_M_c_t(self):
        z_tm = self.z_m[np.newaxis, :]
        b_z_m = self.cross_section_shape_.get_b(z_tm)
        N_z_tm2 = b_z_m * self.get_sig_c_z(self.kappa_t, self.eps_bot_t, z_tm)
        return -np.trapz(N_z_tm2 * z_tm, x=z_tm, axis=-1)

    M_t = tr.Property(depends_on=DEPSTR)
    '''Bending moment
    '''

    @tr.cached_property
    def _get_M_t(self):
        # print('M - k recalculated')
        eta_factor = 1.
        return eta_factor * (self.M_c_t + self.M_s_t)

    # @tr.cached_property
    # def _get_M_t(self):
    #     initial_step = (self.high_kappa - self.low_kappa) / self.num_of_trials
    #     for i in range(self.num_of_trials):
    #         try:
    #             M_t = self.M_c_t + self.M_s_t
    #         except SolutionNotFoundError:
    #             print('failed high_kappa: ', self.high_kappa)
    #             self.high_kappa -= initial_step
    #         else:
    #             # This will run when no exception has been received
    #             print('success high_kappa: ', self.high_kappa)
    #             if i == 0:
    #                 print('Note: high_kappa success from 1st try! selecting a higher value for high_kappa may produce '
    #                       'a more reliable result!')
    #             return M_t
    #     print('No solution has been found!')
    #     return M_t

    N_s_tj = tr.Property(depends_on=DEPSTR)
    '''Normal forces (steel)
    '''

    @tr.cached_property
    def _get_N_s_tj(self):
        return self.get_N_s_tj(self.kappa_t, self.eps_bot_t)

    eps_tm = tr.Property(depends_on=DEPSTR)
    '''strain profiles
    '''

    @tr.cached_property
    def _get_eps_tm(self):
        return self.symb.get_eps_z(self.kappa_t[:, np.newaxis],
                                   self.eps_bot_t[:, np.newaxis],
                                   self.z_m[np.newaxis, :])

    sig_tm = tr.Property(depends_on=DEPSTR)
    '''strain profiles
    '''

    @tr.cached_property
    def _get_sig_tm(self):
        return self.get_sig_c_z(self.kappa_t, self.eps_bot_t,
                                self.z_m[np.newaxis, :])

    M_norm = tr.Property(depends_on=DEPSTR)
    '''
    '''

    @tr.cached_property
    def _get_M_norm(self):
        # Section modulus @TODO optimize W for var b
        W = (self.b * self.H**2) / 6
        sig_cr = self.E_ct * self.eps_cr
        return W * sig_cr

    kappa_norm = tr.Property()

    def _get_kappa_norm(self):
        return self.kappa_cr

    inv_M_kappa = tr.Property(depends_on=DEPSTR)
    '''Return the inverted data points
    '''

    @tr.cached_property
    def _get_inv_M_kappa(self):
        try:
            """cut off the descending tails"""
            M_t = self.M_t
            I_max = np.argmax(M_t)
            I_min = np.argmin(M_t)
            M_I = np.copy(M_t[I_min:I_max + 1])
            kappa_I = np.copy(self.kappa_t[I_min:I_max + 1])
            # find the index corresponding to zero kappa
            idx = np.argmax(0 <= kappa_I)
            # and modify the values such that the
            # Values of moment are non-descending
            M_plus = M_I[idx:]
            M_diff = M_plus[:, np.newaxis] - M_plus[np.newaxis, :]
            n_ij = len(M_plus)
            ij = np.mgrid[0:n_ij:1, 0:n_ij:1]
            M_diff[np.where(ij[1] >= ij[0])] = 0
            i_x = np.argmin(M_diff, axis=1)
            M_I[idx:] = M_plus[i_x]
            return M_I, kappa_I
        except ValueError:
            print(
                'M inverse has not succeeded, the M-Kappa solution may have failed due to '
                'a wrong kappa range or not suitable material law!')
            return np.array([0]), np.array([0])

    def get_kappa_M(self, M):
        M_I, kappa_I = self.inv_M_kappa
        return np.interp(M, M_I, kappa_I)

    def plot_norm(self, ax1, ax2):
        idx = self.idx
        ax1.plot(self.kappa_t / self.kappa_norm, self.M_t / self.M_norm)
        ax1.plot(self.kappa_t[idx] / self.kappa_norm,
                 self.M_t[idx] / self.M_norm,
                 marker='o')
        ax2.barh(self.z_j,
                 self.N_s_tj[idx, :],
                 height=2,
                 color='red',
                 align='center')
        # ax2.fill_between(eps_z_arr[idx,:], z_arr, 0, alpha=0.1);
        ax3 = ax2.twiny()
        #  ax3.plot(self.eps_tm[idx, :], self.z_m, color='k', linewidth=0.8)
        ax3.plot(self.sig_tm[idx, :], self.z_m)
        ax3.axvline(0, linewidth=0.8, color='k')
        ax3.fill_betweenx(self.z_m, self.sig_tm[idx, :], 0, alpha=0.1)
        mpl_align_xaxis(ax2, ax3)

    M_scale = Float(1e+6)
    plot_strain = Bool(False)

    def plot(self, ax1, ax2, ax3):
        self.plot_mk_and_stress_profile(ax1, ax2)
        if self.plot_strain:
            self.plot_strain_profile(ax3)
        else:
            self.plot_mk_inv(ax3)

    @staticmethod
    def subplots(fig):
        ax1, ax2, ax3 = fig.subplots(1, 3)
        return ax1, ax2, ax3

    def update_plot(self, axes):
        self.plot(*axes)

    def plot_mk_inv(self, ax3):
        try:
            M, kappa = self.inv_M_kappa
            ax3.plot(M / self.M_scale, kappa)
        except ValueError:
            print(
                'M inverse has not succeeded, the M-Kappa solution may have failed due to a wrong kappa range!'
            )

        ax3.set_xlabel('Moment [kNm]')
        ax3.set_ylabel('Curvature[mm$^{-1}$]')

    def plot_mk_and_stress_profile(self, ax1, ax2):
        self.plot_mk(ax1)
        idx = self.idx
        ax1.plot(self.kappa_t[idx],
                 self.M_t[idx] / self.M_scale,
                 color='orange',
                 marker='o')

        if len(self.z_j):
            ax2.barh(self.z_j,
                     self.N_s_tj[idx, :] / self.A_j,
                     height=4,
                     color='red',
                     align='center')
            ax2.set_ylabel('z [mm]')
            ax2.set_xlabel('$\sigma_r$ [MPa]')

        ax22 = ax2.twiny()
        ax22.set_xlabel('$\sigma_c$ [MPa]')
        ax22.plot(self.sig_tm[idx, :], self.z_m)
        ax22.axvline(0, linewidth=0.8, color='k')
        ax22.fill_betweenx(self.z_m, self.sig_tm[idx, :], 0, alpha=0.1)
        mpl_align_xaxis(ax2, ax22)

    def plot_mk(self, ax1):
        ax1.plot(self.kappa_t, self.M_t / self.M_scale, label='M-K')
        ax1.set_ylabel('Moment [kNm]')
        ax1.set_xlabel('Curvature [mm$^{-1}$]')
        ax1.legend()

    def plot_strain_profile(self, ax):
        ax.set_ylabel('z [mm]')
        ax.set_xlabel(r'$\varepsilon$ [-]')
        ax.plot(self.eps_tm[self.idx, :], self.z_m)
        ax.axvline(0, linewidth=0.8, color='k')
        ax.fill_betweenx(self.z_m, self.eps_tm[self.idx, :], 0, alpha=0.1)

    def get_mk(self):
        return self.M_t / self.M_scale, self.kappa_t