Exemple #1
0
class INotificationListenerFactory(IFactory):
    """Envisage required interface for the BaseNotificationListenerFactory.
    You should not need to use this directly.

    Refer to the BaseNotificationListenerFactory for documentation.
    """
    listener_class = Type(
        "force_bdss.notification_listeners"
        ".base_notification_listener.BaseNotificationListener",
        allow_none=False,
    )

    model_class = Type(
        "force_bdss.notification_listeners"
        ".base_notification_listener_model.BaseNotificationListenerModel",
        allow_none=False)

    def get_model_class(self):
        """
        :return: model class.
        """

    def get_listener_class(self):
        """
        :return: listener class.
        """

    def create_listener(self):
        """
        :return: listener.
        """

    def create_model(self):
        """
Exemple #2
0
class ObjectFactory(HasStrictTraits):
    """ A factory with metadata.
    """

    # A unique ID identifying the factory.
    id = Str()

    # A short, user-visible name for the object.
    name = Unicode()

    # A longer, user-visible description for the object.
    description = Unicode()

    # The type of the object.
    type = Type()

    # An Enaml UI for editing the object. The object will be passed to widget
    # via the 'obj' attribute.
    ui = Type('enaml.widgets.widget.Widget')

    # A factory for creating new instances of the object.
    # If not specified, objects are created by invoking the type constructor.
    factory = Callable()

    def create(self, *args, **kwds):
        """ Create an instance of the object.
        """
        if self.factory:
            return self.factory(*args, **kwds)
        elif self.type:
            return self.type(*args, **kwds)
        else:
            raise RuntimeError('Cannot construct object from factory')
Exemple #3
0
class IDataSourceFactory(IFactory):
    """Envisage required interface for the BaseDataSourceFactory.
    You should not need to use this directly.

    Refer to the BaseDataSourceFactory for documentation.
    """
    data_source_class = Type(
        "force_bdss.data_sources.base_data_source.BaseDataSource",
        allow_none=False)

    model_class = Type(
        "force_bdss.data_sources.base_data_source_model.BaseDataSourceModel",
        allow_none=False)

    def get_data_source_class(self):
        """
        :return: data source class.
        """

    def get_model_class(self):
        """
        :return: model class.
        """

    def create_data_source(self):
        """Returns an instance of subclass BaseDataSource
        """

    def create_model(self):
        """Returns an instance of subclass BaseDataSourceModel
class IMultiImageFactory(Interface):

    label = Str

    multi_image_class = Type(IMultiImage)

    reader_class = Type(IMultiImageReader)

    analyser_class = Type(IMultiImageAnalyser)

    parser_class = Type(IFileParser)

    viewer_class = Type(IMultiImageViewer)

    def get_label(self):
        """Returns key associated with this factory"""

    def get_multi_image(self):
        """Returns BaseMultiImage associated with this factory"""

    def get_reader(self):
        """Returns list of IMultiImageReader classes able to load
        the IMultiImage class created by this factory"""

    def get_analyser(self):
        """Returns list of IMultiImageAnalyser classes able to analyse
        the IMultiImage class created by this factory"""

    def get_parser(self):
        """Returns list of IFileParser classes able to parse files
        that are used to load the IMultiImage class created by
        this factory"""

    def get_viewer(self):
        """Returns list of IMultiImageViewer classes able to display
Exemple #5
0
class BaseNotificationListenerFactory(BaseFactory):
    """Base class for notification listeners.
    Notification listeners are extensions that receive event notifications
    from the MCO and perform an associated action.
    """
    #: The listener class that must be instantiated. Define this to your
    #: listener class.
    listener_class = Type(BaseNotificationListener, allow_none=False)

    #: The associated model to the listener. Define this to your
    #: listener model class.
    model_class = Type(BaseNotificationListenerModel, allow_none=False)

    def __init__(self, plugin, *args, **kwargs):
        """Initializes the instance.

        Parameters
        ----------
        plugin: Plugin
            The plugin that holds this factory.
        """
        super(BaseNotificationListenerFactory, self).__init__(plugin=plugin,
                                                              *args,
                                                              **kwargs)

        self.listener_class = self.get_listener_class()
        self.model_class = self.get_model_class()

    def get_listener_class(self):
        raise NotImplementedError(
            "get_listener_class was not implemented in factory {}".format(
                self.__class__))

    def get_model_class(self):
        raise NotImplementedError(
            "get_model_class was not implemented in factory {}".format(
                self.__class__))

    def create_listener(self):
        """
        Creates an instance of the listener.
        """
        return self.listener_class(self)

    def create_model(self, model_data=None):
        """
        Creates an instance of the model.

        Parameters
        ----------
        model_data: dict
            Data to use to fill the model.
        """
        if model_data is None:
            model_data = {}

        return self.model_class(self, **model_data)
Exemple #6
0
class IMCOFactory(IFactory):
    """Interface for the BaseMCOFactory.
    You should not need it, as its main use is for envisage support.

    Refer to BaseMCOFactory for documentation
    """
    optimizer_class = Type("force_bdss.mco.base_mco.BaseMCO", allow_none=False)

    model_class = Type(
        "force_bdss.mco.base_mco_communicator.BaseMCOCommunicator",
        allow_none=False)

    communicator_class = Type("force_bdss.mco.base_mco_model.BaseMCOModel",
                              allow_none=False)

    parameter_factory_classes = List(
        Type("force_bdss.mco.parameters.i_mco_parameter_factory"
             ".IMCOParameterFactory"))

    def get_model_class(self):
        """
        :return: model class.
        """

    def get_communicator_class(self):
        """
        :return: model communicator class.
        """

    def get_optimizer_class(self):
        """
        :return: optimizer class
        """

    def get_parameter_factory_classes(self):
        """Returns a list of classes that provide the
        IMCOParameterFactory interface"""

    def create_optimizer(self):
        """
        :return: optimizer
        """

    def create_model(self):
        """
        :return: model
        """

    def create_communicator(self):
        """
