Esempio n. 1
0
def define_class(class_id):
    """Define a class based on Cinfo element with Id=class_id."""
    class_name = class_id[0].getField('name')
    if class_name in globals().keys():
        return
    base = class_id[0].getField('baseClass')
    if base != 'none':
        try:
            base_class = globals()[base]
        except KeyError:
            define_class(Id('/classes/' + base))
            base_class = globals()[base]
    else:
        base_class = object
    class_obj = type(class_name, (base_class, ), {})
    update_class(class_obj, class_id)
    # Add this class to globals dict
    globals()[class_name] = class_obj
    array_class_name = class_name + 'Array'
    if base != 'none':
        base_class = globals()[base + 'Array']
    else:
        base_class = object
    array_class_obj = type(array_class_name, (base_class, ), {})
    globals()[array_class_name] = array_class_obj
Esempio n. 2
0
def syncDataHandler(target):
    """Synchronize data handlers for target.

    Parameter:
    target -- target element or path or Id.
    """
    raise NotImplementedError(
        'The implementation is not working for IntFire - goes to invalid objects. First fix that issue with SynBase or something in that line.'
    )
    if isinstance(target, str):
        if not _moose.exists(target):
            raise ValueError('%s: element does not exist.' % (target))
        target = Id(target)
        _moose.syncDataHandler(target)
Esempio n. 3
0
def update_class(cls, class_id):
    class_name = class_id[0].name
    num_valueFinfo = getField(class_id[0], 'num_valueFinfo', 'unsigned')
    num_destFinfo = getField(class_id[0], 'num_destFinfo', 'unsigned')
    num_lookupFinfo = getField(class_id[0], 'num_lookupFinfo', 'unsigned')
    valueFinfo = Id('/classes/%s/valueFinfo' % (class_name))
    destFinfo = Id('/classes/%s/destFinfo' % (class_name))
    lookupFinfo = Id('/classes/%s/lookupFinfo' % (class_name))
    destFinfoNames = set(
        [ObjId(destFinfo, 0, ii, 0).name for ii in range(num_destFinfo)])
    for ii in range(num_valueFinfo):
        field = ObjId(valueFinfo, 0, ii, 0)
        fieldName = field.name
        fget = partial(ObjId.getField, fieldName)
        fset = None
        if 'get_%s' % (fieldName) in destFinfoNames:
            fset = partial(ObjId.setField, fieldName)
        doc = None
        # The following is to avoid duplicating the documentation
        # in non-interactive mode. __main__.__file__ is not
        # defined in interactive mode and that is when we create
        # the documentation.
        if not hasattr(main, '__file__'):
            doc = field.docs
        setattr(cls, fieldName, property(fget=fget, fset=fset, doc=doc))

    for ii in range(num_lookupFinfo):
        field = ObjId(lookupFinfo, 0, ii, 0)
        fieldName = field.name
        fget = partial(_LookupField, fieldName)
        # The following is to avoid duplicating the documentation
        # in non-interactive mode. __main__.__file__ is not
        # defined in interactive mode and that is when we create
        # the documentation.
        doc = None
        if not hasattr(main, '__file__'):
            doc = field.docs
        setattr(cls, fieldName, property(fget=fget, doc=doc))

    # Go through the destFinfos and make them look like methods
    for ii in range(num_destFinfo):
        field = ObjId(destFinfo, 0, ii, 0)
        fieldName = field.name
        # get_<fieldName> and set_<fieldName> are internal
        # destFinfos generated for each valueFinfo (the latter
        # created for writable ones). They are not to be accessed
        # by users.
        if fieldName.startswith('get_') or fieldName.startswith('set_'):
            continue
        # Can we handle the arguments required for this destFinfo?
        # Start optimistically.
        manageable = True
        # We keep gathering the function signature in fnsig
        # This will be a lambda function, lambda x, y, ...: expr
        # where expr is evaluated and the result returned.
        fnsig = 'lambda self'
        # We gather the formal arguments in fnargs. field name
        # must be the first argument passed to the
        # ObjId.setField function.
        fnargs = '"%s"' % (fieldName)
        # 'type' is a string field in Finfos specifying the type
        # (retrieved from the template parameters specified in the
        # C++ definition). for DestFinfo with OpFuncN<MooseClass,
        # type1, type2, ..., typeN> will have a type string:
        # "type1,type2,...,typeN". We split this string to find
        # out the formal arguments of the lambda
        argtypes = field.type.split(',')
        for index in range(len(argtypes)):
            # Check if we know how to handle this argument type
            if argtypes[index] not in known_types:
                manageable = False
                break
            elif argtypes[index] != 'void':
                # The replacements are for types with space (like
                # unsigned int) and templated types (like
                # vector<int>)
                arg = 'arg_%d_%s' % (index, argtypes[index].replace(
                    ' ', '_').replace('<', '_').replace('>', '_'))
                fnsig += ', %s' % (arg)
                fnargs += ', %s' % (arg)
        if manageable:
            # The final function will be:
            # lambda self, arg_1_type1, arg_2_type2, ..., arg_N_typeN:
            #     self.oid_.setField(fieldName, arg_1_type1, arg_2_type2, ..., arg_N_typeN)
            function_string = '%s: self.oid_.setDestField(%s)' % (fnsig,
                                                                  fnargs)
            setattr(cls, fieldName, eval(function_string))
