flekspy 0.2.2__tar.gz → 0.2.4__tar.gz
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.
- {flekspy-0.2.2 → flekspy-0.2.4}/PKG-INFO +2 -2
- {flekspy-0.2.2 → flekspy-0.2.4}/pyproject.toml +1 -1
- {flekspy-0.2.2 → flekspy-0.2.4}/src/flekspy/tp/test_particles.py +466 -441
- {flekspy-0.2.2 → flekspy-0.2.4}/src/flekspy/util/data_container.py +29 -47
- {flekspy-0.2.2 → flekspy-0.2.4}/src/flekspy/util/utilities.py +20 -7
- {flekspy-0.2.2 → flekspy-0.2.4}/src/flekspy/yt/yt.py +1 -2
- {flekspy-0.2.2 → flekspy-0.2.4}/LICENSE.md +0 -0
- {flekspy-0.2.2 → flekspy-0.2.4}/README.md +0 -0
- {flekspy-0.2.2 → flekspy-0.2.4}/src/flekspy/__init__.py +0 -0
- {flekspy-0.2.2 → flekspy-0.2.4}/src/flekspy/flekspy.py +0 -0
- {flekspy-0.2.2 → flekspy-0.2.4}/src/flekspy/idl/__init__.py +0 -0
- {flekspy-0.2.2 → flekspy-0.2.4}/src/flekspy/idl/idl.py +0 -0
- {flekspy-0.2.2 → flekspy-0.2.4}/src/flekspy/plot/__init__.py +0 -0
- {flekspy-0.2.2 → flekspy-0.2.4}/src/flekspy/plot/streamplot.py +0 -0
- {flekspy-0.2.2 → flekspy-0.2.4}/src/flekspy/tp/__init__.py +0 -0
- {flekspy-0.2.2 → flekspy-0.2.4}/src/flekspy/util/__init__.py +0 -0
- {flekspy-0.2.2 → flekspy-0.2.4}/src/flekspy/yt/__init__.py +0 -0
|
@@ -1,441 +1,466 @@
|
|
|
1
|
-
from typing import List, Tuple, Dict, Union, Callable
|
|
2
|
-
|
|
3
|
-
import matplotlib.pyplot as plt
|
|
4
|
-
import os
|
|
5
|
-
import numpy as np
|
|
6
|
-
import glob
|
|
7
|
-
import struct
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class FLEKSTP(object):
|
|
11
|
-
r"""
|
|
12
|
-
A class that is used to read and plot test particles. Each particle ID consists of
|
|
13
|
-
a CPU index, a particle index on each CPU, and a location index.
|
|
14
|
-
By default, 7 real numbers saved for each step: time + position + velocity.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
>>> tp
|
|
24
|
-
>>>
|
|
25
|
-
>>> tp.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
self.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
self.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
ids
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
if
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
ax.
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
)
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
1
|
+
from typing import List, Tuple, Dict, Union, Callable
|
|
2
|
+
|
|
3
|
+
import matplotlib.pyplot as plt
|
|
4
|
+
import os
|
|
5
|
+
import numpy as np
|
|
6
|
+
import glob
|
|
7
|
+
import struct
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class FLEKSTP(object):
|
|
11
|
+
r"""
|
|
12
|
+
A class that is used to read and plot test particles. Each particle ID consists of
|
|
13
|
+
a CPU index, a particle index on each CPU, and a location index.
|
|
14
|
+
By default, 7 real numbers saved for each step: time + position + velocity.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
dirs (str): the path to the test particle dataset.
|
|
18
|
+
|
|
19
|
+
Examples:
|
|
20
|
+
>>> tp = FLEKSTP("res/run1/PC/test_particles", iSpecies=1)
|
|
21
|
+
>>> pIDs = list(tp.IDs())
|
|
22
|
+
>>> tp.plot_trajectory(pIDs[3])
|
|
23
|
+
>>> tp.save_trajectory_to_csv(pIDs[5])
|
|
24
|
+
>>> ids, pData = tp.read_particles_at_time(6500.8, doSave=True)
|
|
25
|
+
>>> f = tp.plot_loc(pData)
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
it_ = 0
|
|
29
|
+
ix_ = 1
|
|
30
|
+
iy_ = 2
|
|
31
|
+
iz_ = 3
|
|
32
|
+
iu_ = 4
|
|
33
|
+
iv_ = 5
|
|
34
|
+
iw_ = 6
|
|
35
|
+
iBx_ = 7
|
|
36
|
+
iBy_ = 8
|
|
37
|
+
iBz_ = 9
|
|
38
|
+
iEx_ = 10
|
|
39
|
+
iEy_ = 11
|
|
40
|
+
iEz_ = 12
|
|
41
|
+
|
|
42
|
+
def __init__(
|
|
43
|
+
self,
|
|
44
|
+
dirs: Union[str, List[str]],
|
|
45
|
+
iDomain: int = 0,
|
|
46
|
+
iSpecies: int = 0,
|
|
47
|
+
iListStart: int = 0,
|
|
48
|
+
iListEnd: int = -1,
|
|
49
|
+
readAllFiles: bool = False,
|
|
50
|
+
):
|
|
51
|
+
if type(dirs) == str:
|
|
52
|
+
dirs = [dirs]
|
|
53
|
+
|
|
54
|
+
header = dirs[0] + "/Header"
|
|
55
|
+
if os.path.exists(header):
|
|
56
|
+
with open(header, "r") as f:
|
|
57
|
+
self.nReal = int(f.readline())
|
|
58
|
+
else:
|
|
59
|
+
raise FileNotFoundError(f"Header file not found in {dirs[0]}")
|
|
60
|
+
|
|
61
|
+
self.iSpecies = iSpecies
|
|
62
|
+
self.plistfiles = list()
|
|
63
|
+
self.pfiles = list()
|
|
64
|
+
|
|
65
|
+
for outputDir in dirs:
|
|
66
|
+
self.plistfiles = self.plistfiles + glob.glob(
|
|
67
|
+
f"{outputDir}/FLEKS{iDomain}_particle_list_species_{iSpecies}_*"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
self.pfiles = self.pfiles + glob.glob(
|
|
71
|
+
f"{outputDir}/FLEKS{iDomain}_particle_species_{iSpecies}_*"
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
self.plistfiles.sort()
|
|
75
|
+
self.pfiles.sort()
|
|
76
|
+
|
|
77
|
+
self.indextotime = []
|
|
78
|
+
if readAllFiles:
|
|
79
|
+
for filename in self.pfiles:
|
|
80
|
+
record = self._read_the_first_record(filename)
|
|
81
|
+
if record == None:
|
|
82
|
+
continue
|
|
83
|
+
self.indextotime.append(record[FLEKSTP.it_])
|
|
84
|
+
|
|
85
|
+
if iListEnd == -1:
|
|
86
|
+
iListEnd = len(self.plistfiles)
|
|
87
|
+
self.plistfiles = self.plistfiles[iListStart:iListEnd]
|
|
88
|
+
self.pfiles = self.pfiles[iListStart:iListEnd]
|
|
89
|
+
|
|
90
|
+
self.plists: List[Dict[Tuple[int, int], int]] = []
|
|
91
|
+
for fileName in self.plistfiles:
|
|
92
|
+
self.plists.append(self.read_particle_list(fileName))
|
|
93
|
+
|
|
94
|
+
self.IDs = set()
|
|
95
|
+
for plist in self.plists:
|
|
96
|
+
self.IDs.update(plist.keys())
|
|
97
|
+
|
|
98
|
+
self.filetime = []
|
|
99
|
+
for filename in self.pfiles:
|
|
100
|
+
record = self._read_the_first_record(filename)
|
|
101
|
+
if record == None:
|
|
102
|
+
continue
|
|
103
|
+
self.filetime.append(record[FLEKSTP.it_])
|
|
104
|
+
|
|
105
|
+
print(f"Particles of species {self.iSpecies} are read from {dirs}")
|
|
106
|
+
print(f"Number of particles: {len(self.IDs)}")
|
|
107
|
+
|
|
108
|
+
def getIDs(self):
|
|
109
|
+
return list(sorted(self.IDs))
|
|
110
|
+
|
|
111
|
+
def get_index_to_time(self) -> List:
|
|
112
|
+
"""
|
|
113
|
+
Getter method for accessing indextotime.
|
|
114
|
+
"""
|
|
115
|
+
if len(self.indextotime) == 0:
|
|
116
|
+
print("Index to time mapping was not initialized")
|
|
117
|
+
return self.indextotime
|
|
118
|
+
|
|
119
|
+
def read_particle_list(self, fileName: str) -> Dict[Tuple[int, int], int]:
|
|
120
|
+
"""
|
|
121
|
+
Read and return a list of the particle IDs.
|
|
122
|
+
"""
|
|
123
|
+
# 2 integers + 1 unsigned long long
|
|
124
|
+
listUnitSize = 2 * 4 + 8
|
|
125
|
+
nByte = os.path.getsize(fileName)
|
|
126
|
+
nPart = int(nByte / listUnitSize)
|
|
127
|
+
plist = {}
|
|
128
|
+
with open(fileName, "rb") as f:
|
|
129
|
+
for _ in range(nPart):
|
|
130
|
+
binaryData = f.read(listUnitSize)
|
|
131
|
+
(cpu, id, loc) = struct.unpack("iiQ", binaryData)
|
|
132
|
+
plist.update({(cpu, id): loc})
|
|
133
|
+
return plist
|
|
134
|
+
|
|
135
|
+
def _read_the_first_record(self, fileName: str) -> Union[List[float], None]:
|
|
136
|
+
"""
|
|
137
|
+
Get the first record stored in one file.
|
|
138
|
+
"""
|
|
139
|
+
dataList = list()
|
|
140
|
+
with open(fileName, "rb") as f:
|
|
141
|
+
while True:
|
|
142
|
+
binaryData = f.read(4 * 4)
|
|
143
|
+
|
|
144
|
+
if not binaryData:
|
|
145
|
+
break # EOF
|
|
146
|
+
|
|
147
|
+
(cpu, idtmp, nRecord, weight) = struct.unpack("iiif", binaryData)
|
|
148
|
+
if nRecord > 0:
|
|
149
|
+
binaryData = f.read(4 * self.nReal)
|
|
150
|
+
dataList = dataList + list(
|
|
151
|
+
struct.unpack("f" * self.nReal, binaryData)
|
|
152
|
+
)
|
|
153
|
+
return dataList
|
|
154
|
+
|
|
155
|
+
def read_particles_at_time(
|
|
156
|
+
self, time: float, doSave: bool = False
|
|
157
|
+
) -> Tuple[np.ndarray, np.ndarray]:
|
|
158
|
+
r"""
|
|
159
|
+
Get the information of all the particles at a given time, and save to a csv file
|
|
160
|
+
with the name "particles_t***.csv" in the current directory if doSave is True.
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
ids: a numpy array of tuples contains the particle IDs.
|
|
164
|
+
pData: a numpy real array with the particle weight, location and velocity.
|
|
165
|
+
|
|
166
|
+
Examples:
|
|
167
|
+
>>> ids, pData = pt.read_particles_at_time(3700, doSave=True)
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
nFile = len(self.pfiles)
|
|
171
|
+
if time < self.filetime[0] or time > self.filetime[-1]:
|
|
172
|
+
raise Exception(f"There are no particles at time {time}.")
|
|
173
|
+
iFile = 0
|
|
174
|
+
while iFile < nFile - 1:
|
|
175
|
+
if time < self.filetime[iFile + 1]:
|
|
176
|
+
break
|
|
177
|
+
iFile += 1
|
|
178
|
+
|
|
179
|
+
fileName = self.pfiles[iFile]
|
|
180
|
+
|
|
181
|
+
dataList: list[float] = []
|
|
182
|
+
idList: list[tuple] = []
|
|
183
|
+
with open(fileName, "rb") as f:
|
|
184
|
+
while True:
|
|
185
|
+
binaryData = f.read(4 * 4)
|
|
186
|
+
if not binaryData:
|
|
187
|
+
break # EOF
|
|
188
|
+
|
|
189
|
+
(cpu, idtmp, nRecord, weight) = struct.unpack("iiif", binaryData)
|
|
190
|
+
binaryData = f.read(4 * self.nReal * nRecord)
|
|
191
|
+
allRecords = list(struct.unpack("f" * nRecord * self.nReal, binaryData))
|
|
192
|
+
for i in range(nRecord):
|
|
193
|
+
if (
|
|
194
|
+
allRecords[self.nReal * i + FLEKSTP.it_] >= time
|
|
195
|
+
or i == nRecord - 1
|
|
196
|
+
):
|
|
197
|
+
dataList.append(
|
|
198
|
+
allRecords[self.nReal * i : self.nReal * (i + 1)]
|
|
199
|
+
)
|
|
200
|
+
idList.append((cpu, idtmp))
|
|
201
|
+
break
|
|
202
|
+
|
|
203
|
+
npData = np.array(dataList)
|
|
204
|
+
idData = np.array(idList, dtype="i,i")
|
|
205
|
+
if doSave:
|
|
206
|
+
fileName = f"particles_t{time}.csv"
|
|
207
|
+
header = "cpu,iid,time,x,y,z,ux,uy,uz"
|
|
208
|
+
if self.nReal == 10:
|
|
209
|
+
header += ",bx,by,bz"
|
|
210
|
+
elif self.nReal == 13:
|
|
211
|
+
header += ",bx,by,bz,ex,ey,ez"
|
|
212
|
+
|
|
213
|
+
with open(fileName, "w") as f:
|
|
214
|
+
f.write(header + "\n")
|
|
215
|
+
for id_row, data_row in zip(idData, npData):
|
|
216
|
+
f.write(
|
|
217
|
+
f"{id_row[0]},{id_row[1]},{','.join(str(x) for x in data_row)}\n"
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
return idData, npData
|
|
221
|
+
|
|
222
|
+
def save_trajectory_to_csv(
|
|
223
|
+
self,
|
|
224
|
+
pID: Tuple[int, int],
|
|
225
|
+
fileName: str = None,
|
|
226
|
+
shiftTime: bool = False,
|
|
227
|
+
scaleTime: bool = False,
|
|
228
|
+
) -> None:
|
|
229
|
+
r"""
|
|
230
|
+
Save the trajectory of a particle to a csv file.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
pID: particle ID.
|
|
234
|
+
shiftTime (bool): If set to True, set the initial time to be 0.
|
|
235
|
+
scaleTime (bool): If set to True, scale the time into [0,1] range, only scale time if shiftTime = True.
|
|
236
|
+
|
|
237
|
+
Example:
|
|
238
|
+
>>> tp.save_trajectory_to_csv((3,15))
|
|
239
|
+
"""
|
|
240
|
+
pData = self.read_particle_trajectory(pID)
|
|
241
|
+
if fileName == None:
|
|
242
|
+
fileName = "trajectory_" + str(pID[0]) + "_" + str(pID[1]) + ".csv"
|
|
243
|
+
header = "time [s], X [R], Y [R], Z [R], U_x [km/s], U_y [km/s], U_z [km/s]"
|
|
244
|
+
if self.nReal == 10:
|
|
245
|
+
header += ", B_x [nT], B_y [nT], B_z [nT]"
|
|
246
|
+
if self.nReal == 13:
|
|
247
|
+
header += (
|
|
248
|
+
", B_x [nT], B_y [nT], B_z [nT], E_x [uV/m], E_y [uV/m], E_z [uV/m]"
|
|
249
|
+
)
|
|
250
|
+
if shiftTime:
|
|
251
|
+
pData[:, 0] -= pData[0, 0]
|
|
252
|
+
if scaleTime:
|
|
253
|
+
pData[:, 0] /= pData[-1, 0]
|
|
254
|
+
np.savetxt(fileName, pData, delimiter=",", header=header, comments="")
|
|
255
|
+
|
|
256
|
+
def read_particle_trajectory(self, pID: Tuple[int, int]):
|
|
257
|
+
r"""
|
|
258
|
+
Read and return the trajectory of a particle.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
pID: particle ID
|
|
262
|
+
|
|
263
|
+
Examples:
|
|
264
|
+
>>> trajectory = tp.read_particle_trajectory((66,888))
|
|
265
|
+
"""
|
|
266
|
+
dataList = list()
|
|
267
|
+
for fileName, plist in zip(self.pfiles, self.plists):
|
|
268
|
+
if pID in plist:
|
|
269
|
+
ploc = plist[pID]
|
|
270
|
+
with open(fileName, "rb") as f:
|
|
271
|
+
f.seek(ploc)
|
|
272
|
+
binaryData = f.read(4 * 4)
|
|
273
|
+
(cpu, idtmp, nRecord, weight) = struct.unpack("iiif", binaryData)
|
|
274
|
+
binaryData = f.read(4 * self.nReal * nRecord)
|
|
275
|
+
dataList = dataList + list(
|
|
276
|
+
struct.unpack("f" * nRecord * self.nReal, binaryData)
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
nRecord = int(len(dataList) / self.nReal)
|
|
280
|
+
return np.array(dataList).reshape(nRecord, self.nReal)
|
|
281
|
+
|
|
282
|
+
def read_initial_location(self, pID):
|
|
283
|
+
r"""
|
|
284
|
+
Read and return the initial location of a test particle
|
|
285
|
+
"""
|
|
286
|
+
|
|
287
|
+
for fileName, plist in zip(self.pfiles, self.plists):
|
|
288
|
+
if pID in plist:
|
|
289
|
+
ploc = plist[pID]
|
|
290
|
+
with open(fileName, "rb") as f:
|
|
291
|
+
f.seek(ploc)
|
|
292
|
+
binaryData = f.read(4 * 4)
|
|
293
|
+
(cpu, idtmp, nRecord, weight) = struct.unpack("iiif", binaryData)
|
|
294
|
+
nRead = 1
|
|
295
|
+
binaryData = f.read(4 * self.nReal * nRead)
|
|
296
|
+
dataList = list(struct.unpack("f" * nRead * self.nReal, binaryData))
|
|
297
|
+
return dataList
|
|
298
|
+
|
|
299
|
+
def select_particles(self, fSelect: Callable = None) -> List[Tuple[int, int]]:
|
|
300
|
+
r"""
|
|
301
|
+
Select and return the particles whose initial condition satisfy the requirement
|
|
302
|
+
set by the user defined function fSelect. The first argument of fSelect is the
|
|
303
|
+
particle ID, and the second argument is the initial record (time, location,
|
|
304
|
+
velocity and weight of a particle) of a particle.
|
|
305
|
+
|
|
306
|
+
Examples:
|
|
307
|
+
>>> def fselect(tp, pid):
|
|
308
|
+
>>> pdata = tp.read_initial_loc_with_ID(pid)
|
|
309
|
+
>>> intime = pdata[FLEKSTP.it_] < 3601
|
|
310
|
+
>>> inregion = pdata[FLEKSTP.ix_] > 20
|
|
311
|
+
>>> return intime and inregion
|
|
312
|
+
>>>
|
|
313
|
+
>>> pselected = tp.select_particles(fselect)
|
|
314
|
+
>>> tp.plot_trajectory(list(pselected.keys())[1])
|
|
315
|
+
"""
|
|
316
|
+
|
|
317
|
+
if fSelect == None:
|
|
318
|
+
|
|
319
|
+
def fSelect(tp, pid):
|
|
320
|
+
return True
|
|
321
|
+
|
|
322
|
+
pselected = list(filter(lambda pid: fSelect(self, pid), self.IDs))
|
|
323
|
+
|
|
324
|
+
return pselected
|
|
325
|
+
|
|
326
|
+
def get_data(self, data, name: str):
|
|
327
|
+
match name:
|
|
328
|
+
case "t":
|
|
329
|
+
x = data[:, FLEKSTP.it_]
|
|
330
|
+
case "x":
|
|
331
|
+
x = data[:, FLEKSTP.ix_]
|
|
332
|
+
case "y":
|
|
333
|
+
x = data[:, FLEKSTP.iy_]
|
|
334
|
+
case "z":
|
|
335
|
+
x = data[:, FLEKSTP.iz_]
|
|
336
|
+
case "u" | "vx" | "ux":
|
|
337
|
+
x = data[:, FLEKSTP.iu_]
|
|
338
|
+
case "v" | "vy" | "uy":
|
|
339
|
+
x = data[:, FLEKSTP.iv_]
|
|
340
|
+
case "w" | "vz" | "uz":
|
|
341
|
+
x = data[:, FLEKSTP.iw_]
|
|
342
|
+
case _:
|
|
343
|
+
raise Exception(f"Unknown plot variable {name}")
|
|
344
|
+
|
|
345
|
+
return x
|
|
346
|
+
|
|
347
|
+
def plot_trajectory(
|
|
348
|
+
self,
|
|
349
|
+
pID: Tuple[int, int],
|
|
350
|
+
*,
|
|
351
|
+
type="all",
|
|
352
|
+
xaxis="t",
|
|
353
|
+
yaxis="x",
|
|
354
|
+
ax=None,
|
|
355
|
+
**kwargs,
|
|
356
|
+
):
|
|
357
|
+
r"""
|
|
358
|
+
Plots the trajectory and velocities of the particle pID.
|
|
359
|
+
|
|
360
|
+
Example:
|
|
361
|
+
>>> tp.plot_trajectory((3,15))
|
|
362
|
+
"""
|
|
363
|
+
|
|
364
|
+
def plot_data(dd, label, irow, icol):
|
|
365
|
+
ax[irow, icol].plot(t, dd, label=label)
|
|
366
|
+
ax[irow, icol].scatter(
|
|
367
|
+
t, dd, c=plt.cm.winter(tNorm), edgecolor="none", marker="o", s=10
|
|
368
|
+
)
|
|
369
|
+
ax[irow, icol].set_xlabel("time")
|
|
370
|
+
ax[irow, icol].set_ylabel(label)
|
|
371
|
+
|
|
372
|
+
def plot_vector(idx, labels, irow):
|
|
373
|
+
for i, (id, label) in enumerate(zip(idx, labels)):
|
|
374
|
+
plot_data(data[:, id], label, irow, i, **kwargs)
|
|
375
|
+
|
|
376
|
+
data = self.read_particle_trajectory(pID)
|
|
377
|
+
t = data[:, FLEKSTP.it_]
|
|
378
|
+
tNorm = (t - t[0]) / (t[-1] - t[0])
|
|
379
|
+
|
|
380
|
+
if type == "single":
|
|
381
|
+
x = self.get_data(data, xaxis)
|
|
382
|
+
y = self.get_data(data, yaxis)
|
|
383
|
+
|
|
384
|
+
if ax == None:
|
|
385
|
+
f, ax = plt.subplots(1, 1, figsize=(10, 6), constrained_layout=True)
|
|
386
|
+
|
|
387
|
+
ax.plot(x, y, **kwargs)
|
|
388
|
+
elif type == "all":
|
|
389
|
+
ncol = 3
|
|
390
|
+
nrow = 3 # Default for X, V
|
|
391
|
+
if self.nReal == 10: # additional B field
|
|
392
|
+
nrow = 4
|
|
393
|
+
elif self.nReal == 13: # additional B and E field
|
|
394
|
+
nrow = 5
|
|
395
|
+
|
|
396
|
+
f, ax = plt.subplots(nrow, ncol, figsize=(12, 6), constrained_layout=True)
|
|
397
|
+
|
|
398
|
+
# Plot trajectories
|
|
399
|
+
for i, a in enumerate(ax[0, :]):
|
|
400
|
+
x_id = FLEKSTP.ix_ if i < 2 else FLEKSTP.iy_
|
|
401
|
+
y_id = FLEKSTP.iy_ if i == 0 else FLEKSTP.iz_
|
|
402
|
+
a.plot(data[:, x_id], data[:, y_id], "k")
|
|
403
|
+
a.scatter(
|
|
404
|
+
data[:, x_id],
|
|
405
|
+
data[:, y_id],
|
|
406
|
+
c=plt.cm.winter(tNorm),
|
|
407
|
+
edgecolor="none",
|
|
408
|
+
marker="o",
|
|
409
|
+
s=10,
|
|
410
|
+
)
|
|
411
|
+
a.set_xlabel("x" if i < 2 else "y")
|
|
412
|
+
a.set_ylabel("y" if i == 0 else "z")
|
|
413
|
+
|
|
414
|
+
plot_vector([FLEKSTP.ix_, FLEKSTP.iy_, FLEKSTP.iz_], ["x", "y", "z"], 1)
|
|
415
|
+
plot_vector([FLEKSTP.iu_, FLEKSTP.iv_, FLEKSTP.iw_], ["Vx", "Vy", "Vz"], 2)
|
|
416
|
+
|
|
417
|
+
if self.nReal > FLEKSTP.iBx_:
|
|
418
|
+
plot_vector(
|
|
419
|
+
[FLEKSTP.iBx_, FLEKSTP.iBy_, FLEKSTP.iBz_], ["Bx", "By", "Bz"], 3
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
if self.nReal > FLEKSTP.iEx_:
|
|
423
|
+
plot_vector(
|
|
424
|
+
[FLEKSTP.iEx_, FLEKSTP.iEy_, FLEKSTP.iEz_], ["Ex", "Ey", "Ez"], 4
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
return ax
|
|
428
|
+
|
|
429
|
+
def plot_loc(self, pData: np.ndarray):
|
|
430
|
+
r"""
|
|
431
|
+
Plot the location of particles pData.
|
|
432
|
+
|
|
433
|
+
Examples:
|
|
434
|
+
>>> ids, pData = tp.read_particles_at_time(3700, doSave=True)
|
|
435
|
+
>>> f = tp.plot_loc(pData)
|
|
436
|
+
"""
|
|
437
|
+
|
|
438
|
+
px = pData[:, FLEKSTP.ix_]
|
|
439
|
+
py = pData[:, FLEKSTP.iy_]
|
|
440
|
+
pz = pData[:, FLEKSTP.iz_]
|
|
441
|
+
|
|
442
|
+
# create subplot mosaic with different keyword arguments
|
|
443
|
+
skeys = ["A", "B", "C", "D"]
|
|
444
|
+
f, ax = plt.subplot_mosaic(
|
|
445
|
+
"AB;CD",
|
|
446
|
+
per_subplot_kw={("D"): {"projection": "3d"}},
|
|
447
|
+
gridspec_kw={"width_ratios": [1, 1], "wspace": 0.1, "hspace": 0.1},
|
|
448
|
+
figsize=(10, 10),
|
|
449
|
+
constrained_layout=True,
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
# Create 2D scatter plots
|
|
453
|
+
for i, (x, y, labels) in enumerate(
|
|
454
|
+
zip([px, px, py], [py, pz, pz], [("x", "y"), ("x", "z"), ("y", "z")])
|
|
455
|
+
):
|
|
456
|
+
ax[skeys[i]].scatter(x, y, s=1)
|
|
457
|
+
ax[skeys[i]].set_xlabel(labels[0])
|
|
458
|
+
ax[skeys[i]].set_ylabel(labels[1])
|
|
459
|
+
|
|
460
|
+
# Create 3D scatter plot
|
|
461
|
+
ax[skeys[3]].scatter(px, py, pz, s=1)
|
|
462
|
+
ax[skeys[3]].set_xlabel("x")
|
|
463
|
+
ax[skeys[3]].set_ylabel("y")
|
|
464
|
+
ax[skeys[3]].set_zlabel("z")
|
|
465
|
+
|
|
466
|
+
return ax
|
|
@@ -79,12 +79,12 @@ class DataContainer(object):
|
|
|
79
79
|
if verbose > 0:
|
|
80
80
|
f.text(0.01, 0.01, s)
|
|
81
81
|
|
|
82
|
-
def analyze_variable_string(self, var):
|
|
82
|
+
def analyze_variable_string(self, var: str):
|
|
83
83
|
r"""
|
|
84
84
|
Parses the input string and return the plot variable and plot range.
|
|
85
85
|
|
|
86
86
|
Args:
|
|
87
|
-
var:
|
|
87
|
+
var (str): string of variables to be parsed
|
|
88
88
|
Example: var = "{bb}<(-10)>(-9.8)"
|
|
89
89
|
|
|
90
90
|
Return: a tuple of the variable name, variable min and max.
|
|
@@ -116,7 +116,7 @@ class DataContainer(object):
|
|
|
116
116
|
Evaluates the variable expression and return the result of an YTArray.
|
|
117
117
|
|
|
118
118
|
Args:
|
|
119
|
-
expression:
|
|
119
|
+
expression (str): Python codes to be executed
|
|
120
120
|
Example: expression = "np.log({rhos0}+{rhos1})"
|
|
121
121
|
"""
|
|
122
122
|
|
|
@@ -138,8 +138,7 @@ class DataContainer(object):
|
|
|
138
138
|
Adds a variable to the dataset.
|
|
139
139
|
|
|
140
140
|
Args:
|
|
141
|
-
name:
|
|
142
|
-
The name of the variable to be added into self.data
|
|
141
|
+
name (str): The name of the variable to be added.
|
|
143
142
|
|
|
144
143
|
val: array-like structure
|
|
145
144
|
Values of the variable stored in an array
|
|
@@ -157,8 +156,7 @@ class DataContainer(object):
|
|
|
157
156
|
Return raw variables or calculate derived variables.
|
|
158
157
|
|
|
159
158
|
Args:
|
|
160
|
-
var:
|
|
161
|
-
variable name
|
|
159
|
+
var (str): variable name
|
|
162
160
|
|
|
163
161
|
Return: YTArray
|
|
164
162
|
"""
|
|
@@ -217,8 +215,7 @@ class DataContainer3D(DataContainer):
|
|
|
217
215
|
):
|
|
218
216
|
r"""
|
|
219
217
|
Args:
|
|
220
|
-
dataSets:
|
|
221
|
-
The key is the variable name, and the dictionary value is usually a YTArray.
|
|
218
|
+
dataSets (dict): The keys are variable names, and the dictionary values are YTArray.
|
|
222
219
|
|
|
223
220
|
x/y/z: A 1D YTArray
|
|
224
221
|
"""
|
|
@@ -230,11 +227,9 @@ class DataContainer3D(DataContainer):
|
|
|
230
227
|
"""Get a 2D slice from the 3D box data.
|
|
231
228
|
|
|
232
229
|
Args:
|
|
233
|
-
norm:
|
|
234
|
-
The normal direction of the slice from "x", "y" or "z"
|
|
230
|
+
norm (str): The normal direction of the slice from "x", "y" or "z"
|
|
235
231
|
|
|
236
|
-
cur_loc:
|
|
237
|
-
The position of slicing.
|
|
232
|
+
cur_loc (float): The position of slicing.
|
|
238
233
|
|
|
239
234
|
Return: DataContainer2D
|
|
240
235
|
"""
|
|
@@ -293,18 +288,15 @@ class DataContainer2D(DataContainer):
|
|
|
293
288
|
):
|
|
294
289
|
r"""
|
|
295
290
|
Args:
|
|
296
|
-
dataSets:
|
|
297
|
-
The keys are variable names, and the values are YTArrays.
|
|
291
|
+
dataSets (dict): The keys are variable names, and the values are YTArrays.
|
|
298
292
|
|
|
299
293
|
x/y: 1D YTArray
|
|
300
294
|
|
|
301
|
-
xlabel/ylabel:
|
|
295
|
+
xlabel/ylabel (str): x, y dimension labels
|
|
302
296
|
|
|
303
|
-
cut_norm:
|
|
304
|
-
"x", "y" or "z"
|
|
297
|
+
cut_norm (str): "x", "y" or "z"
|
|
305
298
|
|
|
306
|
-
cut_loc:
|
|
307
|
-
cut_norm and cut_loc are used to record the position of slice if this 2D data set is obtained from a 3D box.
|
|
299
|
+
cut_loc (float): cut_norm and cut_loc are used to record the position of slice if this 2D data set is obtained from a 3D box.
|
|
308
300
|
"""
|
|
309
301
|
|
|
310
302
|
zlabel = None
|
|
@@ -327,15 +319,15 @@ class DataContainer2D(DataContainer):
|
|
|
327
319
|
vars,
|
|
328
320
|
xlim=None,
|
|
329
321
|
ylim=None,
|
|
330
|
-
unit="planet",
|
|
331
|
-
nlevels=200,
|
|
332
|
-
cmap="turbo",
|
|
322
|
+
unit: str = "planet",
|
|
323
|
+
nlevels: int = 200,
|
|
324
|
+
cmap: str = "turbo",
|
|
333
325
|
figsize=(10, 6),
|
|
334
326
|
pcolor=False,
|
|
335
327
|
logscale=False,
|
|
336
328
|
addgrid=False,
|
|
337
329
|
bottomline=10,
|
|
338
|
-
showcolorbar=True,
|
|
330
|
+
showcolorbar: bool = True,
|
|
339
331
|
*args,
|
|
340
332
|
**kwargs,
|
|
341
333
|
):
|
|
@@ -343,25 +335,20 @@ class DataContainer2D(DataContainer):
|
|
|
343
335
|
2D plots.
|
|
344
336
|
|
|
345
337
|
Args:
|
|
346
|
-
vars:
|
|
347
|
-
Ploting variables and ploting range.
|
|
338
|
+
vars (str): ploting variables and ploting range.
|
|
348
339
|
Example: vars = "Bx<(50)>(-50) By (np.log(2*{rhos0}))>(-5)"
|
|
349
340
|
|
|
350
341
|
xlim/ylim: A list/tuple contains the x- y-axis range
|
|
351
342
|
|
|
352
|
-
unit:
|
|
353
|
-
"planet" or "si"
|
|
343
|
+
unit (str): "planet" or "si"
|
|
354
344
|
|
|
355
|
-
nlevels:
|
|
356
|
-
Number of the contour levels
|
|
345
|
+
nlevels (int): Number of the contour levels. Default 200.
|
|
357
346
|
|
|
358
|
-
cmap:
|
|
359
|
-
Color map type
|
|
347
|
+
cmap (str): color map type from Matplotlib
|
|
360
348
|
|
|
361
|
-
figsize:
|
|
349
|
+
figsize (tuple): size of figure. Default (10, 6).
|
|
362
350
|
|
|
363
|
-
logscale:
|
|
364
|
-
True to scale the variable in log.
|
|
351
|
+
logscale (bool): True to scale the variable in log.
|
|
365
352
|
|
|
366
353
|
Examples:
|
|
367
354
|
>>> f, axes = dc.contour("Bx<(50)>(-50) By (np.log(2*{rhos0}))>(-5)", xlim=[-40,-5])
|
|
@@ -469,10 +456,9 @@ class DataContainer2D(DataContainer):
|
|
|
469
456
|
r"""Adding contour lines to an axis.
|
|
470
457
|
|
|
471
458
|
Args:
|
|
472
|
-
ax
|
|
473
|
-
The axis to plot contour lines.
|
|
459
|
+
ax (matplotlib axis): the axis to plot contour lines.
|
|
474
460
|
|
|
475
|
-
var:
|
|
461
|
+
var (str): variable of contours.
|
|
476
462
|
|
|
477
463
|
Examples:
|
|
478
464
|
>>> f, axes = dc.plot("Bx<(50)>(-50) By (np.log(2*{rhos0}))>(-5)", xlim=[-40,-5])
|
|
@@ -521,14 +507,11 @@ class DataContainer2D(DataContainer):
|
|
|
521
507
|
Adding streamlines to an axis.
|
|
522
508
|
|
|
523
509
|
Args:
|
|
524
|
-
ax
|
|
525
|
-
The axis to add streamlines
|
|
510
|
+
ax (matplotlib axis): the axis to add streamlines.
|
|
526
511
|
|
|
527
|
-
var1/var2:
|
|
528
|
-
Streamline variable names
|
|
512
|
+
var1/var2 (str): streamline variable names.
|
|
529
513
|
|
|
530
|
-
density:
|
|
531
|
-
It controls the number of streamlines.
|
|
514
|
+
density (float): it controls the number of streamlines.
|
|
532
515
|
|
|
533
516
|
Examples:
|
|
534
517
|
>>> f, axes = dc.plot("Bx<(50)>(-50) By (np.log(2*{rhos0}))>(-5)", xlim=[-40,-5])
|
|
@@ -589,12 +572,11 @@ class DataContainer1D(DataContainer):
|
|
|
589
572
|
def __init__(self, dataSets, x, xlabel, *args, **kwargs):
|
|
590
573
|
r"""
|
|
591
574
|
Args:
|
|
592
|
-
dataSets:
|
|
593
|
-
The key is the variable name, and the dictionary value is usually a YTArray.
|
|
575
|
+
dataSets (dict): the keys are variable names, and the values are YTArrays.
|
|
594
576
|
|
|
595
577
|
x: 1D YTArray
|
|
596
578
|
|
|
597
|
-
xlabel:
|
|
579
|
+
xlabel (str): x axis label.
|
|
598
580
|
"""
|
|
599
581
|
|
|
600
582
|
ylabel = None
|
|
@@ -76,7 +76,16 @@ plot_unit_si = {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
|
|
79
|
-
def get_unit(var, unit_type="planet"):
|
|
79
|
+
def get_unit(var: str, unit_type="planet") -> str:
|
|
80
|
+
"""Return the unit of variable.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
var (str): variable name.
|
|
84
|
+
unit_type (str, optional): unit system. Defaults to "planet".
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
str: unit in the specified unit system.
|
|
88
|
+
"""
|
|
80
89
|
if var[-1].isdigit():
|
|
81
90
|
# Example: pxxs0 -> pxx
|
|
82
91
|
var = var[0:-2]
|
|
@@ -111,21 +120,24 @@ def get_ticks(vmin, vmax):
|
|
|
111
120
|
nticks = int((tickMax - tickMin) / dv) + 1
|
|
112
121
|
return np.linspace(tickMin, tickMax, nticks)
|
|
113
122
|
|
|
123
|
+
|
|
114
124
|
def unit_one(field, data):
|
|
115
125
|
"""Utility function for setting equal weights for macroparticles.
|
|
116
126
|
TBD: add units.
|
|
117
127
|
"""
|
|
118
128
|
return np.ones_like(data[("particles", "p_w")])
|
|
119
129
|
|
|
120
|
-
|
|
130
|
+
|
|
131
|
+
def download_testfile(url: str, target_path="."):
|
|
121
132
|
"""
|
|
122
133
|
Downloads a tar.gz file from a URL and extracts its contents.
|
|
123
134
|
|
|
124
135
|
Args:
|
|
125
|
-
url:
|
|
126
|
-
target_path:
|
|
127
|
-
Defaults to the current directory.
|
|
136
|
+
url (str): the URL of the tar.gz file.
|
|
137
|
+
target_path (str): the directory to extract the files to. Defaults to the current directory.
|
|
128
138
|
"""
|
|
139
|
+
import os
|
|
140
|
+
|
|
129
141
|
try:
|
|
130
142
|
response = requests.get(url, stream=True)
|
|
131
143
|
response.raise_for_status() # Raise an exception for bad status codes
|
|
@@ -134,6 +146,9 @@ def download_testfile(url, target_path="."):
|
|
|
134
146
|
for chunk in response.iter_content(chunk_size=8192):
|
|
135
147
|
f.write(chunk)
|
|
136
148
|
|
|
149
|
+
if not os.path.exists(target_path):
|
|
150
|
+
os.makedirs(target_path)
|
|
151
|
+
|
|
137
152
|
with tarfile.open("temp.tar.gz", "r:gz") as tar:
|
|
138
153
|
tar.extractall(target_path)
|
|
139
154
|
|
|
@@ -142,7 +157,5 @@ def download_testfile(url, target_path="."):
|
|
|
142
157
|
except tarfile.TarError as e:
|
|
143
158
|
print(f"Error extracting tar file: {e}")
|
|
144
159
|
finally:
|
|
145
|
-
import os
|
|
146
|
-
|
|
147
160
|
if os.path.exists("temp.tar.gz"):
|
|
148
161
|
os.remove("temp.tar.gz") # Clean up temporary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|