class IMultiImageReader(Interface):
    """File reader that loads a stack of Tiff images, represented
    by a IMultiImage subclass"""

    _supported_file_sets = List(IFileSet)

    _multi_image_class = Type(IMultiImage)

    def load_multi_image(self, file_set):
        """Image loader for MultiImage classes"""

    def get_supported_file_sets(self):
        """Returns class of IFileSets that will be supported."""

    def get_filenames(self, file_set):
        """From a collection of files in a FileSet, yield each file that
        should be used
        """

    def create_image_stack(self, filenames):
        """Return a list of numpy arrays suitable for the
        loader's IMultiImage type"""

    def load_image(self, filename):
        """Load a single image from a file"""

    def can_load(self, filename):
        """Perform check to see whether file is formatted
Exemple #8
0
class FieldAction(Action):
    """ A widget action containing an IField

    When the value in the field is changed, the `on_perform` method is called
    with the new value as the argument.
    """

    #: This is a widget action.
    style = Constant("widget")

    #: The field to display.
    field_type = Type(IField)

    #: The default trait values for the field.
    field_defaults = Dict(Str, Any)

    def create_control(self, parent):
        """ Called when creating a "widget" style action.

        This constructs an IField-based control directly and binds changes to
        the value to the `value_updated` method.

        Parameters
        ----------
        parent : toolkit control
            The toolkit control, usually a toolbar.

        Returns
        -------
        control : toolkit control
            A toolkit control or None.
        """
        field = self.field_type(parent=parent, **self.field_defaults)
        field._create()
        field.observe(self.value_updated, "value")
        field.control._field = field
        return field.control

    def value_updated(self, event):
        """ Handle changes to the field value by calling perform.

        The event passed to `perform` has the `value` as an attribute.
        """
        value = event.new
        action_event = ActionEvent(value=value)
        self.perform(action_event)

    def perform(self, event):
        """ Performs the action.

        This dispacthes to the on_perform method with the new value passed
        as an argument.

        Parameters
        ----------
        event : ActionEvent instance
            The event which triggered the action.
        """
        if self.on_perform is not None:
            self.on_perform(event.value)
Exemple #9
0
class BaseMCOParameterFactory(BaseFactory):
    """Factory that produces the model instance of a given BaseMCOParameter
    instance.

    Must be reimplemented for the specific parameter. The generic create_model
    is generally enough, and the only entity to define is model_class with
    the appropriate class of the parameter.
    """

    #: A reference to the MCO factory this parameter factory lives in.
    mco_factory = Instance('force_bdss.mco.base_mco_factory.BaseMCOFactory',
                           allow_none=False)

    # The model class to instantiate when create_model is called.
    model_class = Type(
        "force_bdss.mco.parameters.base_mco_parameter.BaseMCOParameter",
        allow_none=False)

    def __init__(self, mco_factory, *args, **kwargs):
        super(BaseMCOParameterFactory, self).__init__(plugin={
            'id':
            mco_factory.plugin_id,
            'name':
            mco_factory.plugin_name
        },
                                                      mco_factory=mco_factory,
                                                      *args,
                                                      **kwargs)

        self.model_class = self.get_model_class()

    def get_model_class(self):
        raise NotImplementedError(
            "get_model_class was not implemented in factory {}".format(
                self.__class__))

    def create_model(self, data_values=None):
        """Creates the instance of the model class and returns it.
        You should not reimplement this, as the default is generally ok.
        Instead, just define model_class with the appropriate Parameter class.

        Parameters
        ----------
        data_values: dict or None
            The dictionary of values for this parameter. If None, a default
            object will be returned.

        Returns
        -------
        instance of model_class.
        """
        if data_values is None:
            data_values = {}

        return self.model_class(self, **data_values)

    def _global_id(self, identifier):
        return mco_parameter_id(self.mco_factory.id, identifier)
Exemple #10
0
class ToolbarPlot(Plot):
    #: Should we turn on the auto-hide feature on the toolbar?
    auto_hide = DelegatesTo('toolbar')

    toolbar = Instance(PlotToolbar)

    toolbar_class = Type(PlotToolbar)
    toolbar_added = False

    #: Location of the default toolbar that is created if a toolbar
    #: is not specified with the `toolbar` attribute.  Changing this
    #: attribute after the ToolbarPlot instance is created has no effect;
    #: use obj.toolbar.location to dynamically change the location of the
    #: instance `obj`s toolbar.
    toolbar_location = Enum('top', 'right', 'bottom', 'left')

    def __init__(self, *args, **kw):

        # initialize the toolbar class before super() has a chance to create
        # the default using the default class. This can happen because of
        # ordering issues

        if "toolbar_class" in kw:
            self.toolbar_class = kw.pop("toolbar_class")

        super(ToolbarPlot, self).__init__(*args, **kw)

        self.toolbar.component = self
        self.add_toolbar()

    def _toolbar_default(self):
        return self.toolbar_class(self, location=self.toolbar_location)

    def add_toolbar(self):
        if not self.toolbar_added:
            self.overlays.append(self.toolbar)
            self.toolbar_added = True
            self.request_redraw()

    def remove_toolbar(self):
        if self.toolbar_added and self.auto_hide:
            self.overlays.remove(self.toolbar)
            self.toolbar_added = False
            self.request_redraw()

    def _bounds_changed(self, old, new):
        self.toolbar.do_layout(force=True)
        super(ToolbarPlot, self)._bounds_changed(old, new)

    @on_trait_change('toolbar')
    def _toolbar_changed(self, name, obj, old, new):
        if self.toolbar_added:
            # fixup the new toolbar's component to match the old one
            new.component = old.component

            self.overlays.remove(old)
            self.toolbar_added = False
            self.add_toolbar()
Exemple #11
0
class ImageEnumEditor(EnumEditor):
    """ Editor factory for image enumeration editors.
    """

    # -------------------------------------------------------------------------
    #  Trait definitions:
    # -------------------------------------------------------------------------
    #: Prefix to add to values to form image names:
    prefix = Str()

    #: Suffix to add to values to form image names:
    suffix = Str()

    #: Path to use to locate image files:
    path = Str()

    #: Class used to derive the path to the image files:
    klass = Type()

    #: Module used to derive the path to the image files:
    module = Module

    def init(self):
        """ Performs any initialization needed after all constructor traits
            have been set.
        """
        super().init()
        self._update_path()

    @observe("path, klass, module")
    def _update_path(self, event=None):
        """ Handles one of the items defining the path being updated.
        """
        if self.path != "":
            self._image_path = self.path
        elif self.klass is not None:
            module = self.klass.__module__
            if module == "___main___":
                module = "__main__"
            try:
                self._image_path = join(
                    dirname(sys.modules[module].__file__), "images"
                )
            except:
                self._image_path = self.path
                dirs = [
                    join(dirname(sys.argv[0]), "images"),
                    join(getcwd(), "images"),
                ]
                for d in dirs:
                    if exists(d):
                        self._image_path = d
                        break
        elif self.module is not None:
            self._image_path = join(dirname(self.module.__file__), "images")
Exemple #12
0
class ModelTreeItem(HasStrictTraits):
    """ An item within a ModelTree. Used to compose the data for the model
    tree view.
    """
    title = Unicode()
    icon = Instance(QIcon)
    model_object = Instance(ModelObject)
    parent = Instance('ModelTreeItem')
    controller = Instance(ModelEditorController)

    ui = Type(klass='enaml.widgets.widget.Widget', value=None)
    ui_kwargs = Dict(Unicode, Any)
    menu = Instance(Menu)

    _children = List(Instance('ModelTreeItem'))

    @classmethod
    def from_model_object(cls, model_object, **kwargs):
        return cls(title=model_object.name,
                   model_object=model_object,
                   **kwargs)

    def append_child(self, child):
        child.parent = self
        self._children.append(child)

    def child(self, row):
        if 0 <= row < len(self._children):
            return self._children[row]
        return None

    def child_count(self):
        return len(self._children)

    def row(self):
        if self.parent:
            return self.parent._children.index(self)
        return 0

    def select(self):
        self.controller.selected_object = self.model_object
        self.controller.selected_ui = self.ui_instance()

    def default_ui(self):
        klass = type(self.model_object)
        factory = ObjectRegistry.instance().get_closest_by_type(klass)
        return factory.ui if factory else None

    def ui_instance(self):
        ui_klass = self.ui if self.ui else self.default_ui()
        if not ui_klass:
            return None

        return ui_klass(**dict(self.ui_kwargs))
Exemple #13
0
class IMCOParameterFactory(IFactory):

    mco_factory = Instance('force_bdss.mco.base_mco_factory.BaseMCOFactory',
                           allow_none=False)

    model_class = Type(
        "force_bdss.mco.parameters.base_mco_parameter.BaseMCOParameter",
        allow_none=False)

    def get_model_class(self):
        """Returns type of BaseMCOParameter subclass"""

    def create_model(self, data_values=None):
        """Returns instance of BaseMCOParameter subclass"""
Exemple #14
0
class IUIHooksFactory(IFactory):
    """Envisage required interface for the BaseUIHooksFactory.
    You should not need to use this directly.

    Refer to the BaseUIHooksFactory for documentation.
    """
    ui_hooks_manager_class = Type(
        "force_bdss.ui_hooks.base_ui_hooks_manager.BaseUIHooksManager",
        allow_none=False)

    def get_ui_hooks_manager_class(self):
        """
        :return:  hooks manager class
        """

    def create_ui_hooks_manager(self):
        """
class BaseUIHooksFactory(BaseFactory):
    """Base class for UIHooksFactory.
    UI Hooks are extensions that perform actions associated to specific
    moments of the UI lifetime.
    """
    #: The UI Hooks manager class to instantiate. Define this to your
    #: base hook managers.
    ui_hooks_manager_class = Type(BaseUIHooksManager, allow_none=False)

    def __init__(self, plugin, *args, **kwargs):
        """Initializes the instance.

        Parameters
        ----------
        plugin: Plugin
            The plugin that holds this factory.
        """
        super(BaseUIHooksFactory, self).__init__(plugin=plugin,
                                                 *args,
                                                 **kwargs)

        self.ui_hooks_manager_class = self.get_ui_hooks_manager_class()

    def get_ui_hooks_manager_class(self):
        raise NotImplementedError(
            "get_ui_hooks_manager_class was not implemented "
            "in factory {}".format(self.__class__))

    def create_ui_hooks_manager(self):
        """Creates an instance of the hook manager.
        The hooks manager contains a set of methods that are applicable in
        various moments of the UI application lifetime.

        Returns
        -------
        BaseUIHooksManager
        """
        return self.ui_hooks_manager_class(self)
class BaseMCOFactory(BaseFactory):
    """Base class for the MultiCriteria Optimizer factory.
    """

    # NOTE: any changes to the interface of this class must be replicated
    # in the IMCOFactory interface class.

    #: The optimizer class to instantiate. Define this to your MCO class.
    optimizer_class = Type(BaseMCO, allow_none=False)

    #: The model associated to the MCO. Define this to your MCO model class.
    model_class = Type(BaseMCOModel, allow_none=False)

    #: The communicator associated to the MCO. Define this to your MCO comm.
    communicator_class = Type(BaseMCOCommunicator, allow_none=False)

    #: The list of parameter factory classes this MCO supports.
    parameter_factory_classes = List(Type(IMCOParameterFactory))

    #: The instantiated parameter factories.
    parameter_factories = List(Instance(IMCOParameterFactory))

    def __init__(self, plugin, *args, **kwargs):
        super(BaseMCOFactory, self).__init__(plugin=plugin, *args, **kwargs)

        self.optimizer_class = self.get_optimizer_class()
        self.model_class = self.get_model_class()
        self.communicator_class = self.get_communicator_class()
        self.parameter_factory_classes = self.get_parameter_factory_classes()
        self.parameter_factories = self._create_parameter_factories()

    def get_optimizer_class(self):
        raise NotImplementedError(
            f"get_optimizer_class was not implemented "
            f"in factory {self.__class__}"
        )

    def get_model_class(self):
        raise NotImplementedError(
            "get_model_class was not implemented "
            f"in factory {self.__class__}"
        )

    def get_communicator_class(self):
        raise NotImplementedError(
            "get_communicator_class was not implemented "
            f"in factory {self.__class__}"
        )

    def get_parameter_factory_classes(self):
        raise NotImplementedError(
            "get_parameter_factory_classes was not implemented "
            f"in factory {self.__class__}"
        )

    def create_optimizer(self):
        """Factory method.
        Creates the optimizer with the given application
        and model and returns it to the caller.

        Returns
        -------
        BaseMCO
            The optimizer
        """
        return self.optimizer_class(self)

    def create_model(self, model_data=None):
        """Factory method.
        Creates the model object (or network of model objects) of the MCO.
        The model can provide a traits UI View according to traitsui
        specifications, so that a UI can be provided automatically.

        Parameters
        ----------
        model_data: dict or None
            A dictionary of data that can be interpreted appropriately to
            recreate the model. If None, an empty (with defaults) model will
            be created and returned.

        Returns
        -------
        BaseMCOModel
            The MCOModel
        """
        if model_data is None:
            model_data = {}

        return self.model_class(self, **model_data)

    def create_communicator(self):
        """Factory method. Returns the communicator class that allows
        exchange between the MCO and the evaluator code.

        Returns
        -------
        BaseMCOCommunicator
            An instance of the communicator
        """
        return self.communicator_class(self)

    def _create_parameter_factories(self):
        """Returns the parameter factories supported by this MCO

        Returns
        -------
        List of BaseMCOParameterFactory
        """
        return [
            factory_cls(self) for factory_cls in self.parameter_factory_classes
        ]

    def parameter_factory_by_id(self, parameter_id):
        for factory in self.parameter_factories:
            if factory.id == parameter_id:
                return factory

        raise KeyError(
            f"Invalid Parameter Factory id {parameter_id} for "
            f"the specified MCO Factory {self.__class__}. "
            "No plugin responsible for the id is found."
        )