Esempio n. 4
0
    def __init__(self, *args, **kwargs):
        """Initialize a Neutral object.

        Arguments:

        arg1 : A path or an existing ObjId or an Id or a NeutralArray
        or another Neutral object. 
        
        path -- a string specifying the path for the Neutral
        object. If there is already a Neutral object with the given
        path, a reference to that object is created. Otherwise, a new
        NeutralArray is created with the given path. In the latter
        case, the path must be valid up to the last '/'. For example,
        if you specify '/a/b/c', then for correct operation, there
        must be an element named 'a' at the top level and a child
        element of 'a' named 'b'. This works like 'mkdir' or 'md'
        command in some operating systems.

        ObjId -- if the first argument is an ObjId, then the Neutral
        object refers to the existing object with the specified ObjId.

        Id -- if the first argument is an Id then the Neutral object
        will refer to some entry in the ArrayElement with this Id. The
        exact index pointed to will be determined by the second
        argument, or the first entry if no second argument is
        specified.

        NeutralArray -- Same as Id (as if the Id of the NeutralArray
        was passed).

        Neutral -- create a new reference to the existing Neutral
        object.

        arg2 : if there is a second argument, then this is taken as
        the dataindex into an existing array element.

        arg3: if there is a third argument, this is taken as the
        fieldindex into an existing array field.
        """
        id_ = None
        self.oid_ = None
        dindex = None
        findex = None
        numFieldBits = None
        if len(args) >= 1:
            if isinstance(args[0], ObjId):
                self.oid_ = args[0]
            elif isinstance(args[0], Id):
                id_ = args[0].getValue()
            elif isinstance(args[0], Neutral):
                self.oid_ = args[0].oid_
            elif isinstance(args[0], NeutralArray):
                id_ = args[0].id_
            elif isinstance(args[0], str):
                try:
                    self.oid_ = _moose.ObjId(args[0])
                except ValueError:
                    # A non-existing path has been provided. Try to
                    # construct a singleton array element and create
                    # reference to the first element.
                    self_class = self.__class__
                    while (self_class.__name__ not in _moose_classes) and (
                            self_class !=
                            object):  # Handle class extension in Python.
                        self_class = self_class.__base__
                    if self_class == object:
                        raise TypeError(
                            'Class %s does not inherit any MOOSE class.' %
                            (self.__class__.__name__))
                    id_ = Id(path=args[0],
                             dims=(1, ),
                             type=self_class.__name__)
            else:
                raise TypeError(
                    'First non-keyword argument must be a number or an existing Id/ObjId/Neutral/NeutralArray object or a path.'
                )
        if len(args) >= 2:
            dindex = args[1]
        if len(args) >= 3:
            findex = args[2]
        if len(args) >= 4:
            numFieldBits = args[3]
        if (kwargs):
            try:
                id_ = kwargs['id']
            except KeyError:
                pass
            try:
                dindex = kwargs['dataIndex']
            except KeyError:
                pass
            try:
                findex = kwargs['fieldIndex']
            except KeyError:
                pass
            try:
                numFieldBits = kwargs['numFieldBits']
            except KeyError:
                pass
        if self.oid_ is None:
            if id_ is not None:
                if dindex is None:
                    self.oid_ = _moose.ObjId(id_)
                elif findex is None:
                    self.oid_ = _moose.ObjId(id_, dindex)
                elif numFieldBits is None:
                    self.oid_ = _moose.ObjId(id_, dindex, findex)
                else:
                    self.oid_ = _moose.ObjId(id_, dindex, findex, numFieldBits)
        # Check for conversion from instance of incompatible MOOSE
        # class.
        orig_classname = self.oid_.getField('class')
        if self.__class__.__name__ != orig_classname:
            orig_class = eval(orig_classname)
            self_class = self.__class__
            while self_class != object and self_class not in orig_class.mro():
                self_class = self_class.__base__
            if self_class == object:
                self.oid_ = None
                raise TypeError('Cannot convert %s to %s' %
                                (orig_class, self.__class__))
