1"""Python wrappers for MOAB Types."""
2
3from pymoab cimport moab
4from pymoab cimport tag_conventions
5
6cimport numpy as np
7import numpy as np
8
9_eh_py_type = np.uint64
10
11cdef class MOABErrorCode:
12
13    cdef readonly moab.ErrorCode error_value
14
15    cdef readonly dict err_strings
16    def __cinit__(self, value = 0):
17        if isinstance(value, MOABErrorCode):
18            self.error_value = value.error_value
19        else:
20            self.error_value = <moab.ErrorCode> value
21
22        self.err_strings = { moab.MB_SUCCESS : "MB_SUCCESS",
23                             moab.MB_INDEX_OUT_OF_RANGE : "MB_INDEX_OUT_OF_RANGE",
24                             moab.MB_TYPE_OUT_OF_RANGE : "MB_TYPE_OUT_OF_RANGE",
25                             moab.MB_MEMORY_ALLOCATION_FAILED : "MB_MEMORY_ALLOCATION_FAILED",
26                             moab.MB_ENTITY_NOT_FOUND : "MB_ENTITY_NOT_FOUND",
27                             moab.MB_MULTIPLE_ENTITIES_FOUND : "MB_MULTIPLE_ENTITIES_FOUND",
28                             moab.MB_TAG_NOT_FOUND : "MB_TAG_NOT_FOUND",
29                             moab.MB_FILE_DOES_NOT_EXIST : "MB_FILE_DOES_NOT_EXIST",
30                             moab.MB_FILE_WRITE_ERROR : "MB_FILE_WRITE_ERROR",
31                             moab.MB_NOT_IMPLEMENTED : "MB_NOT_IMPLEMENTED",
32                             moab.MB_ALREADY_ALLOCATED : "MB_ALREADY_ALLOCATED",
33                             moab.MB_VARIABLE_DATA_LENGTH : "MB_VARIABLE_DATA_LENGTH",
34                             moab.MB_INVALID_SIZE : "MB_INVALID_SIZE",
35                             moab.MB_UNSUPPORTED_OPERATION : "MB_UNSUPPORTED_OPERATION",
36                             moab.MB_UNHANDLED_OPTION : "MB_UNHANDLED_OPTION",
37                             moab.MB_STRUCTURED_MESH : "MB_STRUCTURED_MESH",
38                             moab.MB_FAILURE : "MB_FAILURE" }
39
40    def __richcmp__(self, other, op):
41        if op == 2:
42            if isinstance(other, MOABErrorCode):
43                return self.error_value == other.error_value
44            elif type(other) == int:
45                return self.error_value == other
46        else:
47            return NotImplemented
48
49    def __hash__(self):
50        return self.error_value
51
52    def __repr__(self):
53        return self.__str__()
54
55    def __str__(self):
56        return "MOAB ErrorCode: "+self.err_strings[self.error_value]
57
58
59# Error codes
60MB_SUCCESS = MOABErrorCode(moab.MB_SUCCESS)
61MB_INDEX_OUT_OF_RANGE = MOABErrorCode(moab.MB_INDEX_OUT_OF_RANGE)
62MB_TYPE_OUT_OF_RANGE = MOABErrorCode(moab.MB_TYPE_OUT_OF_RANGE)
63MB_MEMORY_ALLOCATION_FAILED = MOABErrorCode(moab.MB_MEMORY_ALLOCATION_FAILED)
64MB_ENTITY_NOT_FOUND = MOABErrorCode(moab.MB_ENTITY_NOT_FOUND)
65MB_MULTIPLE_ENTITIES_FOUND = MOABErrorCode(moab.MB_MULTIPLE_ENTITIES_FOUND)
66MB_TAG_NOT_FOUND = MOABErrorCode(moab.MB_TAG_NOT_FOUND)
67MB_FILE_DOES_NOT_EXIST = MOABErrorCode(moab.MB_FILE_DOES_NOT_EXIST)
68MB_FILE_WRITE_ERROR = MOABErrorCode(moab.MB_FILE_WRITE_ERROR)
69MB_NOT_IMPLEMENTED = MOABErrorCode(moab.MB_NOT_IMPLEMENTED)
70MB_ALREADY_ALLOCATED = MOABErrorCode(moab.MB_ALREADY_ALLOCATED)
71MB_VARIABLE_DATA_LENGTH = MOABErrorCode(moab.MB_VARIABLE_DATA_LENGTH)
72MB_INVALID_SIZE = MOABErrorCode(moab.MB_INVALID_SIZE)
73MB_UNSUPPORTED_OPERATION = MOABErrorCode(moab.MB_UNSUPPORTED_OPERATION)
74MB_UNHANDLED_OPTION = MOABErrorCode(moab.MB_UNHANDLED_OPTION)
75MB_STRUCTURED_MESH = MOABErrorCode(moab.MB_STRUCTURED_MESH)
76MB_FAILURE = MOABErrorCode(moab.MB_FAILURE)
77
78
79cdef dict _ERROR_MSGS = {
80    MB_INDEX_OUT_OF_RANGE: (IndexError, 'MOAB index out of range'),
81    MB_TYPE_OUT_OF_RANGE: (TypeError, 'Incorrect MOAB type, out of range'),
82    MB_MEMORY_ALLOCATION_FAILED: (MemoryError, 'MOAB memory allocation'),
83    MB_ENTITY_NOT_FOUND: (RuntimeError, 'Entity not found'),
84    MB_MULTIPLE_ENTITIES_FOUND: (RuntimeError, 'Multiple entities found'),
85    MB_TAG_NOT_FOUND: (RuntimeError, 'Tag not found'),
86    MB_FILE_DOES_NOT_EXIST: (IOError, 'File not found'),
87    MB_FILE_WRITE_ERROR: (IOError, 'File write error'),
88    MB_NOT_IMPLEMENTED: (NotImplementedError, '[MOAB]'),
89    MB_ALREADY_ALLOCATED: (MemoryError, 'already allocated'),
90    MB_VARIABLE_DATA_LENGTH: (TypeError, 'variable length data'),
91    MB_INVALID_SIZE: (ValueError, 'invalid size'),
92    MB_UNSUPPORTED_OPERATION: (RuntimeError, 'unsupported operation'),
93    MB_UNHANDLED_OPTION: (RuntimeError, 'unhandled option'),
94    MB_STRUCTURED_MESH: (RuntimeError, 'structured mesh'),
95    MB_FAILURE: (RuntimeError, '[MOAB] failure'),
96    }
97
98def check_error(err, tuple exceptions = (), **kwargs):
99    """Checks error status code and raises error if needed."""
100    for exception in exceptions:
101        if exception == err:
102            return
103    if err == MB_SUCCESS:
104        return
105    errtype, msg = _ERROR_MSGS[err]
106    if len(kwargs) > 0:
107        msg += ': '
108        msg += ', '.join(sorted(['{0}={1!r}'.format(k, v) for k, v in kwargs.items()]))
109    raise errtype(MOABErrorCode(err))
110
111# Data Types
112MB_TYPE_OPAQUE = moab.MB_TYPE_OPAQUE
113MB_TYPE_INTEGER = moab.MB_TYPE_INTEGER
114MB_TYPE_DOUBLE = moab.MB_TYPE_DOUBLE
115MB_TYPE_BIT = moab.MB_TYPE_BIT
116MB_TYPE_HANDLE = moab.MB_TYPE_HANDLE
117MB_MAX_DATA_TYPE = moab.MB_MAX_DATA_TYPE
118
119
120_TAG_TYPE_STRS = {
121    MB_TYPE_OPAQUE : "MB_TYPE_OPAQUE",
122    MB_TYPE_INTEGER : "MB_TYPE_INTEGER",
123    MB_TYPE_DOUBLE : "MB_TYPE_DOUBLE",
124    MB_TYPE_BIT : "MB_TYPE_BIT",
125    MB_TYPE_HANDLE : "MB_TYPE_HANDLE",
126    MB_MAX_DATA_TYPE : "MB_MAX_DATA_TYPE"
127}
128
129_DTYPE_CONV = {
130    MB_TYPE_OPAQUE: 'S',
131    MB_TYPE_INTEGER: 'int32',
132    MB_TYPE_DOUBLE: 'float64',
133    MB_TYPE_BIT: 'bool',
134    MB_TYPE_HANDLE: 'uint64',
135    MB_MAX_DATA_TYPE: 'uint64'
136}
137
138_VALID_DTYPES= {
139    MB_TYPE_OPAQUE: frozenset(['S','U','O','object']),
140    MB_TYPE_INTEGER: frozenset(['i','int8','int16','int32','int64','O','object']),
141    MB_TYPE_DOUBLE: frozenset(['float64','float','f8','f', 'O','object',]),
142    MB_TYPE_BIT: frozenset(['f','int8','int16','int32','int64','S1','bool','O','object']),
143    MB_TYPE_HANDLE: frozenset(['uint64','O','object']),
144    MB_MAX_DATA_TYPE: frozenset(['uint64','O','object'])
145}
146
147_VALID_NATIVE_TYPES = {
148    int: MB_TYPE_INTEGER,
149    float: MB_TYPE_DOUBLE,
150    str: MB_TYPE_OPAQUE,
151    object: MB_TYPE_OPAQUE,
152    np.uint64 : MB_TYPE_HANDLE
153}
154
155def pymoab_data_type(input_type):
156    """
157    Attempts to find a PyMOAB datatype given a Python native type or
158    NumPy dtype
159    """
160
161    # check native types
162    try:
163        t = _VALID_NATIVE_TYPES[input_type]
164        return t
165    except KeyError:
166        print("Checking all types...")
167        pass
168
169    # check valid dtypes
170    for k in _VALID_DTYPES.keys():
171        if input_type in _VALID_DTYPES[k]:
172            return k
173
174    raise ValueError("Could not determine the PyMOAB data type.")
175
176def _convert_array(iterable, accepted_types, return_dtype):
177    err_msg = "Incorrect datatype found in array: {}"
178    #if this is already an array of the correct type, avoid the loop
179    if isinstance(iterable, np.ndarray) and iterable.dtype == return_dtype:
180        return  iterable
181    #if not, each entry in the iterable should be verified
182    for entry in iterable:
183        assert (isinstance(entry, accepted_types)), err_msg.format(type(entry))
184        #if this is true, then create an array from the iterable
185    return np.fromiter(iterable, return_dtype)
186
187def _eh_array(iterable):
188    err_msg = """
189               Invalid EntityHandle type is being used.  Please ensure all
190               EntityHandles are either Python type long or NumPy dtype uint64.
191              """
192    # get dtype for EntityHandles
193    EH_DTYPE = _DTYPE_CONV[MB_TYPE_HANDLE]
194    # try to convert array
195    try:
196        arr = _convert_array(iterable, (_eh_py_type,), EH_DTYPE)
197    except:
198        raise ValueError(err_msg)
199    # return array if successful
200    return arr
201
202def np_tag_type(type):
203    return _DTYPE_CONV[type]
204
205def validate_type(tag_type,tag_length,tag_data):
206
207    #ensure this type is supported
208    assert tag_type in _DTYPE_CONV.keys(), "Invalid Tag Type"
209    #and that it is the correct shape
210    assert tag_data.ndim == 0 or tag_data.ndim == 1, "Not a flat array"
211
212
213    if MB_TYPE_OPAQUE == tag_type:
214        #so long as the array is some kind of string type, we're happy
215        is_valid = tag_data.dtype.char in _VALID_DTYPES[tag_type]
216        final_type = _DTYPE_CONV[tag_type]+str(tag_length)
217    else:
218        is_valid = str(tag_data.dtype) in _VALID_DTYPES[tag_type]
219        final_type = _DTYPE_CONV[tag_type]
220
221    assert is_valid, "Data is invalid for Tag. Please verify data length and type."
222    tag_data = np.asarray(tag_data, dtype=final_type)
223    return tag_data
224
225# Entity types
226MBVERTEX = moab.MBVERTEX
227MBEDGE = moab.MBEDGE
228MBTRI = moab.MBTRI
229MBQUAD = moab.MBQUAD
230MBPOLYGON = moab.MBPOLYGON
231MBTET = moab.MBTET
232MBPYRAMID = moab.MBPYRAMID
233MBPRISM = moab.MBPRISM
234MBKNIFE = moab.MBKNIFE
235MBHEX = moab.MBHEX
236MBPOLYHEDRON = moab.MBPOLYHEDRON
237MBENTITYSET = moab.MBENTITYSET
238MBMAXTYPE = moab.MBMAXTYPE
239
240# Tag Types
241MB_TAG_BIT  = moab.MB_TAG_BIT
242MB_TAG_SPARSE = moab.MB_TAG_SPARSE
243MB_TAG_DENSE = moab.MB_TAG_DENSE
244MB_TAG_MESH = moab.MB_TAG_MESH
245MB_TAG_BYTES = moab.MB_TAG_BYTES
246MB_TAG_VARLEN = moab.MB_TAG_VARLEN
247MB_TAG_CREAT = moab.MB_TAG_CREAT
248MB_TAG_EXCL = moab.MB_TAG_EXCL
249MB_TAG_STORE = moab.MB_TAG_STORE
250MB_TAG_ANY = moab.MB_TAG_ANY
251MB_TAG_NOOPQ = moab.MB_TAG_NOOPQ
252MB_TAG_DFTOK = moab.MB_TAG_DFTOK
253
254# Query selection types
255INTERSECT = 0
256UNION = 1
257
258MESHSET_TRACK_OWNER = moab.MESHSET_TRACK_OWNER
259MESHSET_SET = moab.MESHSET_SET
260MESHSET_ORDERED = moab.MESHSET_ORDERED
261
262MATERIAL_SET_TAG_NAME   = str(tag_conventions.MATERIAL_SET_TAG_NAME.decode())
263DIRICHLET_SET_TAG_NAME  = str(tag_conventions.DIRICHLET_SET_TAG_NAME.decode())
264NEUMANN_SET_TAG_NAME    = str(tag_conventions.NEUMANN_SET_TAG_NAME.decode())
265HAS_MID_NODES_TAG_NAME  = str(tag_conventions.HAS_MID_NODES_TAG_NAME.decode())
266GEOM_DIMENSION_TAG_NAME = str(tag_conventions.GEOM_DIMENSION_TAG_NAME.decode())
267MESH_TRANSFORM_TAG_NAME = str(tag_conventions.MESH_TRANSFORM_TAG_NAME.decode())
268GLOBAL_ID_TAG_NAME      = str(tag_conventions.GLOBAL_ID_TAG_NAME.decode())
269CATEGORY_TAG_NAME       = str(tag_conventions.CATEGORY_TAG_NAME.decode())
270CATEGORY_TAG_SIZE       = tag_conventions.CATEGORY_TAG_SIZE
271NAME_TAG_NAME           = str(tag_conventions.NAME_TAG_NAME.decode())
272NAME_TAG_SIZE           = tag_conventions.NAME_TAG_SIZE
273