class PolarDiscr(HasTraits):
    '''
    Manager of the microplane arrays.

    This class is responsible for the generation and initialization
    and state management of an array of microplanes. Additionally, it
    can perform the setup of damage function parameters using the
    value of the microplane integrator object.
    '''

    mfn_class = Type(None)
    #-------------------------------------------------------------------------
    # Common parameters for for isotropic and anisotropic damage function specifications
    #-------------------------------------------------------------------------
    n_mp = Range(0, 50, 6, label='Number of microplanes', auto_set=False)

    E = Float(34e+3,
              label="E",
              desc="Young's Modulus",
              auto_set=False,
              enter_set=True)
    nu = Float(0.2,
               label='nu',
               desc="Poison's ratio",
               auto_set=False,
               enter_set=True)

    c_T = Float(
        0.0,
        label='c_T',
        desc='fraction of tangential stress accounted on each microplane',
        auto_set=False,
        enter_set=True)

    #-------------------------------------------------------------------------
    # list of angles
    #-------------------------------------------------------------------------
    alpha_list = Property(Array, depends_on='n_mp')

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

    #-------------------------------------------------------------------------
    # Damage function specification
    #-------------------------------------------------------------------------

    phi_fn = EitherType(klasses=[
        PhiFnGeneral, PhiFnGeneralExtended, PhiFnGeneralExtendedExp,
        PhiFnStrainSoftening, PhiFnStrainHardening, PhiFnStrainHardeningLinear,
        PhiFnStrainHardeningBezier
    ])

    def _phi_fn_default(self):
        print('setting phi_fn default')
        return PhiFnStrainSoftening(polar_discr=self)

    def _phi_fn_changed(self):
        print('setting phi_fn changed')
        self.phi_fn.polar_discr = self

    varied_params = List(Str, [])

    #-------------------------------------------------------------------------
    # Management of spatially varying parameters depending on the value of mats_eval
    #-------------------------------------------------------------------------
    varpars = Dict

    def _varpars_default(self):
        return self._get_varpars()

    @on_trait_change('phi_fn,varied_params')
    def _update_varpars(self):
        self.varpars = self._get_varpars()

    def _get_varpars(self):
        '''
        reset the varpar list according to the current phi_fn object.
        '''
        params = self.phi_fn.identify_parameters()
        varset = {}
        for key in params:
            varset[key] = VariedParam(phi_fn=self.phi_fn,
                                      mats_eval=self,
                                      varname=key)
            if key in self.varied_params:
                varset[key].switched_on = True
        return varset

    varpar_list = Property(List(VariedParam), depends_on='varpars')

    @cached_property
    def _get_varpar_list(self):
        return [self.varpars[key] for key in self.phi_fn.identify_parameters()]

    # variable selectable in the table of varied params (just for viewing)
    current_varpar = Instance(VariedParam)

    def _current_varpar_default(self):
        if len(self.varpar_list) > 0:
            return self.varpar_list[0]
        return None

    @on_trait_change('phi_fn')
    def set_current_varpar(self):
        if len(self.varpar_list) > 0:
            self.current_varpar = self.varpar_list[0]

    #-------------------------------------------------------------------------
    # Get the damage state for all microplanes
    #-------------------------------------------------------------------------
    def get_phi_arr(self, sctx, e_max_arr):
        '''
        Return the damage coefficients
        '''
        # gather the coefficients for parameters depending on the orientation
        carr_list = [
            self.varpars[key].polar_fn_vectorized(self.alpha_list)
            for key in self.phi_fn.identify_parameters()
        ]
        # vectorize the damage function evaluation
        n_arr = 1 + len(carr_list)
        phi_fn_vectorized = frompyfunc(self.phi_fn.get_value, n_arr, 1)
        # damage parameter for each microplane
        return phi_fn_vectorized(e_max_arr, *carr_list)

    def get_polar_fn_fracture_energy_arr(self, sctx, e_max_arr):
        '''
        Return the fracture energy contributions
        '''
        carr_list = [
            self.varpars[key].polar_fn_vectorized(self.alpha_list)
            for key in self.phi_fn.identify_parameters()
        ]
        # vectorize the damage function evaluation
        n_arr = 1 + len(carr_list)
        integ_phi_fn_vectorized = frompyfunc(self.phi_fn.get_integ, n_arr, 1)
        return self.E * integ_phi_fn_vectorized(e_max_arr, *carr_list)

    polar_fn_group = Group(
        Group(Item('n_mp@', width=200),
              Item('E'),
              Item('nu'),
              Item('c_T'),
              Spring(),
              label='Elasticity parameters'),
        Group(Item('phi_fn@', show_label=False), label='Damage parameters'),
        Group(VSplit(
            Item('varpar_list',
                 label='List of material variables',
                 show_label=False,
                 editor=varpar_editor),
            Item('current_varpar',
                 label='Selected variable',
                 show_label=False,
                 style='custom',
                 resizable=True),
            dock='tab',
        ),
              label='Angle-dependent variations'),
        Include('config_param_vgroup'),
        layout='tabbed',
        springy=True,
        dock='tab',
        id='ibvpy.mats.matsXD_cmdm.MATSXDPolarDiscr',
    )

    traits_view = View(Include('polar_fn_group'),
                       resizable=True,
                       scrollable=True,
                       width=0.6,
                       height=0.9)
class ViewportToolbar(Container, AbstractOverlay):
    """
    ViewportToolbar is a toolbar that is attached to the top of a viewport on
    the block canvas.
    """

    button_spacing = Int(5)

    button_vposition = Int(6)

    always_on = Bool(True)

    toolbar_height = Float(30.0)

    order = Enum("left-to-right", "right-to-left")

    buttons = List(Type(Button))

    # Override default values for inherited traits
    auto_size = False

    bgcolor = ColorTrait((0.5, 0.5, 0.5, 0.25))

    def __init__(self, component=None, *args, **kw):
        # self.component should be a CanvasViewport
        self.component = component
        for buttontype in self.buttons:
            self.add_button(buttontype())
        super(ViewportToolbar, self).__init__(*args, **kw)

    def _do_layout(self, component=None):
        if component is None:
            component = self.component

        if component is not None:
            self.x = component.x
            # FIXME: Adding 2 to the self.y because there is a tiny gap
            # at the top of the toolbar where components from the block
            # canvas show through.
            self.y = component.y2 - self.toolbar_height + 2
            self.height = self.toolbar_height
            self.width = component.width

        metrics = font_metrics_provider()
        if self.order == "right-to-left":
            last_button_position = self.width - self.button_spacing
            for b in self.components:
                x, y, w, h = metrics.get_text_extent(b.label)
                b.width = w + 2 * b.label_padding
                b.x = last_button_position - b.width
                b.y = self.button_vposition
                last_button_position -= b.width + self.button_spacing * 2
        else:
            last_button_position = 0
            for b in self.components:
                x, y, w, h = metrics.get_text_extent(b.label)
                b.width = w + 2 * b.label_padding
                b.x = self.button_spacing + last_button_position
                b.y = self.button_vposition
                last_button_position += b.width + self.button_spacing * 2

    def overlay(self, other_component, gc, view_bounds=None, mode="normal"):
        c = other_component
        self.do_layout(component=c)
        with gc:
            gc.clip_to_rect(c.x, c.y, c.width, c.height)
            Container._draw(self, gc, view_bounds)
        return

    def add_button(self, button):
        self.add(button)
        button.toolbar_overlay = self
        self._layout_needed = True
        return
Exemple #19
0
class ExampleTypeModel(HasTraits):
    _class = Type(klass=BaseClass)