Esempio n. 5
0
    def __init__(self, *args, **kwargs):
        """
        A NeutralArray object can be constructed in many ways. The
        most basic one being:

        neutral = moose.NeutralArray('my_neutral_object', [3])

        This will create a NeutralArray object with name
        'my_neutral_object' containing 3 elements. The object will be
        created as a child of the current working entity. Any class
        derived from NeutralArray can also be created using the same
        constructor. Actually it takes keyword parameters to do that:

        intfire = moose.NeutralArray(path='/my_neutral_object', dims=[3], type='IntFire')

        will create an IntFire object of size 3 as a child of the root entity.

        If the above code is already executed,

        duplicate = moose.NeutralArray(intfire)

        will create a duplicate reference to the existing intfire
        object. They will share the same Id and any changes made via
        the MOOSE API to one will be effective on the other.
        
        """
        path = None
        dims = None
        self.id_ = None
        try:
            className = kwargs['type']
            self.className = className
        except KeyError:
            # This code is messy and depends on the class name. I
            # could not find a way to pass the element data type to
            # the class definition dynamically
            if not hasattr(self, 'className'):
                self.className = 'Neutral'
        try:
            dims = kwargs['dims']
        except KeyError:
            pass
        try:
            path = kwargs['path']
        except KeyError:
            pass
        if len(args) > 0:
            if isinstance(args[0], str):
                path = args[0]
            elif isinstance(args[0], Id):
                self.id_ = args[0]
            elif isinstance(args[0], int):
                self.id_ = Id(args[0])
        if len(args) > 1:
            dims = args[1]
        if len(args) > 2:
            self.className = args[2]
        # No existing Array element ot Id specified, create new
        # ArrayElement
        if self.id_ is None:
            if path is None:
                raise TypeError(
                    'A string path or an existing Id or an int value for existing Id must be the first argument to __init__'
                )
            if exists(path):
                self.id_ = _moose.Id(path=path)
                # Check if specified dimensions match the existing
                # object's dimensions
                if dims is not None:
                    shape = self.id_.getShape()
                    if isinstance(dims, int):
                        if shape[0] != dims:
                            raise ValueError(
                                'Specified dimensions do not match that of existing array object'
                            )
                    else:
                        if len(shape) != len(dims):
                            raise ValueError(
                                'Specified dimensions do not match that of existing array object'
                            )
                        for ii in range(len(shape)):
                            if shape[ii] != dims[ii]:
                                raise ValueError(
                                    'Specified dimensions do not match that of existing array object'
                                )
                else:
                    dims = (1)
            # Create a new ArrayElement
            _base_class = self.__class__
            _class_name = self.__class__.__name__
            if _class_name.endswith('Array'):
                _class_name = _class_name[:-len('Array')]
            # For classes extended in Python get to the first MOOSE base class
            while _class_name not in _moose_classes:
                _base_class = self.__base__
                if _base_class == object:
                    raise TypeError(
                        'Class %s does not inherit any MOOSE class.' %
                        (self.__class__.__name__))
                _class_name = _base_class.__name__
                if _class_name.endswith('Array'):
                    _class_name = _class_name[:-len('Array')]
            self.id_ = _moose.Id(path=path, dims=dims, type=_class_name)
        # Check for conversion from instance of incompatible MOOSE
        # class.
        orig_classname = self.id_[0].getField('class') + 'Array'
        if self.__class__.__name__ != orig_classname:
            orig_class = eval(orig_classname)
            self_class = self.__class__
            while self_class != object and self_class not in orig_class.mro():
                self_class = self_class.__base__
            if self_class == object:
                self.id_ = None
                raise TypeError('Cannot convert %s to %s' %
                                (orig_class, self.__class__))
