pytecplot 1.5.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pytecplot-1.5.2.dist-info/LICENSE.html +77 -0
- pytecplot-1.5.2.dist-info/METADATA +508 -0
- pytecplot-1.5.2.dist-info/RECORD +97 -0
- pytecplot-1.5.2.dist-info/WHEEL +5 -0
- pytecplot-1.5.2.dist-info/top_level.txt +1 -0
- tecplot/__init__.py +94 -0
- tecplot/annotation/__init__.py +7 -0
- tecplot/annotation/annotation.py +223 -0
- tecplot/annotation/geometry.py +369 -0
- tecplot/annotation/georeference.py +33 -0
- tecplot/annotation/image.py +185 -0
- tecplot/annotation/iter.py +105 -0
- tecplot/annotation/polyline.py +381 -0
- tecplot/annotation/text.py +744 -0
- tecplot/constant.py +401 -0
- tecplot/data/__init__.py +34 -0
- tecplot/data/array.py +645 -0
- tecplot/data/create.py +1 -0
- tecplot/data/dataset.py +1809 -0
- tecplot/data/extract.py +544 -0
- tecplot/data/face_neighbors.py +494 -0
- tecplot/data/facemap.py +814 -0
- tecplot/data/load.py +2075 -0
- tecplot/data/nodemap.py +577 -0
- tecplot/data/operate.py +928 -0
- tecplot/data/query.py +334 -0
- tecplot/data/save.py +343 -0
- tecplot/data/variable.py +280 -0
- tecplot/data/zone.py +841 -0
- tecplot/exception.py +201 -0
- tecplot/export/__init__.py +13 -0
- tecplot/export/animation.py +521 -0
- tecplot/export/export_setup.py +318 -0
- tecplot/export/image.py +577 -0
- tecplot/export/print_setup.py +218 -0
- tecplot/export/time_animation.py +607 -0
- tecplot/extension/__init__.py +14 -0
- tecplot/extension/ipython.py +68 -0
- tecplot/layout/__init__.py +20 -0
- tecplot/layout/frame.py +1285 -0
- tecplot/layout/layout.py +488 -0
- tecplot/layout/page.py +541 -0
- tecplot/legend/__init__.py +4 -0
- tecplot/legend/contour_legend.py +516 -0
- tecplot/legend/legend.py +141 -0
- tecplot/legend/line_legend.py +66 -0
- tecplot/legend/rgb_coloring_legend.py +291 -0
- tecplot/legend/scatter_legend.py +136 -0
- tecplot/macro.py +339 -0
- tecplot/plot/__init__.py +62 -0
- tecplot/plot/axes.py +881 -0
- tecplot/plot/axis.py +1350 -0
- tecplot/plot/blanking.py +584 -0
- tecplot/plot/contour.py +1302 -0
- tecplot/plot/effects.py +162 -0
- tecplot/plot/fieldmap.py +2159 -0
- tecplot/plot/grid.py +758 -0
- tecplot/plot/isosurface.py +1167 -0
- tecplot/plot/labels.py +338 -0
- tecplot/plot/linemap.py +1905 -0
- tecplot/plot/linking.py +489 -0
- tecplot/plot/plot.py +1791 -0
- tecplot/plot/rgb_coloring.py +281 -0
- tecplot/plot/scatter.py +396 -0
- tecplot/plot/slice.py +1544 -0
- tecplot/plot/streamtrace.py +1949 -0
- tecplot/plot/symbol.py +567 -0
- tecplot/plot/ticks.py +666 -0
- tecplot/plot/title.py +380 -0
- tecplot/plot/vector.py +679 -0
- tecplot/plot/view.py +868 -0
- tecplot/session/__init__.py +112 -0
- tecplot/session/aux_data.py +276 -0
- tecplot/session/config.py +92 -0
- tecplot/session/session.py +425 -0
- tecplot/session/state_changed.py +225 -0
- tecplot/session/style.py +504 -0
- tecplot/tecutil/__init__.py +16 -0
- tecplot/tecutil/arglist.py +230 -0
- tecplot/tecutil/captured_output.py +177 -0
- tecplot/tecutil/constant.py +1312 -0
- tecplot/tecutil/index_set.py +118 -0
- tecplot/tecutil/lock.py +36 -0
- tecplot/tecutil/message_pb2.py +39 -0
- tecplot/tecutil/preamble.py +54 -0
- tecplot/tecutil/stringlist.py +114 -0
- tecplot/tecutil/sv.py +1662 -0
- tecplot/tecutil/tecutil.py +12402 -0
- tecplot/tecutil/tecutil_client.py +627 -0
- tecplot/tecutil/tecutil_connector.py +937 -0
- tecplot/tecutil/tecutil_rpc.py +6845 -0
- tecplot/tecutil/util.py +332 -0
- tecplot/text/__init__.py +3 -0
- tecplot/text/font.py +224 -0
- tecplot/text/label_format.py +374 -0
- tecplot/text/textbox.py +106 -0
- tecplot/version.py +41 -0
tecplot/data/array.py
ADDED
|
@@ -0,0 +1,645 @@
|
|
|
1
|
+
from builtins import range, super
|
|
2
|
+
|
|
3
|
+
import ctypes
|
|
4
|
+
import logging
|
|
5
|
+
import textwrap
|
|
6
|
+
|
|
7
|
+
from ctypes import (addressof, byref, cast, c_double, c_float, c_int8, c_int16,
|
|
8
|
+
c_int32, c_int64, c_void_p, POINTER)
|
|
9
|
+
|
|
10
|
+
from ..tecutil import _tecutil, _tecutil_connector
|
|
11
|
+
from ..constant import *
|
|
12
|
+
from ..exception import *
|
|
13
|
+
from .. import session, tecutil
|
|
14
|
+
from . import operate
|
|
15
|
+
|
|
16
|
+
log = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Array(c_void_p):
|
|
20
|
+
"""Low-level accessor for underlying data within a `Dataset <tecplot.data.Dataset>`.
|
|
21
|
+
|
|
22
|
+
This object exposes a list-like interface to the underlying data array.
|
|
23
|
+
Using it, values can be directly queried and modified. After any
|
|
24
|
+
modification to the data, the Tecplot Engine will have to be notified of
|
|
25
|
+
the change. This notification will happen automatically in most cases, but
|
|
26
|
+
can be turned off using the `suspend context <tecplot.session.suspend>` for
|
|
27
|
+
a significant performance increase on large data sets.
|
|
28
|
+
|
|
29
|
+
Accessing values within an `Array` is done through the standard ``[]``
|
|
30
|
+
syntax::
|
|
31
|
+
|
|
32
|
+
>>> print(array[3])
|
|
33
|
+
3.1415
|
|
34
|
+
|
|
35
|
+
The numbers passed are interpreted just like Python's built-in
|
|
36
|
+
:py:class:`slice` object::
|
|
37
|
+
|
|
38
|
+
>>> # print the values at indices: 5, 7, 9
|
|
39
|
+
>>> print(array[5:10:2])
|
|
40
|
+
[1.0, 1.0, 1.0]
|
|
41
|
+
|
|
42
|
+
Elements within an array can be manipulated in-place with the assignment
|
|
43
|
+
operator::
|
|
44
|
+
|
|
45
|
+
>>> array[3] = 5.0
|
|
46
|
+
>>> print(array[3])
|
|
47
|
+
5.0
|
|
48
|
+
|
|
49
|
+
Element-by-element access is *not* guaranteed to be performant and users
|
|
50
|
+
should avoid writing loops over indices in Python. Instead, whole arrays
|
|
51
|
+
should be used. This will effectively push the loop down to the underlying
|
|
52
|
+
native library and will be much faster in virtually all cases.
|
|
53
|
+
|
|
54
|
+
Consider this array of 10k elements::
|
|
55
|
+
|
|
56
|
+
>>> ds = frame.create_dataset('Dataset', ['x'])
|
|
57
|
+
>>> zn = ds.add_ordered_zone('Zone', 10000)
|
|
58
|
+
>>> array = zn.values('x')
|
|
59
|
+
|
|
60
|
+
The following loop, which takes the sine of all values in the array will
|
|
61
|
+
require several Python function calls per element which is a tremendous
|
|
62
|
+
overhead::
|
|
63
|
+
|
|
64
|
+
>>> import math
|
|
65
|
+
>>> for i in range(len(ar)):
|
|
66
|
+
... ar[i] = math.sin(ar[i])
|
|
67
|
+
|
|
68
|
+
An immediate improvement on this can be made by looping over the elements
|
|
69
|
+
in Python only when reading the values, but assigning them using the
|
|
70
|
+
whole array. This will be several times faster for even modest arrays::
|
|
71
|
+
|
|
72
|
+
>>> ar[:] = [math.sin(x) for x in ar]
|
|
73
|
+
|
|
74
|
+
But there is still a large performance penalty for looping over elements
|
|
75
|
+
directly in Python and PyTecplot supports two solutions for large arrays:
|
|
76
|
+
`tecplot.data.operate.execute_equation` and `Array.as_numpy_array()`.
|
|
77
|
+
Please refer to these for details. Continuing with the example above, we
|
|
78
|
+
could accomplish the same thing with either of the following using
|
|
79
|
+
`execute_equation()` (assuming the array is identified by the first zone,
|
|
80
|
+
first variable)::
|
|
81
|
+
|
|
82
|
+
>>> from tecplot.data.operate import execute_equation
|
|
83
|
+
>>> execute_equation('V1 = SIN(V1)', zones=[dataset.zone(0)])
|
|
84
|
+
|
|
85
|
+
or by using the `numpy` library::
|
|
86
|
+
|
|
87
|
+
>>> import numpy as np
|
|
88
|
+
>>> ar[:] = np.sin(ar[:])
|
|
89
|
+
|
|
90
|
+
In both of these cases, the calculation of the sine and loop over elements
|
|
91
|
+
is pushed to the low level library and is much faster. Note that only the
|
|
92
|
+
`execute_equation()` solution does the calculation within Tecplot and does
|
|
93
|
+
not require the data to copied out to Python so it will typically be the
|
|
94
|
+
fastest option.
|
|
95
|
+
|
|
96
|
+
.. note::
|
|
97
|
+
|
|
98
|
+
When modifying data using this class, it may be necessary to update the
|
|
99
|
+
range of any associated contouring with a call to
|
|
100
|
+
`ContourLevels.reset()` or similar. This will ensure that the total
|
|
101
|
+
range of the new values is presented in the plot.
|
|
102
|
+
"""
|
|
103
|
+
def __init__(self, zone, variable):
|
|
104
|
+
self.zone = zone
|
|
105
|
+
self.variable = variable
|
|
106
|
+
super().__init__(self._native_reference())
|
|
107
|
+
|
|
108
|
+
@property
|
|
109
|
+
def _cache(self):
|
|
110
|
+
if _tecutil_connector.suspended:
|
|
111
|
+
_tecutil_connector._delete_caches.append(self._delete_cache)
|
|
112
|
+
return True
|
|
113
|
+
else:
|
|
114
|
+
return False
|
|
115
|
+
|
|
116
|
+
def _delete_cache(self):
|
|
117
|
+
attrs = '''
|
|
118
|
+
_rnr _wnr _rrp _wrp
|
|
119
|
+
_location
|
|
120
|
+
_len
|
|
121
|
+
_data_type
|
|
122
|
+
'''.split()
|
|
123
|
+
for attr in attrs:
|
|
124
|
+
try:
|
|
125
|
+
delattr(self, attr)
|
|
126
|
+
except AttributeError:
|
|
127
|
+
pass
|
|
128
|
+
|
|
129
|
+
def _native_reference(self, writable=False):
|
|
130
|
+
args = (self.zone.dataset.uid, self.zone.index + 1, self.variable.index + 1)
|
|
131
|
+
if writable:
|
|
132
|
+
if self._cache:
|
|
133
|
+
if not hasattr(self, '_wnr'):
|
|
134
|
+
with tecutil.lock():
|
|
135
|
+
self._wnr = _tecutil.DataValueGetWritableNativeRefByUniqueID(*args)
|
|
136
|
+
return self._wnr
|
|
137
|
+
else:
|
|
138
|
+
with tecutil.lock():
|
|
139
|
+
return _tecutil.DataValueGetWritableNativeRefByUniqueID(*args)
|
|
140
|
+
else:
|
|
141
|
+
if self._cache:
|
|
142
|
+
if not hasattr(self, '_rnr'):
|
|
143
|
+
with tecutil.lock():
|
|
144
|
+
self._rnr = _tecutil.DataValueGetReadableNativeRefByUniqueID(*args)
|
|
145
|
+
return self._rnr
|
|
146
|
+
else:
|
|
147
|
+
with tecutil.lock():
|
|
148
|
+
return _tecutil.DataValueGetReadableNativeRefByUniqueID(*args)
|
|
149
|
+
|
|
150
|
+
@tecutil.lock()
|
|
151
|
+
def _raw_pointer(self, writable=False):
|
|
152
|
+
if _tecutil_connector.connected:
|
|
153
|
+
msg = 'raw pointer access only available in batch-mode'
|
|
154
|
+
raise TecplotLogicError(msg)
|
|
155
|
+
elif writable:
|
|
156
|
+
ref = self._native_reference(writable=True)
|
|
157
|
+
_tecutil.handle.tecUtilDataValueGetWritableRawPtrByRef.restype = \
|
|
158
|
+
POINTER(self.c_type)
|
|
159
|
+
wrp = _tecutil.DataValueGetWritableRawPtrByRef(ref)
|
|
160
|
+
if self._cache:
|
|
161
|
+
if not hasattr(self, '_wrp'):
|
|
162
|
+
self._wrp = wrp
|
|
163
|
+
return self._wrp
|
|
164
|
+
else:
|
|
165
|
+
return wrp
|
|
166
|
+
else:
|
|
167
|
+
_tecutil.handle.tecUtilDataValueGetReadableRawPtrByRef.restype = \
|
|
168
|
+
POINTER(self.c_type)
|
|
169
|
+
rrp = _tecutil.DataValueGetReadableRawPtrByRef(self)
|
|
170
|
+
if self._cache:
|
|
171
|
+
if not hasattr(self, '_rrp'):
|
|
172
|
+
self._rrp = rrp
|
|
173
|
+
return self._rrp
|
|
174
|
+
else:
|
|
175
|
+
return rrp
|
|
176
|
+
|
|
177
|
+
def __eq__(self, other):
|
|
178
|
+
self_addr = addressof(cast(self, POINTER(c_int64)).contents)
|
|
179
|
+
other_addr = addressof(cast(other, POINTER(c_int64)).contents)
|
|
180
|
+
return self_addr == other_addr
|
|
181
|
+
|
|
182
|
+
def __ne__(self, other):
|
|
183
|
+
return not (self == other)
|
|
184
|
+
|
|
185
|
+
def __len__(self):
|
|
186
|
+
"""The number of values in this array.
|
|
187
|
+
|
|
188
|
+
:rtype: `integer <int>`
|
|
189
|
+
|
|
190
|
+
Example showing size of ordered data::
|
|
191
|
+
|
|
192
|
+
>>> x = dataset.zone('Zone').values('X')
|
|
193
|
+
>>> print(x.shape)
|
|
194
|
+
(10, 10, 10)
|
|
195
|
+
>>> print(len(x))
|
|
196
|
+
1000
|
|
197
|
+
"""
|
|
198
|
+
if self._cache:
|
|
199
|
+
if not hasattr(self, '_len'):
|
|
200
|
+
self._len = _tecutil.DataValueGetCountByRef(self)
|
|
201
|
+
return self._len
|
|
202
|
+
else:
|
|
203
|
+
return _tecutil.DataValueGetCountByRef(self)
|
|
204
|
+
|
|
205
|
+
@property
|
|
206
|
+
def location(self):
|
|
207
|
+
"""`ValueLocation`: Data points location with respect to the elements.
|
|
208
|
+
|
|
209
|
+
Possible values are `ValueLocation.CellCentered` and
|
|
210
|
+
`ValueLocation.Nodal`. Example usage::
|
|
211
|
+
|
|
212
|
+
>>> print(dataset.zone(0).values('X').location)
|
|
213
|
+
ValueLocation.Nodal
|
|
214
|
+
"""
|
|
215
|
+
if self._cache:
|
|
216
|
+
if not hasattr(self, '_location'):
|
|
217
|
+
self._location = _tecutil.DataValueGetLocation(
|
|
218
|
+
self.zone.index + 1, self.variable.index + 1)
|
|
219
|
+
return self._location
|
|
220
|
+
else:
|
|
221
|
+
return _tecutil.DataValueGetLocation(self.zone.index + 1,
|
|
222
|
+
self.variable.index + 1)
|
|
223
|
+
|
|
224
|
+
@property
|
|
225
|
+
def shape(self):
|
|
226
|
+
"""`tuple` of `floats <float>`: ``(i, j, k)`` shape for this array.
|
|
227
|
+
|
|
228
|
+
This is defined by the parent zone and can be used to reshape arrays.
|
|
229
|
+
The following example assumes 32-bit floating point array and copies
|
|
230
|
+
the Tecplot-owned ``data`` into the `numpy`-owned ``array``::
|
|
231
|
+
|
|
232
|
+
>>> import numpy as np
|
|
233
|
+
>>> data = dataset.zone('Zone').values('X')
|
|
234
|
+
>>> array = np.empty(data.shape, dtype=np.float32)
|
|
235
|
+
>>> arr_ptr = array.ctypes.data_as(POINTER(data.c_type))
|
|
236
|
+
>>> memmove(arr_ptr, data.copy(), sizeof(data.c_type) * len(data))
|
|
237
|
+
|
|
238
|
+
The data array presented is normally one-dimensional. For ordered data,
|
|
239
|
+
you may wish to reshape the array indexing according to the
|
|
240
|
+
dimensionality given by the ``shape`` attribute:
|
|
241
|
+
|
|
242
|
+
.. code-block:: python
|
|
243
|
+
:emphasize-lines: 30
|
|
244
|
+
|
|
245
|
+
import numpy as np
|
|
246
|
+
import tecplot as tp
|
|
247
|
+
|
|
248
|
+
frame = tp.active_frame()
|
|
249
|
+
dataset = frame.create_dataset('Dataset', ['X'])
|
|
250
|
+
zone = dataset.add_ordered_zone('Zone', shape=(3,3,3))
|
|
251
|
+
|
|
252
|
+
'''
|
|
253
|
+
the following will print:
|
|
254
|
+
[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
|
|
255
|
+
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
|
|
256
|
+
'''
|
|
257
|
+
x = np.array(zone.values('X')[:])
|
|
258
|
+
print(x)
|
|
259
|
+
|
|
260
|
+
'''
|
|
261
|
+
the following will print:
|
|
262
|
+
[[[ 0. 0. 0.]
|
|
263
|
+
[ 0. 0. 0.]
|
|
264
|
+
[ 0. 0. 0.]]
|
|
265
|
+
|
|
266
|
+
[[ 0. 0. 0.]
|
|
267
|
+
[ 0. 0. 0.]
|
|
268
|
+
[ 0. 0. 0.]]
|
|
269
|
+
|
|
270
|
+
[[ 0. 0. 0.]
|
|
271
|
+
[ 0. 0. 0.]
|
|
272
|
+
[ 0. 0. 0.]]]
|
|
273
|
+
'''
|
|
274
|
+
x.shape = zone.values('X').shape
|
|
275
|
+
print(x)
|
|
276
|
+
|
|
277
|
+
"""
|
|
278
|
+
if self.zone.zone_type is ZoneType.Ordered:
|
|
279
|
+
array_shape = tuple(i for i in self.zone._shape if i > 1)
|
|
280
|
+
else:
|
|
281
|
+
array_shape = (self.zone.num_points,)
|
|
282
|
+
if self.location is ValueLocation.CellCentered:
|
|
283
|
+
array_shape = tuple(i - 1 for i in array_shape if i > 2)
|
|
284
|
+
if not array_shape:
|
|
285
|
+
array_shape = (1,)
|
|
286
|
+
return array_shape
|
|
287
|
+
|
|
288
|
+
@property
|
|
289
|
+
def c_type(self):
|
|
290
|
+
"""`ctypes` compatible data type of this array.
|
|
291
|
+
|
|
292
|
+
This is the `ctypes` equivalent of `Array.data_type` and will return
|
|
293
|
+
one of the following:
|
|
294
|
+
|
|
295
|
+
* `ctypes.c_float`
|
|
296
|
+
* `ctypes.c_double`
|
|
297
|
+
* `ctypes.c_int`
|
|
298
|
+
* `ctypes.c_int16`
|
|
299
|
+
* `ctypes.c_int8`
|
|
300
|
+
|
|
301
|
+
and can be used to create a `ctypes` array to store a copy of the
|
|
302
|
+
data:
|
|
303
|
+
|
|
304
|
+
.. code-block:: python
|
|
305
|
+
|
|
306
|
+
import tecplot as tp
|
|
307
|
+
frame = tp.active_frame()
|
|
308
|
+
dataset = frame.create_dataset('Dataset', ['x'])
|
|
309
|
+
dataset.add_ordered_zone('Zone', (3,3,3))
|
|
310
|
+
x = dataset.zone('Zone').values('x')
|
|
311
|
+
# allocate array using Python's ctypes
|
|
312
|
+
x_array = (x.c_type * len(x))()
|
|
313
|
+
# copy values from Dataset into ctypes array
|
|
314
|
+
x_array[:] = x[:]
|
|
315
|
+
"""
|
|
316
|
+
_ctypes = {
|
|
317
|
+
FieldDataType.Float: ctypes.c_float,
|
|
318
|
+
FieldDataType.Double: ctypes.c_double,
|
|
319
|
+
FieldDataType.Int32: ctypes.c_int32,
|
|
320
|
+
FieldDataType.Int16: ctypes.c_int16,
|
|
321
|
+
FieldDataType.Byte: ctypes.c_int8}
|
|
322
|
+
return _ctypes[self.data_type]
|
|
323
|
+
|
|
324
|
+
@property
|
|
325
|
+
def data_type(self):
|
|
326
|
+
"""`FieldDataType`: Indicating the underlying value type of this array.
|
|
327
|
+
|
|
328
|
+
Example usage::
|
|
329
|
+
|
|
330
|
+
>>> print(dataset.zone('Zone').values('X').data_type)
|
|
331
|
+
FieldDataType.Float
|
|
332
|
+
"""
|
|
333
|
+
return _tecutil.DataValueGetRefType(self)
|
|
334
|
+
|
|
335
|
+
@tecutil.lock()
|
|
336
|
+
def as_ctypes_array(self, offset=0, size=None, copy=True):
|
|
337
|
+
"""Present the underlying data array as a `ctypes.Array`.
|
|
338
|
+
|
|
339
|
+
If the **copy** parameter is `False`, this method will attempt to return
|
|
340
|
+
an array pointing to the actual data stored in the Tecplot Engine. This
|
|
341
|
+
will fail in connected mode or if the loader does not support
|
|
342
|
+
immediate loading of the entire array into memory. Care should be taken
|
|
343
|
+
to ensure the validity of the pointers to the data.
|
|
344
|
+
|
|
345
|
+
Parameters:
|
|
346
|
+
offset (`int`, optional): Zero-based offset into the array. This
|
|
347
|
+
will be the starting point of the resulting data. (default: 0)
|
|
348
|
+
size (`int`, optional): Number of elements in the resulting array.
|
|
349
|
+
The default (a value of `None`) is to go to the end of the
|
|
350
|
+
data.
|
|
351
|
+
copy (`bool`, optional): Copy the data out from the Tecplot Engine.
|
|
352
|
+
If `False`, an attempt is made to point to the underlying raw
|
|
353
|
+
data and an exception is thrown on error. (default: `True`)
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
`ctypes.Array`
|
|
357
|
+
|
|
358
|
+
Example usage::
|
|
359
|
+
|
|
360
|
+
>>> x = dataset.zone('Zone').values('X').as_ctypes_array()
|
|
361
|
+
"""
|
|
362
|
+
size = (len(self) - offset) if size is None else size
|
|
363
|
+
CArray = (self.c_type * size)
|
|
364
|
+
if copy:
|
|
365
|
+
arr = CArray()
|
|
366
|
+
_tecutil.DataValueArrayGetByRef(self, offset + 1, size, arr)
|
|
367
|
+
return arr
|
|
368
|
+
else:
|
|
369
|
+
ptr = self._raw_pointer(True)
|
|
370
|
+
if offset:
|
|
371
|
+
vptr = ctypes.cast(ctypes.pointer(ptr),
|
|
372
|
+
ctypes.POINTER(ctypes.c_void_p))
|
|
373
|
+
vptr.contents.value += ctypes.sizeof(ptr._type_) * offset
|
|
374
|
+
ptr_addr = ctypes.addressof(ptr.contents)
|
|
375
|
+
arr = CArray.from_address(ptr_addr)
|
|
376
|
+
return arr
|
|
377
|
+
|
|
378
|
+
def as_numpy_array(self, offset=0, size=None, copy=True):
|
|
379
|
+
"""Present the underlying data array as a `numpy.ndarray`.
|
|
380
|
+
|
|
381
|
+
If the **copy** parameter is `False`, this method will attempt to return
|
|
382
|
+
an array pointing to the actual data stored in the Tecplot Engine. This
|
|
383
|
+
will fail in connected mode or if the loader does not support
|
|
384
|
+
immediate loading of the entire array into memory. Care should be taken
|
|
385
|
+
to ensure the validity of the pointers to the data.
|
|
386
|
+
|
|
387
|
+
Parameters:
|
|
388
|
+
offset (`int`, optional): Zero-based offset into the array. This
|
|
389
|
+
will be the starting point of the resulting data. (default: 0)
|
|
390
|
+
size (`int`, optional): Number of elements in the resulting array.
|
|
391
|
+
The default (a value of `None`) is to go to the end of the
|
|
392
|
+
data.
|
|
393
|
+
copy (`bool`, optional): Copy the data out from the Tecplot Engine.
|
|
394
|
+
If `False`, an attempt is made to point to the underlying raw
|
|
395
|
+
data and an exception is thrown on error. (default: `True`)
|
|
396
|
+
|
|
397
|
+
Returns:
|
|
398
|
+
`numpy.ndarray`
|
|
399
|
+
|
|
400
|
+
Example usage::
|
|
401
|
+
|
|
402
|
+
>>> x = dataset.zone('Zone').values('X').as_numpy_array()
|
|
403
|
+
"""
|
|
404
|
+
import numpy as np
|
|
405
|
+
carr = self.as_ctypes_array(offset, size, copy)
|
|
406
|
+
return np.ctypeslib.as_array(carr)
|
|
407
|
+
|
|
408
|
+
@tecutil.lock()
|
|
409
|
+
def copy(self, offset=0, size=None):
|
|
410
|
+
"""Copy the whole or part of the array into a ctypes array.
|
|
411
|
+
|
|
412
|
+
Parameters:
|
|
413
|
+
offset (`int`, optional): Zero-based offset for starting
|
|
414
|
+
index to copy. (default: 0)
|
|
415
|
+
size (`int`, optional): Number of values to copy into the
|
|
416
|
+
resulting array. A value of `None` will copy to the end of the
|
|
417
|
+
array. (default: `None`)
|
|
418
|
+
|
|
419
|
+
Here we will copy out chunks of the data, do some operation and set the
|
|
420
|
+
values back into the dataset:
|
|
421
|
+
|
|
422
|
+
.. code-block:: python
|
|
423
|
+
|
|
424
|
+
import tecplot as tp
|
|
425
|
+
|
|
426
|
+
tp.new_layout()
|
|
427
|
+
frame = tp.active_frame()
|
|
428
|
+
dataset = frame.create_dataset('Dataset', ['x'])
|
|
429
|
+
dataset.add_ordered_zone('Zone', (2, 2, 2))
|
|
430
|
+
x = dataset.zone('Zone').values('x')
|
|
431
|
+
|
|
432
|
+
# loop over array copying out 4 values at a time
|
|
433
|
+
for i, offset in enumerate(range(0, len(x), 4)):
|
|
434
|
+
x_array = x.copy(offset, 4)
|
|
435
|
+
x_array[:] = [i] * 4
|
|
436
|
+
x[offset:offset + 4] = x_array
|
|
437
|
+
|
|
438
|
+
# will print: [0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0]
|
|
439
|
+
print(x[:])
|
|
440
|
+
"""
|
|
441
|
+
try:
|
|
442
|
+
return self.as_numpy_array(offset, size, copy=True)
|
|
443
|
+
except ImportError:
|
|
444
|
+
msg = textwrap.dedent('''\
|
|
445
|
+
Falling back to using basic Python for data operations.
|
|
446
|
+
If installed, PyTecplot will make use of Numpy where
|
|
447
|
+
appropriate for significant performance gains.
|
|
448
|
+
''')
|
|
449
|
+
log.warning(msg)
|
|
450
|
+
return self.as_ctypes_array(offset, size, copy=True)
|
|
451
|
+
|
|
452
|
+
def _slice_range(self, s):
|
|
453
|
+
start = s.start or 0
|
|
454
|
+
if start < 0:
|
|
455
|
+
start += len(self)
|
|
456
|
+
stop = s.stop or len(self)
|
|
457
|
+
if stop < 0:
|
|
458
|
+
stop += len(self)
|
|
459
|
+
step = s.step or 1
|
|
460
|
+
return range(start, stop, step)
|
|
461
|
+
|
|
462
|
+
def __getitem__(self, i):
|
|
463
|
+
if not isinstance(i, slice):
|
|
464
|
+
return _tecutil.DataValueGetByRef(self, i + 1)
|
|
465
|
+
else:
|
|
466
|
+
s = self._slice_range(i)
|
|
467
|
+
if s.step > 1:
|
|
468
|
+
# i is a non-contiguous slice
|
|
469
|
+
return [_tecutil.DataValueGetByRef(self, ii + 1) for ii in s]
|
|
470
|
+
else:
|
|
471
|
+
# i is a contiguous slice
|
|
472
|
+
return self.copy(s.start, s.stop - s.start)
|
|
473
|
+
|
|
474
|
+
@tecutil.lock()
|
|
475
|
+
def __setitem__(self, i, val):
|
|
476
|
+
"""
|
|
477
|
+
Developers note:
|
|
478
|
+
This method avoids using raw pointers which may not be available
|
|
479
|
+
for different reasons -- backing data does not support it, limited
|
|
480
|
+
memory resources or we are in connected mode for example.
|
|
481
|
+
"""
|
|
482
|
+
if not isinstance(i, slice):
|
|
483
|
+
# i is an index
|
|
484
|
+
ref = self._native_reference(True)
|
|
485
|
+
_tecutil.DataValueSetByRef(ref, i + 1, val)
|
|
486
|
+
session.data_altered(self.zone, self.variable, i)
|
|
487
|
+
elif isinstance(val, Array) and val == self:
|
|
488
|
+
# self assignment no-op
|
|
489
|
+
return
|
|
490
|
+
else:
|
|
491
|
+
if callable(getattr(val, 'ravel', None)):
|
|
492
|
+
val = val.ravel()
|
|
493
|
+
s = self._slice_range(i)
|
|
494
|
+
if len(s) != len(val):
|
|
495
|
+
msg = 'Array length mismatch {} != {}'
|
|
496
|
+
raise TecplotIndexError(msg.format(len(s), len(val)))
|
|
497
|
+
if s.step > 1:
|
|
498
|
+
# i is a non-contiguous slice
|
|
499
|
+
# the following works, but is slow!
|
|
500
|
+
for a, b in enumerate(s):
|
|
501
|
+
self[b] = val[a]
|
|
502
|
+
else:
|
|
503
|
+
# i is a contiguous slice
|
|
504
|
+
offset = s.start
|
|
505
|
+
size = s.stop - s.start
|
|
506
|
+
|
|
507
|
+
if isinstance(val, Array):
|
|
508
|
+
if (
|
|
509
|
+
offset == 0 and
|
|
510
|
+
size in (None, len(self)) and
|
|
511
|
+
val.zone.dataset == self.zone.dataset
|
|
512
|
+
):
|
|
513
|
+
# copy whole array
|
|
514
|
+
if val.zone == self.zone:
|
|
515
|
+
eqn = 'V{0} = V{1}'.format(self.variable.index + 1,
|
|
516
|
+
val.variable.index + 1)
|
|
517
|
+
operate.execute_equation(eqn, self.zone)
|
|
518
|
+
else:
|
|
519
|
+
src_zone_idx = self.zone.index
|
|
520
|
+
tgt_zone_idx = val.zone.index
|
|
521
|
+
var_idx = val.variable.index
|
|
522
|
+
if not _tecutil.DataValueCopy(src_zone_idx + 1,
|
|
523
|
+
tgt_zone_idx + 1,
|
|
524
|
+
var_idx + 1):
|
|
525
|
+
raise TecplotSystemError()
|
|
526
|
+
return
|
|
527
|
+
else:
|
|
528
|
+
# either sub array or different datasets
|
|
529
|
+
val = val.as_ctypes_array(copy=True)
|
|
530
|
+
|
|
531
|
+
ctype = self.c_type
|
|
532
|
+
if isinstance(val, ctypes.Array) and val._type_ == ctype:
|
|
533
|
+
arr = val
|
|
534
|
+
else:
|
|
535
|
+
# coerce val to a ctypes array, using numpy if available
|
|
536
|
+
try:
|
|
537
|
+
import numpy as np
|
|
538
|
+
nparr = np.asarray(val, dtype=ctype)
|
|
539
|
+
ptarr = nparr.ctypes.data_as(POINTER(ctype))
|
|
540
|
+
ptaddr = addressof(ptarr.contents)
|
|
541
|
+
arr = (ctype * size).from_address(ptaddr)
|
|
542
|
+
except ImportError:
|
|
543
|
+
msg = textwrap.dedent('''\
|
|
544
|
+
Falling back to using basic Python for data
|
|
545
|
+
operations. If installed, PyTecplot will make use
|
|
546
|
+
of Numpy where appropriate for significant
|
|
547
|
+
performance gains.
|
|
548
|
+
''')
|
|
549
|
+
log.warning(msg)
|
|
550
|
+
arr = (ctype * size)(*val)
|
|
551
|
+
|
|
552
|
+
ref = self._native_reference(True)
|
|
553
|
+
_tecutil.DataValueArraySetByRef(ref, offset + 1, size, arr)
|
|
554
|
+
session.data_altered(self.zone, self.variable)
|
|
555
|
+
|
|
556
|
+
def __iter__(self):
|
|
557
|
+
self.current_index = -1
|
|
558
|
+
self.current_length = len(self)
|
|
559
|
+
return self
|
|
560
|
+
|
|
561
|
+
def __next__(self):
|
|
562
|
+
self.current_index += 1
|
|
563
|
+
if self.current_index < self.current_length:
|
|
564
|
+
return self.__getitem__(self.current_index)
|
|
565
|
+
else:
|
|
566
|
+
del self.current_index
|
|
567
|
+
del self.current_length
|
|
568
|
+
raise StopIteration
|
|
569
|
+
|
|
570
|
+
def next(self): # if sys.version_info < (3,)
|
|
571
|
+
return self.__next__()
|
|
572
|
+
|
|
573
|
+
def minmax(self):
|
|
574
|
+
"""Limits of the values stored in this array.
|
|
575
|
+
|
|
576
|
+
:rtype: `tuple` of `floats <float>`
|
|
577
|
+
|
|
578
|
+
This always returns `floats <float>` regardless of the underlying data
|
|
579
|
+
type::
|
|
580
|
+
|
|
581
|
+
>>> print(dataset.zone('Zone').values('x').minmax())
|
|
582
|
+
(0, 10)
|
|
583
|
+
"""
|
|
584
|
+
return _tecutil.DataValueGetMinMaxByRef(self)
|
|
585
|
+
|
|
586
|
+
def min(self):
|
|
587
|
+
"""Lower bound of the values stored in this array.
|
|
588
|
+
|
|
589
|
+
:rtype: `float`
|
|
590
|
+
|
|
591
|
+
This always returns a `float` regardless of the underlying data type::
|
|
592
|
+
|
|
593
|
+
>>> print(dataset.zone('Zone').values('x').min())
|
|
594
|
+
0
|
|
595
|
+
"""
|
|
596
|
+
return self.minmax()[0]
|
|
597
|
+
|
|
598
|
+
def max(self):
|
|
599
|
+
"""Upper bound of the values stored in this array.
|
|
600
|
+
|
|
601
|
+
:rtype: `float`
|
|
602
|
+
|
|
603
|
+
This always returns a `float` regardless of the underlying data type::
|
|
604
|
+
|
|
605
|
+
>>> print(dataset.zone('Zone').values('x').max())
|
|
606
|
+
10
|
|
607
|
+
"""
|
|
608
|
+
return self.minmax()[1]
|
|
609
|
+
|
|
610
|
+
@property
|
|
611
|
+
def shared_zones(self):
|
|
612
|
+
"""`list` of `Zones <data_access>`: All `Zones <data_access>` sharing this array.
|
|
613
|
+
|
|
614
|
+
Example usage::
|
|
615
|
+
|
|
616
|
+
>>> dataset.zone('My Zone').copy(share_variables=True)
|
|
617
|
+
>>> for z in dataset.zone('My Zone').values(0).shared_zones:
|
|
618
|
+
... print(z.index)
|
|
619
|
+
0
|
|
620
|
+
1
|
|
621
|
+
"""
|
|
622
|
+
indices = _tecutil.DataValueGetShareZoneSet(self.zone.index + 1,
|
|
623
|
+
self.variable.index + 1)
|
|
624
|
+
ret = [self.zone.dataset.zone(i) for i in indices]
|
|
625
|
+
indices.dealloc()
|
|
626
|
+
return ret
|
|
627
|
+
|
|
628
|
+
@property
|
|
629
|
+
def passive(self):
|
|
630
|
+
"""`bool`: An unallocated zone-variable combination.
|
|
631
|
+
|
|
632
|
+
Passive variables are placeholders where no data is defined for a zone
|
|
633
|
+
variable combination. Passive variables will always return zero when
|
|
634
|
+
queried:
|
|
635
|
+
|
|
636
|
+
.. code-block:: python
|
|
637
|
+
|
|
638
|
+
import tecplot as tp
|
|
639
|
+
|
|
640
|
+
ds = tp.active_page().add_frame().create_dataset('D', ['x','y'])
|
|
641
|
+
z = ds.add_ordered_zone('Z1', (3,))
|
|
642
|
+
assert not z.values(0).passive
|
|
643
|
+
"""
|
|
644
|
+
return _tecutil.DataValueIsPassive(self.zone.index + 1,
|
|
645
|
+
self.variable.index + 1)
|
tecplot/data/create.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|