Exemple #20
0
class PlotToolbar(Container, AbstractOverlay):
    """ A toolbar for embedding buttons in
    """

    buttons = List(Type(ToolbarButton))

    # Should the toolbar be hidden
    hiding = Bool(True)

    # should the toolbar go automatically go back into hiding when the mouse
    # is not hovering over it
    auto_hide = Bool(True)

    # the radius used to determine how round to make the toolbar's edges
    end_radius = Float(4.0)

    # button spacing is defined as the number of pixels on either side of
    # a button. The gap between 2 buttons will be 2 x the button spacing
    button_spacing = Float(5.0)

    # how many pixels to put before and after the set of buttons
    horizontal_padding = Float(5.0)

    # how many pixels to put on top and bottom the set of buttons
    vertical_padding = Float(5.0)

    # The edge against which the toolbar is placed.
    location = Enum('top', 'right', 'bottom', 'left')

    # Should tooltips be shown?
    show_tooltips = Bool(False)

    ############################################################
    # PlotToolbar API
    ############################################################

    def __init__(self, component=None, *args, **kw):
        super(PlotToolbar, self).__init__(*args, **kw)
        self.component = component

        if component is not None and hasattr(component, 'toolbar_location'):
            self.location = component.toolbar_location

        for buttontype in self.buttons:
            self.add_button(buttontype())

        hover_tool = PlotToolbarHover(component=self, callback=self.on_hover)
        self.tools.append(hover_tool)

        if self.location in ['top', 'bottom']:
            self._calculate_width()
        else:
            self._calculate_height()

    def _buttons_default(self):
        return [
            IndexAxisLogButton, ValueAxisLogButton, SaveAsButton,
            CopyToClipboardButton, ExportDataToClipboardButton, ZoomResetButton
        ]

    def add_button(self, button):
        """ adds a button to the toolbar
        """
        self.add(button)
        button.toolbar_overlay = self
        self._layout_needed = True
        return

    def normal_mouse_move(self, event):
        """ handler for normal mouse move
        """
        self.on_hover('')
        if self.hiding:
            self.hiding = False

    def on_hover(self, tooltip):
        if self.show_tooltips:
            self.component.window.set_tooltip(tooltip)

    def normal_left_down(self, event):
        """ handler for a left mouse click
        """
        if self.hiding:
            return
        else:
            for button in self.components:
                if button.is_in(event.x, event.y):
                    button.perform(event)
                    event.handled = True
                    break

    ############################################################
    # AbstractOverlay API
    ############################################################

    def overlay(self, other_component, gc, view_bounds=None, mode="normal"):
        """ Draws this component overlaid on another component.
        """

        starting_color = numpy.array([0.0, 1.0, 1.0, 1.0, 0.5])
        ending_color = numpy.array([1.0, 0.0, 0.0, 0.0, 0.5])

        x = self.x
        y = self.y
        height = self.height

        with gc:
            gc.begin_path()
            gc.move_to(x + self.end_radius, y)
            gc.arc_to(x + self.width, y, x + self.width, y + self.end_radius,
                      self.end_radius)
            gc.arc_to(x + self.width, y + height,
                      x + self.width - self.end_radius, y + height,
                      self.end_radius)
            gc.arc_to(x, y + height, x, y + height - self.end_radius,
                      self.end_radius)
            gc.arc_to(x, y, x + self.end_radius, y, self.end_radius)

            if self.location in ['top', 'bottom']:
                gc.linear_gradient(x, y, x, y + 100,
                                   numpy.array([starting_color, ending_color]),
                                   "pad")
            else:
                gc.linear_gradient(x, y, x + 100, y,
                                   numpy.array([starting_color, ending_color]),
                                   "pad")

            gc.draw_path()

            if not self.hiding:
                for button in self.components:
                    button.draw(gc)

    def is_in(self, x, y):
        if (x >= self.x and x <= self.x2) and (y >= self.y and y <= self.y2):
            return True
        return False

    def _do_layout(self, component=None):
        if component is None:
            component = self.component

        if self.location in ['top', 'bottom']:
            if self.hiding:
                self.height = height = 10
            else:
                tallest_button = max(
                    [button.height for button in self.components])
                self.height = height = (tallest_button +
                                        self.vertical_padding * 2)
        else:
            if self.hiding:
                self.width = width = 10
            else:
                widest_button = max(
                    [button.width for button in self.components])
                self.width = width = (widest_button +
                                      self.horizontal_padding * 2)

        if component is not None:
            # Overlay positions are not relative to the component's position,
            # so we have to add in the component's position
            cx, cy = component.outer_position
            if self.location is 'top':
                self.x = (cx + (component.width - self.width) / 2 +
                          component.padding_left)
                self.y = (cy + component.height + component.padding_bottom -
                          height - 2)
            elif self.location is 'bottom':
                self.x = (cx + (component.width - self.width) / 2 +
                          component.padding_left)
                self.y = cy + component.padding_bottom + 2
            elif self.location is 'left':
                self.x = cx + component.padding_left + 2
                self.y = (cy + (component.height - self.height) / 2 +
                          component.padding_bottom)
            else:  # 'right'
                self.x = (cx + component.width + component.padding_left -
                          width - 2)
                self.y = (cy + (component.height - self.height) / 2 +
                          component.padding_bottom)

        if self.location in ['top', 'bottom']:
            v_position = self.y + self.vertical_padding * 2

            last_button_position = (self.x + self.horizontal_padding +
                                    self.button_spacing)
            for button in self.components:
                button.x = last_button_position
                button.y = v_position
                last_button_position += button.width + self.button_spacing * 2
        else:
            # location is 'left' or 'right'
            h_position = self.x + self.horizontal_padding

            last_button_position = (self.y + self.vertical_padding +
                                    self.button_spacing)
            for button in reversed(self.components):
                h_offset = (self.width - button.width) / 2
                button.y = last_button_position
                button.x = h_position + h_offset
                last_button_position += button.height + self.button_spacing * 2

    def _dispatch_stateful_event(self, event, suffix):
        if self.is_in(event.x, event.y):
            if suffix == 'mouse_move':
                self.normal_mouse_move(event)
            elif suffix == 'left_down':
                self.normal_left_down(event)
                event.handled = True
        else:
            if self.auto_hide:
                self.hiding = True

        return

    ############################################################
    # Trait handlers
    ############################################################

    @on_trait_change('components, location')
    def _calculate_width(self):
        if self.location in ['top', 'bottom']:
            width = self.horizontal_padding * 2
            for button in self.components:
                width += button.width + self.button_spacing * 2

            self.width = max(10, width)
            self._layout_needed = True
            self.request_redraw()

    @on_trait_change('components, location')
    def _calculate_height(self):
        if self.location in ['left', 'right']:
            height = self.vertical_padding * 2
            for button in self.components:
                height += button.height + self.button_spacing * 2

            self.height = max(10, height)
            self._layout_needed = True
            self.request_redraw()

    @on_trait_change('hiding')
    def _hiding_changed(self):
        self._layout_needed = True
        self.request_redraw()

    @on_trait_change('auto_hide')
    def _auto_hide_changed(self):
        self.hiding = self.auto_hide
        self.request_redraw()
class BaseDataSourceFactory(BaseFactory):
    """Base class for DataSource factories. Reimplement this class to
    create your own DataSource.

    You must reimplement the following methods as from example::

        class MyDataSourceFactory(BaseDataSourceFactory)
            def get_data_source_class(self):
                return MyDataSource

            def get_data_source_model(self):
                return MyDataSourceModel

            def get_name(self):
                return "My data source"

            def get_identifier(self):
                return "my_data_source"
    """
    # NOTE: changes to this class must be ported also to the IDataSourceFactory

    #: The data source to be instantiated. Define this to your DataSource
    data_source_class = Type(BaseDataSource, allow_none=False)

    #: The model associated to the data source.
    #: Define this to your DataSourceModel
    model_class = Type(BaseDataSourceModel, allow_none=False)

    def __init__(self, plugin, *args, **kwargs):
        super(BaseDataSourceFactory, self).__init__(plugin=plugin,
                                                    *args,
                                                    **kwargs)

        self.data_source_class = self.get_data_source_class()
        self.model_class = self.get_model_class()

    def get_data_source_class(self):
        """Must be reimplemented to return the DataSource class.
        """
        raise NotImplementedError(
            "get_data_source_class was not implemented in factory {}".format(
                self.__class__))

    def get_model_class(self):
        """Must be reimplemented to return the DataSourceModel class.
        """
        raise NotImplementedError(
            "get_model_class was not implemented in factory {}".format(
                self.__class__))

    def create_data_source(self):
        """Factory method.
        Must return the factory-specific BaseDataSource instance.

        Returns
        -------
        BaseDataSource
            The specific instance of the generated DataSource
        """
        return self.data_source_class(self)

    def create_model(self, model_data=None):
        """Factory method.
        Creates the model object (or network of model objects) of the KPI
        calculator. The model can provide a traits UI View according to
        traitsui specifications, so that a UI can be provided automatically.

        Parameters
        ----------
        model_data: dict or None
            A dictionary containing the information to recreate the model.
            If None, an empty (with defaults) model will be returned.

        Returns
        -------
        BaseDataSourceModel
            The model
        """
        if model_data is None:
            model_data = {}

        return self.model_class(self, **model_data)