Esempio n. 6
0
class NeutralArray(object):
    """
    The base class. Each NeutralArray object has an unique Id (field
    id_) and that is the only data directly visible under Python. All
    operation are done on the objects by calling functions on the Id.
    
    A NeutralArray object is actually an array. The individual
    elements in a NeutralArray are of class Neutral. To access these
    individual elements, you can index the NeutralArray object.

    """
    def __init__(self, *args, **kwargs):
        """
        A NeutralArray object can be constructed in many ways. The
        most basic one being:

        neutral = moose.NeutralArray('my_neutral_object', [3])

        This will create a NeutralArray object with name
        'my_neutral_object' containing 3 elements. The object will be
        created as a child of the current working entity. Any class
        derived from NeutralArray can also be created using the same
        constructor. Actually it takes keyword parameters to do that:

        intfire = moose.NeutralArray(path='/my_neutral_object', dims=[3], type='IntFire')

        will create an IntFire object of size 3 as a child of the root entity.

        If the above code is already executed,

        duplicate = moose.NeutralArray(intfire)

        will create a duplicate reference to the existing intfire
        object. They will share the same Id and any changes made via
        the MOOSE API to one will be effective on the other.
        
        """
        path = None
        dims = None
        self.id_ = None
        try:
            className = kwargs['type']
            self.className = className
        except KeyError:
            # This code is messy and depends on the class name. I
            # could not find a way to pass the element data type to
            # the class definition dynamically
            if not hasattr(self, 'className'):
                self.className = 'Neutral'
        try:
            dims = kwargs['dims']
        except KeyError:
            pass
        try:
            path = kwargs['path']
        except KeyError:
            pass
        if len(args) > 0:
            if isinstance(args[0], str):
                path = args[0]
            elif isinstance(args[0], Id):
                self.id_ = args[0]
            elif isinstance(args[0], int):
                self.id_ = Id(args[0])
        if len(args) > 1:
            dims = args[1]
        if len(args) > 2:
            self.className = args[2]
        # No existing Array element ot Id specified, create new
        # ArrayElement
        if self.id_ is None:
            if path is None:
                raise TypeError(
                    'A string path or an existing Id or an int value for existing Id must be the first argument to __init__'
                )
            if exists(path):
                self.id_ = _moose.Id(path=path)
                # Check if specified dimensions match the existing
                # object's dimensions
                if dims is not None:
                    shape = self.id_.getShape()
                    if isinstance(dims, int):
                        if shape[0] != dims:
                            raise ValueError(
                                'Specified dimensions do not match that of existing array object'
                            )
                    else:
                        if len(shape) != len(dims):
                            raise ValueError(
                                'Specified dimensions do not match that of existing array object'
                            )
                        for ii in range(len(shape)):
                            if shape[ii] != dims[ii]:
                                raise ValueError(
                                    'Specified dimensions do not match that of existing array object'
                                )
                else:
                    dims = (1)
            # Create a new ArrayElement
            _base_class = self.__class__
            _class_name = self.__class__.__name__
            if _class_name.endswith('Array'):
                _class_name = _class_name[:-len('Array')]
            # For classes extended in Python get to the first MOOSE base class
            while _class_name not in _moose_classes:
                _base_class = self.__base__
                if _base_class == object:
                    raise TypeError(
                        'Class %s does not inherit any MOOSE class.' %
                        (self.__class__.__name__))
                _class_name = _base_class.__name__
                if _class_name.endswith('Array'):
                    _class_name = _class_name[:-len('Array')]
            self.id_ = _moose.Id(path=path, dims=dims, type=_class_name)
        # Check for conversion from instance of incompatible MOOSE
        # class.
        orig_classname = self.id_[0].getField('class') + 'Array'
        if self.__class__.__name__ != orig_classname:
            orig_class = eval(orig_classname)
            self_class = self.__class__
            while self_class != object and self_class not in orig_class.mro():
                self_class = self_class.__base__
            if self_class == object:
                self.id_ = None
                raise TypeError('Cannot convert %s to %s' %
                                (orig_class, self.__class__))

    def getFieldNames(self, ftype=''):
        """Return a list of fields available in this object.

        Parameters:

        str ftype -- (default '') category of field, valid values are:
        valueFinfo, lookupFinfo, srcFinfo, destFinfo or sharedFinfo.

        If empty string or not specified, returns names of fields from
        all categories.
        """

        return self.id_[0].getFieldNames(ftype)

    def getFieldType(self, field, ftype=''):
        """Return the data type of the field as a string."""
        return self.id_[0].getFieldType(field, ftype)

    def __getitem__(self, index):
        objid = self.id_[index]
        retclass = eval(self.id_[0].getField('class'))
        ret = retclass(objid)
        return ret

    def __len__(self):
        return len(self.id_)

    def __contains__(self, other):
        if isinstance(other, Neutral):
            return other.oid_ in self.id_
        elif isinstance(other, ObjId):
            return other in self.id_
        else:
            return False

    def __repr__(self):
        return self.id_.getPath()

    path = property(lambda self: self.id_.getPath())
    fieldNames = property(lambda self: self.id_[0].getFieldNames('valueFinfo'))
    name = property(lambda self: self.id_[0].name)
    shape = property(lambda self: self.id_.getShape())
Esempio n. 7
0
from _moose import wildcardFind as _wildcardFind  # We override the original
import __main__ as main

sequence_types = [
    'vector<double>', 'vector<int>', 'vector<long>', 'vector<unsigned int>',
    'vector<float>', 'vector<unsigned long>', 'vector<short>', 'vector<Id>',
    'vector<ObjId>'
]
known_types = [
    'void', 'char', 'short', 'int', 'unsigned int', 'double', 'float', 'long',
    'unsigned long', 'string', 'Id', 'ObjId'
] + sequence_types

# Dict of available MOOSE class names. This is faster for look-up
_moose_classes = dict([(child[0].name, True)
                       for child in Id('/classes')[0].getField('children')])

# class _MooseDescriptor(object):
#     """Descriptor to give access to MOOSE class' ValueFinfo attributes"""
#     def __init__(self, name):
#         self.name = name

#     def __get__(self, obj, objtype=None):
#         return obj.oid_.getField(self.name)

#     def __set__(self, obj, value):
#         obj.oid_.setField(self.name, value)

#     def __delete__(self, obj):
#         raise AttributeError('ValueFinfos cannot be deleted.')
Esempio n. 8
0
    def __init__(self, *args, **kwargs):
        """
        A NeutralArray object can be constructed in many ways. The
        most basic one being:

        neutral = moose.NeutralArray('my_neutral_object', [3])

        This will create a NeutralArray object with name
        'my_neutral_object' containing 3 elements. The object will be
        created as a child of the current working entity. Any class
        derived from NeutralArray can also be created using the same
        constructor. Actually it takes keyword parameters to do that:

        intfire = moose.NeutralArray(path='/my_neutral_object', dims=[3], type='IntFire')

        will create an IntFire object of size 3 as a child of the root entity.

        If the above code is already executed,

        duplicate = moose.NeutralArray(intfire)

        will create a duplicate reference to the existing intfire
        object. They will share the same Id and any changes made via
        the MOOSE API to one will be effective on the other.
        
        """
        path = None
        dims = None
        self.id_ = None
        try:
            className = kwargs['type']
            self.className = className
        except KeyError:
            # This code is messy and depends on the class name. I
            # could not find a way to pass the element data type to
            # the class definition dynamically
            if not hasattr(self, 'className'):
                self.className = 'Neutral'
        try:
            dims = kwargs['dims']
        except KeyError:
            pass
        try:
            path = kwargs['path']
        except KeyError:
            pass
        if len(args) > 0:
            if isinstance(args[0], str):
                path = args[0]
            elif isinstance(args[0], Id):
                self.id_ = args[0]
            elif isinstance(args[0], int):
                self.id_ = Id(args[0])
        if len(args) > 1:
            dims = args[1]
        if len(args) > 2:
            self.className = args[2]
        # No existing Array element ot Id specified, create new
        # ArrayElement
        if self.id_ is None:
            if path is None:
                raise TypeError('A string path or an existing Id or an int value for existing Id must be the first argument to __init__')
            if exists(path):
                self.id_ = _moose.Id(path=path)
                # Check if specified dimensions match the existing
                # object's dimensions
                if dims is not None:
                    shape = self.id_.getShape()
                    if isinstance(dims, int):
                        if shape[0] != dims:
                            raise ValueError('Specified dimensions do not match that of existing array object')
                    else:
                        if len(shape) != len(dims):
                            raise ValueError('Specified dimensions do not match that of existing array object')
                        for ii in range(len(shape)):
                            if shape[ii] != dims[ii]:
                                raise ValueError('Specified dimensions do not match that of existing array object')
                else:
                    dims = (1)
            # Create a new ArrayElement
            _base_class = self.__class__
            _class_name = self.__class__.__name__
            if _class_name.endswith('Array'):
                _class_name = _class_name[:-len('Array')]
            # For classes extended in Python get to the first MOOSE base class
            while _class_name not in _moose_classes:
                _base_class = self.__base__
                if _base_class == object:
                    raise TypeError('Class %s does not inherit any MOOSE class.' % (self.__class__.__name__))                    
                _class_name = _base_class.__name__
                if _class_name.endswith('Array'):
                    _class_name = _class_name[:-len('Array')]
            self.id_ = _moose.Id(path=path, dims=dims, type=_class_name)
        # Check for conversion from instance of incompatible MOOSE
        # class.
        orig_classname = self.id_[0].getField('class') + 'Array'
        if self.__class__.__name__ != orig_classname:
            orig_class = eval(orig_classname)
            self_class = self.__class__
            while self_class != object and self_class not in orig_class.mro():
                self_class = self_class.__base__
            if self_class == object:
                self.id_ = None
                raise TypeError('Cannot convert %s to %s' % (orig_class, self.__class__))