Exemple #22
0
class MATS2DMicroplaneDamage(MATSXDMicroplaneDamage, MATS2DEval):

    # implements(IMATSEval)

    # number of spatial dimensions
    #
    n_dim = Constant(2)

    # number of components of engineering tensor representation
    #
    n_eng = Constant(3)

    # planar constraint
    stress_state = Enum("plane_strain", "plane_stress")

    # Specify the class to use for directional dependence
    mfn_class = Type(MFnPolar)

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

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

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

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

    elasticity_tensors = Property(depends_on='E, nu, stress_state')

    @cached_property
    def _get_elasticity_tensors(self):
        '''
        Intialize the fourth order elasticity tensor
        for 3D or 2D plane strain or 2D plane stress
        '''
        # ----------------------------------------------------------------------------
        # Lame constants calculated from E and nu
        # ----------------------------------------------------------------------------
        E = self.E
        nu = self.nu

        # first Lame paramter
        la = E * nu / ((1 + nu) * (1 - 2 * nu))
        # second Lame parameter (shear modulus)
        mu = E / (2 + 2 * nu)

        # -----------------------------------------------------------------------------------------------------
        # Get the fourth order elasticity and compliance tensors for the 3D-case
        # -----------------------------------------------------------------------------------------------------

        # The following lines correspond to the tensorial expression:
        # (using numpy functionality in order to avoid the loop):
        #
        # D4_e_3D = zeros((3,3,3,3),dtype=float)
        # C4_e_3D = zeros((3,3,3,3),dtype=float)
        # delta = identity(3)
        # for i in range(0,3):
        #     for j in range(0,3):
        #         for k in range(0,3):
        #             for l in range(0,3):
        #                 # elasticity tensor (cf. Jir/Baz Inelastic analysis of structures Eq.D25):
        #                 D4_e_3D[i,j,k,l] = la * delta[i,j] * delta[k,l] + \
        #                                    mu * ( delta[i,k] * delta[j,l] + delta[i,l] * delta[j,k] )
        #                 # elastic compliance tensor (cf. Simo, Computational Inelasticity, Eq.(2.7.16) AND (2.1.16)):
        #                 C4_e_3D[i,j,k,l] = (1+nu)/(2*E) * \
        #                                    ( delta[i,k] * delta[j,l] + delta[i,l]* delta[j,k] ) - \
        #                                    nu / E * delta[i,j] * delta[k,l]
        #
        # NOTE: swapaxes returns a reference not a copy!
        # (the index notation always refers to the initial indexing (i=0,j=1,k=2,l=3))
        delta = identity(3)
        delta_ijkl = outer(delta, delta).reshape(3, 3, 3, 3)
        delta_ikjl = delta_ijkl.swapaxes(1, 2)
        delta_iljk = delta_ikjl.swapaxes(2, 3)
        D4_e_3D = la * delta_ijkl + mu * (delta_ikjl + delta_iljk)
        C4_e_3D = -nu / E * delta_ijkl + \
            (1 + nu) / (2 * E) * (delta_ikjl + delta_iljk)

        # -----------------------------------------------------------------------------------------------------
        # Get the fourth order elasticity and compliance tensors for the 2D-case
        # -----------------------------------------------------------------------------------------------------
        # 1. step: Get the (6x6)-elasticity and compliance matrices
        #          for the 3D-case:
        D2_e_3D = map3d_tns4_to_tns2(D4_e_3D)
        C2_e_3D = map3d_tns4_to_tns2(C4_e_3D)

        # 2. step: Get the (3x3)-elasticity and compliance matrices
        #          for the 2D-cases plane stress and plane strain:
        D2_e_2D_plane_stress = get_D_plane_stress(D2_e_3D)
        D2_e_2D_plane_strain = get_D_plane_strain(D2_e_3D)
        C2_e_2D_plane_stress = get_C_plane_stress(C2_e_3D)
        C2_e_2D_plane_strain = get_C_plane_strain(C2_e_3D)

        if self.stress_state == 'plane_stress':
            D2_e = D2_e_2D_plane_stress

        if self.stress_state == 'plane_strain':
            D2_e = D2_e_2D_plane_strain

        # 3. step: Get the fourth order elasticity and compliance tensors
        # for the 2D-cases plane stress and plane strain (D4.shape = (2,2,2,2))
        D4_e_2D_plane_stress = map2d_tns2_to_tns4(D2_e_2D_plane_stress)
        D4_e_2D_plane_strain = map2d_tns2_to_tns4(D2_e_2D_plane_strain)
        C4_e_2D_plane_stress = map2d_tns2_to_tns4(C2_e_2D_plane_stress)
        C4_e_2D_plane_strain = map2d_tns2_to_tns4(C2_e_2D_plane_strain)

        # -----------------------------------------------------------------------------------------------------
        # assign the fourth order elasticity and compliance tensors as return values
        # -----------------------------------------------------------------------------------------------------
        if self.stress_state == 'plane_stress':
            # print 'stress state:   plane-stress'
            D4_e = D4_e_2D_plane_stress
            C4_e = C4_e_2D_plane_stress

        if self.stress_state == 'plane_strain':
            # print 'stress state:   plane-strain'
            D4_e = D4_e_2D_plane_strain
            C4_e = C4_e_2D_plane_strain

        return D4_e, C4_e, D2_e

    def _get_explorer_config(self):
        '''Get the specific configuration of this material model in the explorer
        '''
        c = super(MATS2DMicroplaneDamage, self)._get_explorer_config()

        from ibvpy.mats.mats2D.mats2D_rtrace_cylinder import MATS2DRTraceCylinder

        # overload the default configuration
        c['rtrace_list'] += [
            MATS2DRTraceCylinder(name='Laterne',
                                 var_axis='time', idx_axis=0,
                                 var_surface='microplane_damage',
                                 record_on='update'),
        ]

        return c

    #-------------------------------------------------------------------------
    # Dock-based view with its own id
    #-------------------------------------------------------------------------
    traits_view = View(Include('polar_fn_group'),
                       dock='tab',
                       id='ibvpy.mats.mats3D.mats_2D_cmdm.MATS2D_cmdm',
                       kind='modal',
                       resizable=True,
                       scrollable=True,
                       width=0.6, height=0.8,
                       buttons=['OK', 'Cancel']
                       )
Exemple #23
0
class InstanceEditor(EditorFactory):
    """ Editor factory for instance editors.
    """

    # -------------------------------------------------------------------------
    #  Trait definitions:
    # -------------------------------------------------------------------------

    #: List of items describing the types of selectable or editable instances
    values = List(InstanceChoiceItem)

    #: Extended name of the context object trait containing the list of types
    #: of selectable or editable instances
    name = Str()

    #: Is the current value of the object trait editable (vs. merely
    #: selectable)?
    editable = Bool(True)

    #: Should the object trait value be selectable from a list of objects (a
    #: value of True forces a selection list to be displayed, while a value of
    #: False displays a selection list only if at least one object in the list
    #: of possible object values is selectable):
    selectable = Bool(False)

    #: Should the editor support drag and drop of objects to set the trait
    #: value (a value of True forces the editor to allow drag and drop, while
    #: a value of False only supports drag and drop if at least one item in the
    #: list of possible objects supports drag and drop):
    droppable = Bool(False)

    #: Should factory-created objects be cached?
    cachable = Bool(True)

    #: Optional label for button
    label = Str()

    #: Optional instance view to use
    view = AView

    #: Extended name of the context object trait containing the view, or name
    #: of the view, to use
    view_name = Str()

    #: The ID to use with the view
    id = Str()

    #: Kind of pop-up editor (live, modal, nonmodal, wizard)
    kind = AKind

    #: The orientation of the instance editor relative to the instance selector
    orientation = Enum("default", "horizontal", "vertical")

    #: The default adapter class used to create InstanceChoice compatible
    #: adapters for instance objects:
    adapter = Type(InstanceChoice, allow_none=False)

    # -------------------------------------------------------------------------
    #  Traits view definitions:
    # -------------------------------------------------------------------------

    traits_view = View([
        ["label{Button label}", "view{View name}", "|[]"],
        ["kind@", "|[Pop-up editor style]<>"],
    ])
class ToolkitEditorFactory(EditorFactory):
    """ Editor factory for instance editors.
    """

    #-------------------------------------------------------------------------
    #  Trait definitions:
    #-------------------------------------------------------------------------

    # List of items describing the types of selectable or editable instances
    values = List(InstanceChoiceItem)

    # Extended name of the context object trait containing the list of types of
    # selectable or editable instances
    name = Str

    # Is the current value of the object trait editable (vs. merely
    # selectable)?
    editable = Bool(True)

    # Should the object trait value be selectable from a list of objects (a
    # value of True forces a selection list to be displayed, while a value of
    # False displays a selection list only if at least one object in the list
    # of possible object values is selectable):
    selectable = Bool(False)

    # Should the editor support drag and drop of objects to set the trait value
    # (a value of True forces the editor to allow drag and drop, while a value
    # of False only supports drag and drop if at least one item in the list of
    # possible objects supports drag and drop):
    droppable = Bool(False)

    # Should factory-created objects be cached?
    cachable = Bool(True)

    # Optional label for button
    label = Unicode

    # Optional instance view to use
    view = AView

    # Extended name of the context object trait containing the view, or name of
    # the view, to use
    view_name = Str

    # The ID to use with the view
    id = Str

    # Kind of pop-up editor (live, modal, nonmodal, wizard)
    kind = AKind

    # The orientation of the instance editor relative to the instance selector
    orientation = Enum('default', 'horizontal', 'vertical')

    # The default adapter class used to create InstanceChoice compatible
    # adapters for instance objects:
    adapter = Type(InstanceChoice, allow_none=False)

    #-------------------------------------------------------------------------
    #  Traits view definitions:
    #-------------------------------------------------------------------------

    traits_view = View([['label{Button label}',
                         'view{View name}', '|[]'],
                        ['kind@', '|[Pop-up editor style]<>']])
Exemple #25
0
class BaseMultiImageFactory(ABCHasStrictTraits):
    """Main component contributed by plugins to allow expansion
    of the software. Represents a multi-channel image that can be
    loaded from a single or multiple files, with an analysis
    routine.
    """

    #: Label to be displayed in UI
    label = Str()

    #: Multi image class type associated with this factory
    multi_image_class = Type(IMultiImage)

    #: Reader class, used to load a BaseMultiImage from file
    reader_class = Type(IMultiImageReader)

    #: Analyser class, used to perform an analysis script on
    #: a specific image type
    analyser_class = Type(IMultiImageAnalyser)

    #: Parser class, used to collate files into sets
    parser_class = Type(IFileParser)

    #: Viewer class, used to display an image type
    viewer_class = Type(IMultiImageViewer)

    def __init__(self, **traits):

        label = self.get_label()
        multi_image = self.get_multi_image()
        reader = self.get_reader()
        analyser = self.get_analyser()
        parser = self.get_parser()
        viewer = self.get_viewer()

        super(BaseMultiImageFactory,
              self).__init__(label=label,
                             multi_image_class=multi_image,
                             reader_class=reader,
                             analyser_class=analyser,
                             parser_class=parser,
                             viewer_class=viewer,
                             **traits)

    @abstractmethod
    def get_label(self):
        """Returns key associated with this factory"""

    @abstractmethod
    def get_multi_image(self):
        """Returns BaseMultiImage associated with this factory"""

    @abstractmethod
    def get_reader(self):
        """Returns BaseMultiImageReader class able to load
        the BaseMultiImage class created by this factory"""

    @abstractmethod
    def get_analyser(self):
        """Returns BaseMultiImageAnalyser class able to analyse
        the BaseMultiImage class created by this factory"""

    @abstractmethod
    def get_parser(self):
        """Returns BaseFileParser class able to collate image files
        together"""

    @abstractmethod
    def get_viewer(self):
        """Returns BaseMultiImageViewer class able to display
        the BaseMultiImage class created by this factory"""

    def create_reader(self, **kwargs):
        """Public method used to return an instance of
        BaseMultiImageReader"""
        return self.reader_class(**kwargs)

    def create_analyser(self, **kwargs):
        """Public method used to return an instance of
        BaseMultiImageAnalyser"""
        return self.analyser_class(**kwargs)

    def create_parser(self, **kwargs):
        """Public method used to return an instance of
        BaseFileParser"""
        return self.parser_class(**kwargs)

    def create_viewer(self, **kwargs):
        """Public method used to return an instance of
        BaseMultiImageViewer"""
        return self.viewer_class(**kwargs)
Exemple #26
0
class Variable(HasStrictTraits):
    """ Represents a variable in a data set.
    
    Typically corresponds to a column in a flat file or SQL database.
    """

    # The name of the variable.
    name = Str()
    
    # The type of the variable, represented as a TraitType.
    # We use a TraitType instead of a NumPy dtype or SQL data type to avoid a 
    # coupling to any particular data source.
    type = Type()
    
    # Whether the variable is categorical or numerical.
    # By default, this is inferred from the ``type`` attribute and boolean
    # types are treated as numerical.
    is_numerical = Bool()
    
    # An object identifying the source of a variable, e.g., a filename or a
    # SQL table name.
    source = Any()
    
    # Summary statistics for the variable.
    statistics = Dict(Str, Any)
    
    def __init__(self, name, type, **traits):
        super(Variable, self).__init__(name=name, type=type, **traits)

    def __repr__(self):
        type_str = 'None' if self.type is None else self.type.__name__
        return 'Variable({0}, {1})'.format(repr(self.name), type_str)

    def __eq__(self, other):
        return (isinstance(other, Variable) and
                self.name == other.name and self.type == other.type and
                self.is_numerical == other.is_numerical and
                self.source == other.source)
    
    def _is_numerical_default(self):
        from traits.api import BaseStr
        return not issubclass(self.type, BaseStr)
    
    @classmethod
    def from_data_frame(cls, df, statistics=False, **traits):
        """ Extract a list of Variables from a pandas DataFrame.
        """
        variables = []
        for col, dtype in zip(df.columns, df.dtypes):
            var = cls.from_dtype(col, dtype, **traits)
            if statistics:
                var.statistics = dict(df[col].describe())
            variables.append(var)
        return variables

    @classmethod
    def from_metadata(cls, df, type, **traits):
        """ Extract a list of Variables from a metadata table.
        """
        variables = []

        of_type = df[df['type'] == type]
        for _, row in of_type.iterrows():
            name = row['name']
            type = R_CLASS_TO_TRAIT[row['dtype']]
            variables.append(cls(name, type, **traits))

        return variables
                
    @classmethod
    def from_dtype(cls, name, dtype, **traits):
        from traits.trait_numeric import dtype2trait
        if dtype.name == 'bool':
            type = Bool
        elif dtype.name == 'object':
            type = Str
        else:
            type = dtype2trait(dtype)
        return cls(name, type, **traits)