Esempio n. 9
0
class NeutralArray(object):
    """
    The base class. Each NeutralArray object has an unique Id (field
    id_) and that is the only data directly visible under Python. All
    operation are done on the objects by calling functions on the Id.
    
    A NeutralArray object is actually an array. The individual
    elements in a NeutralArray are of class Neutral. To access these
    individual elements, you can index the NeutralArray object.

    """
    def __init__(self, *args, **kwargs):
        """
        A NeutralArray object can be constructed in many ways. The
        most basic one being:

        neutral = moose.NeutralArray('my_neutral_object', [3])

        This will create a NeutralArray object with name
        'my_neutral_object' containing 3 elements. The object will be
        created as a child of the current working entity. Any class
        derived from NeutralArray can also be created using the same
        constructor. Actually it takes keyword parameters to do that:

        intfire = moose.NeutralArray(path='/my_neutral_object', dims=[3], type='IntFire')

        will create an IntFire object of size 3 as a child of the root entity.

        If the above code is already executed,

        duplicate = moose.NeutralArray(intfire)

        will create a duplicate reference to the existing intfire
        object. They will share the same Id and any changes made via
        the MOOSE API to one will be effective on the other.
        
        """
        path = None
        dims = None
        self.id_ = None
        try:
            className = kwargs['type']
            self.className = className
        except KeyError:
            # This code is messy and depends on the class name. I
            # could not find a way to pass the element data type to
            # the class definition dynamically
            if not hasattr(self, 'className'):
                self.className = 'Neutral'
        try:
            dims = kwargs['dims']
        except KeyError:
            pass
        try:
            path = kwargs['path']
        except KeyError:
            pass
        if len(args) > 0:
            if isinstance(args[0], str):
                path = args[0]
            elif isinstance(args[0], Id):
                self.id_ = args[0]
            elif isinstance(args[0], int):
                self.id_ = Id(args[0])
        if len(args) > 1:
            dims = args[1]
        if len(args) > 2:
            self.className = args[2]
        # No existing Array element ot Id specified, create new
        # ArrayElement
        if self.id_ is None:
            if path is None:
                raise TypeError('A string path or an existing Id or an int value for existing Id must be the first argument to __init__')
            if exists(path):
                self.id_ = _moose.Id(path=path)
                # Check if specified dimensions match the existing
                # object's dimensions
                if dims is not None:
                    shape = self.id_.getShape()
                    if isinstance(dims, int):
                        if shape[0] != dims:
                            raise ValueError('Specified dimensions do not match that of existing array object')
                    else:
                        if len(shape) != len(dims):
                            raise ValueError('Specified dimensions do not match that of existing array object')
                        for ii in range(len(shape)):
                            if shape[ii] != dims[ii]:
                                raise ValueError('Specified dimensions do not match that of existing array object')
                else:
                    dims = (1)
            # Create a new ArrayElement
            _base_class = self.__class__
            _class_name = self.__class__.__name__
            if _class_name.endswith('Array'):
                _class_name = _class_name[:-len('Array')]
            # For classes extended in Python get to the first MOOSE base class
            while _class_name not in _moose_classes:
                _base_class = self.__base__
                if _base_class == object:
                    raise TypeError('Class %s does not inherit any MOOSE class.' % (self.__class__.__name__))                    
                _class_name = _base_class.__name__
                if _class_name.endswith('Array'):
                    _class_name = _class_name[:-len('Array')]
            self.id_ = _moose.Id(path=path, dims=dims, type=_class_name)
        # Check for conversion from instance of incompatible MOOSE
        # class.
        orig_classname = self.id_[0].getField('class') + 'Array'
        if self.__class__.__name__ != orig_classname:
            orig_class = eval(orig_classname)
            self_class = self.__class__
            while self_class != object and self_class not in orig_class.mro():
                self_class = self_class.__base__
            if self_class == object:
                self.id_ = None
                raise TypeError('Cannot convert %s to %s' % (orig_class, self.__class__))

    def getFieldNames(self, ftype=''):
        """Return a list of fields available in this object.

        Parameters:

        str ftype -- (default '') category of field, valid values are:
        valueFinfo, lookupFinfo, srcFinfo, destFinfo or sharedFinfo.

        If empty string or not specified, returns names of fields from
        all categories.
        """
        
        return self.id_[0].getFieldNames(ftype)

    def getFieldType(self, field, ftype=''):
        """Return the data type of the field as a string."""
        return self.id_[0].getFieldType(field, ftype)

    def __getitem__(self, index):
        objid = self.id_[index]
        retclass = eval(self.id_[0].getField('class'))
        ret = retclass(objid)
        return ret

    def __len__(self):
        return len(self.id_)

    def __contains__(self, other):
        if isinstance(other, Neutral):
            return other.oid_ in self.id_
        elif isinstance(other, ObjId):
            return other in self.id_
        else:
            return False

    def __repr__(self):
        return self.id_.getPath()

    path = property(lambda self: self.id_.getPath())
    fieldNames = property(lambda self: self.id_[0].getFieldNames('valueFinfo'))
    name = property(lambda self: self.id_[0].name)
    shape = property(lambda self: self.id_.getShape())