class XDomainFEGrid(BMCSTreeNode):

    hidden = Bool(False)
    #=========================================================================
    # Type and shape specification of state variables representing the domain
    #=========================================================================
    U_var_shape = Property(Int)

    def _get_U_var_shape(self):
        return self.mesh.n_dofs

    vtk_expand_operator = Property

    def _get_vtk_expand_operator(self):
        return self.fets.vtk_expand_operator

    K_type = Type(SysMtxArray)

    state_var_shape = Property(Tuple)

    def _get_state_var_shape(self):
        return (
            self.mesh.n_active_elems,
            self.fets.n_m,
        )

    #=========================================================================
    # Methods needed by XDomain to chain the subdomains
    #=========================================================================
    dof_offset = Property

    def _get_dof_offset(self):
        return self.mesh.dof_offset

    n_active_elems = Property

    def _get_n_active_elems(self):
        return self.mesh.n_active_elems

    def set_next(self, next_):
        self.mesh.next_grid = next_.mesh

    def set_prev(self, prev):
        self.mesh.prev_grid = prev.mesh

    #=========================================================================
    # Input parameters
    #=========================================================================
    coord_min = Array(Float, value=[0., 0., 0.], GEO=True)
    '''Grid geometry specification - min corner point
    '''
    coord_max = Array(Float, value=[1., 1., 1.], MESH=True)
    '''Grid geometry specification - max corner point
    '''
    shape = Array(Int, value=[1, 1, 1], MESH=True)
    '''Number of elements in the individual dimensions
    '''
    geo_transform = Callable
    '''Geometry transformation
    '''
    integ_factor = Float(1.0, input=True, CS=True)
    '''Integration factor used to multiply the integral
    '''
    fets = Instance(IFETSEval, input=True, FE=True)
    '''Finite element type
    '''

    n_u = Property
    """Dimension of the field variables in the finite element formulation
    """

    def _get_n_u(self):
        return self.fets.n_nodal_dofs

    Diff1_abcd = Array(np.float_, input=True)
    '''Symmetric operator distributing the first order
    derivatives of the shape functions into the 
    tensor field
    '''

    def _Diff1_abcd_default(self):
        delta = np.identity(self.n_u)
        # symmetrization operator
        Diff1_abcd = 0.5 * (np.einsum('ac,bd->abcd', delta, delta) +
                            np.einsum('ad,bc->abcd', delta, delta))
        return Diff1_abcd

    #=========================================================================
    # Finite element discretization respecting the FE definition
    #=========================================================================
    mesh = Property(Instance(FEGrid), depends_on='MESH,GEO')

    @cached_property
    def _get_mesh(self):
        return FEGrid(coord_min=self.coord_min,
                      coord_max=self.coord_max,
                      shape=self.shape,
                      geo_transform=self.geo_transform,
                      fets_eval=self.fets)

    x_Eia = Property(depends_on='MESH,GEO,CS,FE')

    def _get_x_Eia(self):
        x_Ia = self.mesh.X_Id
        I_Ei = self.mesh.I_Ei
        x_Eia = x_Ia[I_Ei, :]
        return x_Eia

    x_Ema = Property(depends_on='MESH,GEO,CS,FE')

    def _get_x_Ema(self):
        return np.einsum('im,Eia->Ema', self.fets.N_im, self.x_Eia)

    o_Ia = Property(depends_on='MESH,GEO,CS,FE')

    @cached_property
    def _get_o_Ia(self):
        x_Ia = self.mesh.X_Id
        n_I, _ = x_Ia.shape
        n_a = self.mesh.n_nodal_dofs
        do = self.mesh.dof_offset
        return do + np.arange(n_I * n_a, dtype=np.int_).reshape(-1, n_a)

    o_Eia = Property(depends_on='MESH,GEO,CS,FE')

    @cached_property
    def _get_o_Eia(self):
        I_Ei = self.mesh.I_Ei
        return self.o_Ia[I_Ei]

    B1_Einabc = Property(depends_on='MESH,GEO,CS,FE')
    '''Kinematic mapping between displacement and strain in every
    visualization point
    '''

    @cached_property
    def _get_B1_Einabc(self):
        inv_J_Enar = np.linalg.inv(self.J_Enar)
        return np.einsum('abcd,imr,Eidr->Eimabc', self.Diff1_abcd,
                         self.fets.dN_inr, inv_J_Enar)

    I_Ei = Property(depends_on='MESH,GEO,CS,FE')
    '''[element, node] -> global node
    '''

    def _get_I_Ei(self):
        return self.mesh.I_Ei

    det_J_Em = Property(depends_on='MESH,GEO,CS,FE')
    '''Jacobi matrix in integration points
    '''

    @cached_property
    def _get_det_J_Em(self):
        return np.linalg.det(self.J_Emar)

    J_Emar = Property(depends_on='MESH,GEO,CS,FE')
    '''Jacobi matrix in integration points
    '''

    @cached_property
    def _get_J_Emar(self):
        return np.einsum('imr,Eia->Emar', self.fets.dN_imr, self.x_Eia)

    J_Enar = Property(depends_on='MESH,GEO,CS,FE')
    '''Jacobi matrix in nodal points
    '''

    @cached_property
    def _get_J_Enar(self):
        return np.einsum('inr,Eia->Enar', self.fets.dN_inr, self.x_Eia)

    #=========================================================================
    # Conversion between linear algebra objects and field variables
    #=========================================================================
    B1_Eimabc = Property(depends_on='MESH,GEO,CS,FE')
    '''Kinematic mapping between displacements and strains in every
    integration point.
    '''

    @cached_property
    def _get_B1_Eimabc(self):
        inv_J_Emar = np.linalg.inv(self.J_Emar)
        return np.einsum('abcd,imr,Emrd->Eimabc', self.Diff1_abcd,
                         self.fets.dN_imr, inv_J_Emar)

    B_Eimabc = Property(depends_on='MESH,GEO,CS,FE')
    '''Kinematic mapping between displacements and strains in every
    integration point.
    '''

    @cached_property
    def _get_B_Eimabc(self):
        return self.B1_Eimabc

    BB_Emicjdabef = Property(depends_on='MESH,GEO,CS,FE')
    '''Quadratic form of the kinematic mapping.
    '''

    def _get_BB_Emicjdabef(self):
        return np.einsum('...Eimabc,...Ejmefd, Em, m->...Emicjdabef',
                         self.B_Eimabc, self.B_Eimabc, self.det_J_Em,
                         self.fets.w_m)

    n_dofs = Property

    def _get_n_dofs(self):
        return self.mesh.n_dofs

    ##################################################################
    #
    def map_U_to_field(self, U_o):
        #        n_c = self.fets.n_nodal_dofs
        U_Eia = U_o[self.o_Eia]
        eps_Emab = np.einsum('Eimabc,Eic->Emab', self.B_Eimabc, U_Eia)
        return eps_Emab

    def map_field_to_F(self, sig_Emab):
        _, n_i, _, _, _, n_c = self.B_Eimabc.shape
        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)
        o_E = self.o_Eia.reshape(-1, n_i * n_c)
        return o_E.flatten(), f_Ei.flatten()

    def map_field_to_K(self, D_Emabef):
        K_Eicjd = self.integ_factor * np.einsum('Emicjdabef,Emabef->Eicjd',
                                                self.BB_Emicjdabef, D_Emabef)
        _, n_i, n_c, n_j, n_d = K_Eicjd.shape
        K_Eij = K_Eicjd.reshape(-1, n_i * n_c, n_j * n_d)
        o_Ei = self.o_Eia.reshape(-1, n_i * n_c)
        return SysMtxArray(mtx_arr=K_Eij, dof_map_arr=o_Ei)

    ###########

    debug_cell_data = Bool(False)

    # @todo - comment this procedure`

    def get_vtk_cell_data(self, position, point_offset, cell_offset):
        if position == 'nodes':
            subcell_offsets, subcell_lengths, subcells, subcell_types = \
                self.fets.vtk_node_cell_data
        elif position == 'int_pnts':
            subcell_offsets, subcell_lengths, subcells, subcell_types = \
                self.fets.vtk_ip_cell_data

        if self.debug_cell_data:
            print('subcell_offsets')
            print(subcell_offsets)
            print('subcell_lengths')
            print(subcell_lengths)
            print('subcells')
            print(subcells)
            print('subcell_types')
            print(subcell_types)

        n_subcells = subcell_types.shape[0]
        n_cell_points = self.n_cell_points
        subcell_size = subcells.shape[0] + n_subcells

        if self.debug_cell_data:
            print('n_cell_points', n_cell_points)
            print('n_cells', self.n_cells)

        vtk_cell_array = np.zeros((self.n_cells, subcell_size), dtype=int)

        idx_cell_pnts = np.repeat(True, subcell_size)

        if self.debug_cell_data:
            print('idx_cell_pnts')
            print(idx_cell_pnts)

        idx_cell_pnts[subcell_offsets] = False

        if self.debug_cell_data:
            print('idx_cell_pnts')
            print(idx_cell_pnts)

        idx_lengths = idx_cell_pnts == False

        if self.debug_cell_data:
            print('idx_lengths')
            print(idx_lengths)

        point_offsets = np.arange(self.n_cells) * n_cell_points
        point_offsets += point_offset

        if self.debug_cell_data:
            print('point_offsets')
            print(point_offsets)

        vtk_cell_array[:,
                       idx_cell_pnts] = point_offsets[:,
                                                      None] + subcells[None, :]
        vtk_cell_array[:, idx_lengths] = subcell_lengths[None, :]

        if self.debug_cell_data:
            print('vtk_cell_array')
            print(vtk_cell_array)

        n_active_cells = self.mesh.n_active_elems

        if self.debug_cell_data:
            print('n active cells')
            print(n_active_cells)

        cell_offsets = np.arange(n_active_cells, dtype=int) * subcell_size
        cell_offsets += cell_offset
        vtk_cell_offsets = cell_offsets[:, None] + subcell_offsets[None, :]

        if self.debug_cell_data:
            print('vtk_cell_offsets')
            print(vtk_cell_offsets)

        vtk_cell_types = np.zeros(self.n_cells * n_subcells,
                                  dtype=int).reshape(self.n_cells, n_subcells)
        vtk_cell_types += subcell_types[None, :]

        if self.debug_cell_data:
            print('vtk_cell_types')
            print(vtk_cell_types)

        return (vtk_cell_array.flatten(), vtk_cell_offsets.flatten(),
                vtk_cell_types.flatten())

    n_cells = Property(Int)

    def _get_n_cells(self):
        '''Return the total number of cells'''
        return self.mesh.n_active_elems

    n_cell_points = Property(Int)

    def _get_n_cell_points(self):
        '''Return the number of points defining one cell'''
        return self.fets.n_vtk_r
class BaseExtensionPlugin(Plugin):
    """Base class for extension plugins, that is, plugins that are
    provided by external contributors.

    It provides a set of slots to be populated that end up contributing
    to the application extension points. To use the class, simply inherit it
    in your plugin, and reimplement the methods as from example::

        class MyPlugin(BaseExtensionPlugin):
            id = plugin_id("enthought", "plugin_name", 0)

            def get_name(self):
                return "Enthought plugin"

            def get_version(self):
                return 0

            def get_description(self):
                return "A long description"

            def get_factory_classes(self):
                return [
                    MyDataSourceFactory1,
                    MyDataSourceFactory2,
                    MyMCOFactory
                ]
    """
    #: The user visible name of the plugin
    name = Str()

    #: An integer representing the version of the plugin
    version = Int()

    #: The user visible long description of the plugin
    description = Str()

    #: Reports if the plugin loaded its factories successfully or not.
    broken = Bool(False)

    #: The error message generated by the factory instantiations
    error_msg = Str()

    #: The error traceback generated by the factory instantiations.
    error_tb = Str()

    #: A list of all the factory classes to export.
    factory_classes = List(
        Either(Type(BaseDataSourceFactory), Type(BaseMCOFactory),
               Type(BaseNotificationListenerFactory),
               Type(BaseUIHooksFactory)))

    #: A list of available Multi Criteria Optimizers this plugin exports.
    mco_factories = List(IMCOFactory,
                         contributes_to=ExtensionPointID.MCO_FACTORIES)

    #: A list of the available Data Sources this plugin exports.
    data_source_factories = List(
        IDataSourceFactory,
        contributes_to=ExtensionPointID.DATA_SOURCE_FACTORIES)

    #: A list of the available notification listeners this plugin exports
    notification_listener_factories = List(
        INotificationListenerFactory,
        contributes_to=ExtensionPointID.NOTIFICATION_LISTENER_FACTORIES)

    #: A list of the available ui hooks this plugin exports
    ui_hooks_factories = List(
        IUIHooksFactory, contributes_to=ExtensionPointID.UI_HOOKS_FACTORIES)

    #: The logger.
    _logger = Instance(logging.Logger)

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

        try:
            self.name = self.get_name()
            self.description = self.get_description()
            self.version = self.get_version()
            self.factory_classes = self.get_factory_classes()
            self.mco_factories[:] = [
                cls(self) for cls in self._factory_by_type(BaseMCOFactory)
            ]
            self.data_source_factories[:] = [
                cls(self)
                for cls in self._factory_by_type(BaseDataSourceFactory)
            ]
            self.notification_listener_factories[:] = [
                cls(self) for cls in self._factory_by_type(
                    BaseNotificationListenerFactory)
            ]
            self.ui_hooks_factories[:] = [
                cls(self) for cls in self._factory_by_type(BaseUIHooksFactory)
            ]
        except Exception as e:
            self._logger.exception(e)
            self.error_msg = str(e)
            self.error_tb = traceback.format_exc()
            self.name = ""
            self.description = ""
            self.version = 0
            self.broken = True
            self.mco_factories[:] = []
            self.data_source_factories[:] = []
            self.notification_listener_factories[:] = []
            self.ui_hooks_factories[:] = []

    def get_name(self):
        raise NotImplementedError(
            "get_name was not implemented in plugin {}".format(self.__class__))

    def get_version(self):
        raise NotImplementedError(
            "get_version was not implemented in plugin {}".format(
                self.__class__))

    def get_description(self):
        return "No description available"

    def get_factory_classes(self):
        """Must return a list of factory classes that this plugin exports.
        """
        raise NotImplementedError(
            "get_factory_classes was not implemented in plugin {}".format(
                self.__class__))

    def _factory_by_type(self, type_):
        """Returns all the factories of the given type"""
        return [cls for cls in self.factory_classes if issubclass(cls, type_)]

    def __logger_default(self):
        return logging.getLogger(self.__class__.__name__)
class XDomainFE(BMCSTreeNode):

    hidden = Bool(False)
    #=========================================================================
    # Type and shape specification of state variables representing the domain
    #=========================================================================
    U_var_shape = Property(Int)

    def _get_U_var_shape(self):
        return self.mesh.n_dofs

    vtk_expand_operator = Property

    def _get_vtk_expand_operator(self):
        return self.fets.vtk_expand_operator

    K_type = Type(SysMtxArray)

    state_var_shape = Property(Tuple)

    def _get_state_var_shape(self):
        return (
            self.mesh.n_active_elems,
            self.fets.n_m,
        )

    #=========================================================================
    # Methods needed by XDomain to chain the subdomains
    #=========================================================================
    dof_offset = Property

    def _get_dof_offset(self):
        return self.mesh.dof_offset

    n_active_elems = Property

    def _get_n_active_elems(self):
        return self.mesh.n_active_elems

    def set_next(self, next_):
        self.mesh.next_grid = next_.mesh

    def set_prev(self, prev):
        self.mesh.prev_grid = prev.mesh

    #=========================================================================
    # Input parameters
    #=========================================================================
    # coord_min = Array(Float, value=[0., 0., 0.], GEO=True)
    # '''Grid geometry specification - min corner point
    # '''
    # coord_max = Array(Float, value=[1., 1., 1.], MESH=True)
    # '''Grid geometry specification - max corner point
    # '''
    # shape = Array(Int, value=[1, 1, 1], MESH=True)
    # '''Number of elements in the individual dimensions
    # '''
    # geo_transform = Callable
    # '''Geometry transformation
    # '''
    integ_factor = Float(1.0, input=True, CS=True)
    '''Integration factor used to multiply the integral
    '''
    # fets = Instance(IFETSEval, input=True, FE=True)
    # '''Finite element type
    # '''

    mesh = Instance(IFEUniformDomain)
    X_Id = DelegatesTo('mesh')
    # I_Ei = DelegatesTo('mesh')

    o_Ia = Property(depends_on='MESH,GEO,CS,FE')

    @cached_property
    def _get_o_Ia(self):
        x_Ia = self.mesh.X_Id
        n_I, _ = x_Ia.shape
        n_a = self.mesh.n_nodal_dofs
        do = self.mesh.dof_offset
        return do + np.arange(n_I * n_a, dtype=np.int_).reshape(-1, n_a)
        # for shell element, it's  array([[ 0,  1,  2,  3,  4],
        #        [ 5,  6,  7,  8,  9],
        #        [10, 11, 12, 13, 14]])

    o_Eia = Property(depends_on='MESH,GEO,CS,FE')

    @cached_property
    def _get_o_Eia(self):
        I_Ei = self.I_Ei
        return self.o_Ia[I_Ei]
Exemple #30
0
class BaseDataSourceModel(BaseModel):
    """Base class for the factory specific DataSource models.
    This model will also provide, through traits/traitsui magic the View
    that will appear in the workflow manager UI.

    In your factory definition, your factory-specific model must reimplement
    this class.
    """
    #: A reference to the creating factory, so that we can
    #: retrieve it as the originating factory.
    factory = Instance(IDataSourceFactory, visible=False, transient=True)

    #: Specifies binding between input slots and source for that value.
    #: Each InputSlotMap instance specifies this information for each of the
    #: slots.
    input_slot_info = List(Instance(InputSlotInfo), visible=False)

    #: Allows to assign names and KPI status to the output slots, so that
    #: they can be referenced somewhere else (e.g. another layer's
    #: DataSources).
    #: If the name is the empty string, it means that the user is not
    #: interested in preserving the information, and should therefore be
    #: discarded and not propagated further.
    output_slot_info = List(Instance(OutputSlotInfo), visible=False)

    #: This event claims that a change in the model influences the slots
    #: (either input or output). It must be triggered every time a specific
    #: option in your model implies a change in the slots. The UI will detect
    #: this and adapt the visual entries.
    changes_slots = Event()

    #: Type of the Data Source Start event
    _start_event_type = Type(DataSourceStartEvent,
                             visible=False,
                             transient=True)

    #: Type of the Data Source Finish event
    _finish_event_type = Type(DataSourceFinishEvent,
                              visible=False,
                              transient=True)

    def verify(self):
        """ Verify the data source model.

        The data source model must have:
        - input and output slots match between instance and model
        - all output slots named
        - no errors in input or output slots

        Returns
        -------
        errors : list of VerifierErrors
            The list of all detected errors in the data source model.
        """
        try:
            data_source = self.factory.create_data_source()
        except Exception:
            logger.exception(
                "Unable to create data source from factory '%s', plugin "
                "'%s'. This might indicate a programming error",
                self.factory.id,
                self.factory.plugin_id,
            )
            raise

        try:
            input_slots, output_slots = data_source.slots(self)
        except Exception:
            logger.exception(
                "Unable to retrieve slot information from data source"
                " created by factory '%s', plugin '%s'. This might "
                "indicate a programming error.", self.factory.id,
                self.factory.plugin_id)
            raise

        factory = self.factory
        errors = []
        if len(input_slots) != len(self.input_slot_info):
            local_error_txt = ("The number of input slots ({} values) returned"
                               " by '{}' does not match the number"
                               " of user-defined names specified ({} values)."
                               " This is either a plugin error or a file"
                               " error.").format(len(input_slots),
                                                 factory.name,
                                                 len(self.input_slot_info))
            errors.append(
                VerifierError(
                    subject=self,
                    local_error=local_error_txt,
                    global_error=("A data source model has incorrect number "
                                  "of input slots."),
                ))
        for input_slot in self.input_slot_info:
            errors += input_slot.verify()

        if len(output_slots) != len(self.output_slot_info):
            local_error_txt = (
                "The number of output slots ({} values) returned"
                " by '{}' does not match the number"
                " of user-defined names specified ({} values)."
                " This is either a plugin error or a file"
                " error.").format(len(output_slots), factory.name,
                                  len(self.output_slot_info))
            errors.append(
                VerifierError(
                    subject=self,
                    local_error=local_error_txt,
                    global_error="A data source model has incorrect number "
                    "of output slots."))

        if self.output_slot_info and not any(
                output_slot.name for output_slot in self.output_slot_info):
            errors.append(
                VerifierError(
                    subject=self,
                    severity='warning',
                    local_error="All output variables have undefined names",
                    global_error=(
                        "A data source model has no defined output names"),
                ))
        for output_slot in self.output_slot_info:
            errors += output_slot.verify()

        return errors

    def notify_start_event(self):
        """ Creates base event indicating the start of the MCO."""
        self.notify(
            self._start_event_type(input_names=list(
                p.name for p in self.input_slot_info)))

    def notify_finish_event(self):
        """ Creates base event indicating the finished MCO."""
        self.notify(
            self._finish_event_type(output_names=list(
                p.name for p in self.output_slot_info)))

    @on_trait_change("+changes_slots")
    def _trigger_changes_slots(self, obj, name, new):
        changes_slots = self.traits()[name].changes_slots

        if changes_slots:
            self.changes_slots = True

    @classmethod
    def from_json(cls, factory, json_data):
        """ Instantiate an BaseMCOModel object from a `json_data`
        dictionary and the generating `factory` object.

        Parameters
        ----------
        factory: IDataSourceFactory
            Generating factory object
        json_data: dict
            Dictionary with a DataSourceModel serialized data

        Returns
        ----------
        layer: BaseDataSourceModel
            BaseDataSourceModel instance with attributes values from
            the `json_data` dict
        """
        data = deepcopy(json_data)

        input_slots = [InputSlotInfo(**d) for d in data["input_slot_info"]]
        data["input_slot_info"] = input_slots

        output_slots = [OutputSlotInfo(**d) for d in data["output_slot_info"]]
        data["output_slot_info"] = output_slots

        data_source = factory.create_model(data)
        return data_source