fdsreader 1.2.0rc2__tar.gz → 1.3.7__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.
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/LICENSE +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/MANIFEST.in +0 -0
- {fdsreader-1.2.0rc2/fdsreader.egg-info → fdsreader-1.3.7}/PKG-INFO +2 -2
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/README.md +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/__init__.py +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/_version.py +1 -1
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/bndf/ObstructionCollection.py +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/bndf/__init__.py +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/bndf/obstruction.py +14 -9
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/bndf/utils.py +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/evac/EvacCollection.py +76 -46
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/evac/__init__.py +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/evac/evacuation.py +33 -5
- fdsreader-1.3.7/fdsreader/export/__init__.py +3 -0
- fdsreader-1.3.7/fdsreader/export/obst_exporter.py +116 -0
- fdsreader-1.3.7/fdsreader/export/slcf_exporter.py +63 -0
- fdsreader-1.3.7/fdsreader/export/smoke3d_exporter.py +70 -0
- {fdsreader-1.2.0rc2/fdsreader/utils → fdsreader-1.3.7/fdsreader}/fds_classes/MeshCollection.py +1 -1
- fdsreader-1.3.7/fdsreader/fds_classes/__init__.py +7 -0
- {fdsreader-1.2.0rc2/fdsreader/utils → fdsreader-1.3.7/fdsreader}/fds_classes/mesh.py +45 -4
- {fdsreader-1.2.0rc2/fdsreader/utils → fdsreader-1.3.7/fdsreader}/fds_classes/surface.py +0 -0
- {fdsreader-1.2.0rc2/fdsreader/utils → fdsreader-1.3.7/fdsreader}/fds_classes/ventilation.py +2 -1
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/geom/GeometryCollection.py +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/geom/__init__.py +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/geom/geometry.py +2 -1
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/isof/IsosurfaceCollection.py +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/isof/__init__.py +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/isof/isosurface.py +2 -1
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/part/ParticleCollection.py +1 -1
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/part/__init__.py +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/part/particle.py +2 -1
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/pl3d/Plot3DCollection.py +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/pl3d/__init__.py +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/pl3d/pl3d.py +8 -1
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/settings.py +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/simulation.py +100 -20
- fdsreader-1.3.7/fdsreader/slcf/GeomSliceCollection.py +62 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/slcf/SliceCollection.py +1 -1
- fdsreader-1.3.7/fdsreader/slcf/__init__.py +7 -0
- fdsreader-1.3.7/fdsreader/slcf/geomslice.py +458 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/slcf/slice.py +137 -25
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/smoke3d/Smoke3DCollection.py +1 -1
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/smoke3d/__init__.py +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/smoke3d/smoke3d.py +11 -5
- fdsreader-1.3.7/fdsreader/utils/__init__.py +7 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/utils/data.py +25 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/utils/dimension.py +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/utils/extent.py +13 -10
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/utils/fortran_data.py +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader/utils/misc.py +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7/fdsreader.egg-info}/PKG-INFO +2 -2
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader.egg-info/SOURCES.txt +12 -6
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader.egg-info/dependency_links.txt +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader.egg-info/requires.txt +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/fdsreader.egg-info/top_level.txt +0 -0
- fdsreader-1.3.7/requirements.txt +118 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/setup.cfg +0 -0
- {fdsreader-1.2.0rc2 → fdsreader-1.3.7}/setup.py +2 -2
- fdsreader-1.2.0rc2/fdsreader/slcf/__init__.py +0 -3
- fdsreader-1.2.0rc2/fdsreader/utils/__init__.py +0 -15
- fdsreader-1.2.0rc2/fdsreader/utils/fds_classes/__init__.py +0 -1
- fdsreader-1.2.0rc2/requirements.txt +0 -113
|
File without changes
|
|
File without changes
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fdsreader
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.7
|
|
4
4
|
Summary: Python reader for data generated by FDS.
|
|
5
|
-
Home-page: https://github.com/
|
|
5
|
+
Home-page: https://github.com/FireDynamics/fdsreader
|
|
6
6
|
Author: FZJ IAS-7 (Prof. Dr. Lukas Arnold, Jan Vogelsang)
|
|
7
7
|
Author-email: j.vogelsang@fz-juelich.de
|
|
8
8
|
License: UNKNOWN
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -3,7 +3,7 @@ from typing import List, Dict, Tuple, Union, Sequence
|
|
|
3
3
|
from typing_extensions import Literal
|
|
4
4
|
import numpy as np
|
|
5
5
|
|
|
6
|
-
from fdsreader.utils import
|
|
6
|
+
from fdsreader.utils import Extent, Quantity, Dimension
|
|
7
7
|
import fdsreader.utils.fortran_data as fdtype
|
|
8
8
|
from fdsreader import settings
|
|
9
9
|
|
|
@@ -149,12 +149,12 @@ class SubObstruction:
|
|
|
149
149
|
|
|
150
150
|
:ivar extent: :class:`Extent` object containing 3-dimensional extent information.
|
|
151
151
|
:ivar bound_indices: Indices used to define obstruction bounds in terms of mesh locations.
|
|
152
|
-
:ivar side_surfaces: Tuple of six
|
|
152
|
+
:ivar side_surfaces: Tuple of six :class:`Surface` s for each side of the cuboid.
|
|
153
153
|
:ivar hide_times: List with points in time from when on the SubObstruction will be hidden.
|
|
154
154
|
:ivar show_times: List with points in time from when on the SubObstruction will be shown.
|
|
155
155
|
"""
|
|
156
156
|
|
|
157
|
-
def __init__(self, side_surfaces: Tuple
|
|
157
|
+
def __init__(self, side_surfaces: Tuple, bound_indices: Tuple[int, int, int, int, int, int],
|
|
158
158
|
extent: Extent):
|
|
159
159
|
self.extent = extent
|
|
160
160
|
self.side_surfaces = side_surfaces
|
|
@@ -167,15 +167,20 @@ class SubObstruction:
|
|
|
167
167
|
self.hide_times = list()
|
|
168
168
|
self.show_times = list()
|
|
169
169
|
|
|
170
|
-
def _add_patches(self, bid: int, cell_centered: bool, quantity: str, short_name: str, unit: str,
|
|
171
|
-
times: np.ndarray, n_t: int, lower_bounds: np.ndarray,
|
|
170
|
+
def _add_patches(self, bid: int, cell_centered: bool, quantity: str, short_name: str, unit: str,
|
|
171
|
+
patches: List[Patch], times: np.ndarray, n_t: int, lower_bounds: np.ndarray,
|
|
172
|
+
upper_bounds: np.ndarray):
|
|
172
173
|
if bid not in self._boundary_data:
|
|
173
|
-
self._boundary_data[bid] = Boundary(Quantity(quantity, short_name, unit), cell_centered, times, n_t,
|
|
174
|
-
lower_bounds, upper_bounds)
|
|
174
|
+
self._boundary_data[bid] = Boundary(Quantity(quantity, short_name, unit), cell_centered, times, n_t,
|
|
175
|
+
patches, lower_bounds, upper_bounds)
|
|
175
176
|
|
|
176
177
|
if not settings.LAZY_LOAD:
|
|
177
178
|
_ = self._boundary_data[bid].data
|
|
178
179
|
|
|
180
|
+
@property
|
|
181
|
+
def has_boundary_data(self):
|
|
182
|
+
return len(self._boundary_data) != 0
|
|
183
|
+
|
|
179
184
|
def get_data(self, quantity: Union[str, Quantity]):
|
|
180
185
|
if type(quantity) == Quantity:
|
|
181
186
|
quantity = quantity.name
|
|
@@ -303,7 +308,7 @@ class Obstruction:
|
|
|
303
308
|
if type(quantity) == Quantity:
|
|
304
309
|
quantity = quantity.name
|
|
305
310
|
|
|
306
|
-
ret = [subobst.get_data(quantity) for subobst in self._subobstructions]
|
|
311
|
+
ret = [subobst.get_data(quantity) for subobst in self._subobstructions if subobst.has_boundary_data]
|
|
307
312
|
if orientation == 0:
|
|
308
313
|
return ret
|
|
309
314
|
return [bndf for bndf in ret if orientation in bndf.data.keys()]
|
|
@@ -312,7 +317,7 @@ class Obstruction:
|
|
|
312
317
|
def has_boundary_data(self):
|
|
313
318
|
"""Whether boundary data has been output in the simulation.
|
|
314
319
|
"""
|
|
315
|
-
return
|
|
320
|
+
return any(subobst.has_boundary_data for subobst in self._subobstructions)
|
|
316
321
|
|
|
317
322
|
def clear_cache(self):
|
|
318
323
|
"""Remove all data from the internal cache that has been loaded so far to free memory.
|
|
File without changes
|
|
@@ -4,15 +4,15 @@ from typing import Iterable, Dict, List, Union
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
|
|
6
6
|
from fdsreader.evac import Evacuation
|
|
7
|
-
from fdsreader.
|
|
7
|
+
from fdsreader.fds_classes import Mesh
|
|
8
8
|
from fdsreader.utils.data import FDSDataCollection, Quantity
|
|
9
9
|
import fdsreader.utils.fortran_data as fdtype
|
|
10
10
|
from fdsreader import settings
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class EvacCollection(FDSDataCollection):
|
|
14
|
-
"""Collection of :class:`
|
|
15
|
-
|
|
14
|
+
"""Collection of :class:`Evacuation` objects. Next to agent-class specific data (such as trajectories) lots of
|
|
15
|
+
other data such as FED-data is provided via this class.
|
|
16
16
|
|
|
17
17
|
:ivar times: List of all time steps of the simulation.
|
|
18
18
|
:ivar z_offsets: The offset in z-direction for each mesh where the evac plane lays.
|
|
@@ -92,8 +92,8 @@ class EvacCollection(FDSDataCollection):
|
|
|
92
92
|
units[i] == "TargetDoorCounter"}
|
|
93
93
|
|
|
94
94
|
@property
|
|
95
|
-
def xyz(self) -> np.ndarray:
|
|
96
|
-
"""
|
|
95
|
+
def xyz(self) -> List[np.ndarray]:
|
|
96
|
+
"""List of xyz-data for each mesh.
|
|
97
97
|
"""
|
|
98
98
|
if not hasattr(self, "_xyz"):
|
|
99
99
|
self._load_xyz_data()
|
|
@@ -121,18 +121,26 @@ class EvacCollection(FDSDataCollection):
|
|
|
121
121
|
n_corrs = meta[2]
|
|
122
122
|
n_devc = fdtype.read(infile, fdtype.INT, 1)[0][0][0]
|
|
123
123
|
|
|
124
|
-
n_i
|
|
124
|
+
n_i = list()
|
|
125
|
+
n_j = list()
|
|
126
|
+
for g in range(n_grids):
|
|
127
|
+
n_i_g, n_j_g, _, _ = fdtype.read(infile, dtype_grid_meta, 1)[0][0]
|
|
128
|
+
n_i.append(n_i_g)
|
|
129
|
+
n_j.append(n_j_g)
|
|
130
|
+
for i in range(n_i_g):
|
|
131
|
+
for j in range(n_j_g):
|
|
132
|
+
_ = fdtype.read(infile, dtype_grid_data, 1)
|
|
125
133
|
|
|
126
134
|
# Reset pointer (after file header)
|
|
127
135
|
infile.seek(fdtype.INT.itemsize * 2 + dtype_meta.itemsize)
|
|
128
136
|
|
|
129
|
-
self._xyz = np.empty((
|
|
137
|
+
self._xyz = [np.empty((n_i[g], n_j[g], 3)) for g in range(n_grids)]
|
|
130
138
|
|
|
131
139
|
for g in range(n_grids):
|
|
132
140
|
infile.seek(dtype_grid_meta.itemsize, 1)
|
|
133
|
-
for i in range(n_i):
|
|
134
|
-
for j in range(n_j):
|
|
135
|
-
self._xyz[g
|
|
141
|
+
for i in range(n_i[g]):
|
|
142
|
+
for j in range(n_j[g]):
|
|
143
|
+
self._xyz[g][i, j] = fdtype.read(infile, dtype_grid_data, 1)[0][0]
|
|
136
144
|
|
|
137
145
|
if os.path.exists(self._base_path + ".fed"):
|
|
138
146
|
self._load_fed_data(n_corrs)
|
|
@@ -183,6 +191,9 @@ class EvacCollection(FDSDataCollection):
|
|
|
183
191
|
dtype_meta = fdtype.new((('i', 6),))
|
|
184
192
|
dtype_time = fdtype.new((('f', 2),))
|
|
185
193
|
dtype_grid_meta = fdtype.new((('i', 4),))
|
|
194
|
+
dtype_corr = fdtype.new((('f', 8),))
|
|
195
|
+
dtype_devs_meta = fdtype.new((('i', 2),))
|
|
196
|
+
dtype_devs_data = fdtype.new((('i', 1), ('f', 1), ('i', 2), ('f', 1)))
|
|
186
197
|
|
|
187
198
|
# File header
|
|
188
199
|
file_format = fdtype.read(infile, fdtype.INT, 1)[0][0][0]
|
|
@@ -195,26 +206,35 @@ class EvacCollection(FDSDataCollection):
|
|
|
195
206
|
|
|
196
207
|
# Read gridsize from first timestep header
|
|
197
208
|
infile.seek(dtype_time.itemsize, 1)
|
|
198
|
-
|
|
209
|
+
|
|
210
|
+
n_i = list()
|
|
211
|
+
n_j = list()
|
|
212
|
+
n = list()
|
|
213
|
+
dtype_grid_data = list()
|
|
214
|
+
for g in range(n_grids):
|
|
215
|
+
n_i_g, n_j_g, _, n_g = fdtype.read(infile, dtype_grid_meta, 1)[0][0]
|
|
216
|
+
n_i.append(n_i_g)
|
|
217
|
+
n_j.append(n_j_g)
|
|
218
|
+
n.append(n_g)
|
|
219
|
+
dtype_grid_data.append(fdtype.new((('f', n_g),)))
|
|
220
|
+
for i in range(n_i_g):
|
|
221
|
+
for j in range(n_j_g):
|
|
222
|
+
_ = fdtype.read(infile, dtype_grid_data[-1], 1)
|
|
199
223
|
|
|
200
224
|
# Reset pointer (after file header)
|
|
201
225
|
infile.seek(dtype_meta.itemsize + fdtype.INT.itemsize * 2)
|
|
202
226
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
n_t = (os.stat(file_path).st_size - (fdtype.INT.itemsize * 2 + dtype_meta.itemsize)) // \
|
|
209
|
-
(dtype_time.itemsize + n_grids * (dtype_grid_meta.itemsize + n_i * n_j * dtype_grid_data.itemsize) +
|
|
210
|
-
n_corrs * dtype_corr.itemsize + fdtype.FLOAT.itemsize + n_devc * (
|
|
211
|
-
dtype_devs_meta.itemsize + dtype_devs_data.itemsize))
|
|
227
|
+
n_t = (os.stat(file_path).st_size - (fdtype.INT.itemsize * 2 + dtype_meta.itemsize)) // (
|
|
228
|
+
dtype_time.itemsize + sum(
|
|
229
|
+
(dtype_grid_meta.itemsize + n_i[g] * n_j[g] * dtype_grid_data[g].itemsize) for g in
|
|
230
|
+
range(n_grids)) + n_corrs * dtype_corr.itemsize + fdtype.FLOAT.itemsize + n_devc * (
|
|
231
|
+
dtype_devs_meta.itemsize + dtype_devs_data.itemsize))
|
|
212
232
|
|
|
213
233
|
times = list()
|
|
214
|
-
self._fed_grid = dict(co_co2_o2=[np.empty((n_t, n_i, n_j)) for
|
|
215
|
-
soot_dens=[np.empty((n_t, n_i, n_j)) for
|
|
216
|
-
tmp_g=[np.empty((n_t, n_i, n_j)) for
|
|
217
|
-
radflux=[np.empty((n_t, n_i, n_j)) for
|
|
234
|
+
self._fed_grid = dict(co_co2_o2=[np.empty((n_t, n_i[g], n_j[g])) for g in range(n_grids)],
|
|
235
|
+
soot_dens=[np.empty((n_t, n_i[g], n_j[g])) for g in range(n_grids)],
|
|
236
|
+
tmp_g=[np.empty((n_t, n_i[g], n_j[g])) for g in range(n_grids)],
|
|
237
|
+
radflux=[np.empty((n_t, n_i[g], n_j[g])) for g in range(n_grids)])
|
|
218
238
|
self._fed_corr = dict(co_co2_o2=[np.empty((n_t, 2)) for _ in range(n_corrs)],
|
|
219
239
|
soot_dens=[np.empty((n_t, 2)) for _ in range(n_corrs)],
|
|
220
240
|
tmp_g=[np.empty((n_t, 2)) for _ in range(n_corrs)],
|
|
@@ -229,9 +249,9 @@ class EvacCollection(FDSDataCollection):
|
|
|
229
249
|
|
|
230
250
|
for g in range(n_grids):
|
|
231
251
|
infile.seek(dtype_grid_meta.itemsize, 1)
|
|
232
|
-
for i in range(n_i):
|
|
233
|
-
for j in range(n_j):
|
|
234
|
-
co_co2_o2, soot_dens, tmp_g, radflux = fdtype.read(infile, dtype_grid_data, 1)[0][0][:4]
|
|
252
|
+
for i in range(n_i[g]):
|
|
253
|
+
for j in range(n_j[g]):
|
|
254
|
+
co_co2_o2, soot_dens, tmp_g, radflux = fdtype.read(infile, dtype_grid_data[g], 1)[0][0][:4]
|
|
235
255
|
self._fed_grid["co_co2_o2"][g][t, i, j] = co_co2_o2
|
|
236
256
|
self._fed_grid["soot_dens"][g][t, i, j] = soot_dens
|
|
237
257
|
self._fed_grid["tmp_g"][g][t, i, j] = tmp_g
|
|
@@ -267,29 +287,34 @@ class EvacCollection(FDSDataCollection):
|
|
|
267
287
|
def _load_eff_data(self):
|
|
268
288
|
file_path = self._base_path + ".eff"
|
|
269
289
|
if not os.path.exists(file_path):
|
|
290
|
+
self._eff = None
|
|
270
291
|
return
|
|
271
292
|
|
|
272
293
|
with open(file_path, 'rb') as infile:
|
|
273
294
|
dtype_grid_meta = fdtype.new((('i', 3),))
|
|
274
|
-
dtype_grid_data = fdtype.new((('f', 2),))
|
|
295
|
+
dtype_grid_data = fdtype.new((('f', 2),)) # u, v
|
|
275
296
|
|
|
276
297
|
n_grids = fdtype.read(infile, fdtype.INT, 1)[0][0][0]
|
|
277
298
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
#
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
299
|
+
# n_fields = (os.stat(file_path).st_size - fdtype.INT.itemsize) // (
|
|
300
|
+
# sum(dtype_grid_meta.itemsize + n_i[g] * n_j[g] * dtype_grid_data.itemsize for g in range(n_grids)))
|
|
301
|
+
#
|
|
302
|
+
# self._eff = np.empty((n_grids, n_fields, n_i, n_j, 2))
|
|
303
|
+
# for g in range(n_grids):
|
|
304
|
+
# for f in range(n_fields):
|
|
305
|
+
# infile.seek(dtype_grid_meta.itemsize, 1)
|
|
306
|
+
# for i in range(n_i[g]):
|
|
307
|
+
# for j in range(n_j[g]):
|
|
308
|
+
# self._eff[g, f, i, j] = fdtype.read(infile, dtype_grid_data, 1)[0][0]
|
|
309
|
+
|
|
310
|
+
self._eff = list()
|
|
311
|
+
meta = fdtype.read(infile, dtype_grid_meta, 1)
|
|
312
|
+
while len(meta) > 0:
|
|
313
|
+
n_i, n_j, _ = meta[0][0]
|
|
314
|
+
for i in range(n_i + 2):
|
|
315
|
+
for j in range(n_j + 2):
|
|
316
|
+
self._eff.append(fdtype.read(infile, dtype_grid_data, 1)[0][0])
|
|
317
|
+
meta = fdtype.read(infile, dtype_grid_meta, 1)
|
|
293
318
|
|
|
294
319
|
def get_unfiltered_positions(self, quantity: Union[Quantity, str] = None):
|
|
295
320
|
"""Convenience function that combines all trajectories into a single array.
|
|
@@ -357,7 +382,10 @@ class EvacCollection(FDSDataCollection):
|
|
|
357
382
|
for quantity in evac.quantities:
|
|
358
383
|
evac._data[quantity.name].append(np.empty((size,), dtype=np.float32))
|
|
359
384
|
evac._positions.append(np.empty((size, 3), dtype=np.float32))
|
|
360
|
-
evac.
|
|
385
|
+
evac._body_angles.append(np.empty((size,), dtype=np.float32))
|
|
386
|
+
evac._semi_major_axis.append(np.empty((size,), dtype=np.float32))
|
|
387
|
+
evac._semi_minor_axis.append(np.empty((size,), dtype=np.float32))
|
|
388
|
+
evac._agent_heights.append(np.empty((size,), dtype=np.float32))
|
|
361
389
|
evac._tags.append(np.empty((size,), dtype=int))
|
|
362
390
|
|
|
363
391
|
for mesh, file_path in self._file_paths.items():
|
|
@@ -385,8 +413,10 @@ class EvacCollection(FDSDataCollection):
|
|
|
385
413
|
pos = fdtype.read(infile, dtype_positions, 1)[0][0].reshape((n_humans, 7),
|
|
386
414
|
order='F').astype(float)
|
|
387
415
|
evac._positions[t][offset: offset + n_humans] = pos[:, :3]
|
|
388
|
-
|
|
389
|
-
evac.
|
|
416
|
+
evac._body_angles[t][offset: offset + n_humans] = pos[:, 3]
|
|
417
|
+
evac._semi_major_axis[t][offset: offset + n_humans] = pos[:, 4]
|
|
418
|
+
evac._semi_minor_axis[t][offset: offset + n_humans] = pos[:, 5]
|
|
419
|
+
evac._agent_heights[t][offset: offset + n_humans] = pos[:, 6]
|
|
390
420
|
# Read tags
|
|
391
421
|
dtype_tags = fdtype.new((('i', n_humans),))
|
|
392
422
|
evac._tags[t][offset: offset + n_humans] = fdtype.read(infile, dtype_tags, 1)[0][0]
|
|
File without changes
|
|
@@ -2,7 +2,8 @@ from typing import List, Tuple, Dict, Sequence, Union
|
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
|
|
5
|
-
from fdsreader.
|
|
5
|
+
from fdsreader.fds_classes import Mesh
|
|
6
|
+
from fdsreader.utils import Quantity
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
# class Entrance:
|
|
@@ -54,7 +55,10 @@ class Evacuation:
|
|
|
54
55
|
self.n_humans: Dict[Mesh, List[int]] = dict()
|
|
55
56
|
|
|
56
57
|
self._positions: List[np.ndarray] = list()
|
|
57
|
-
self.
|
|
58
|
+
self._body_angles: List[np.ndarray] = list()
|
|
59
|
+
self._semi_major_axis: List[np.ndarray] = list()
|
|
60
|
+
self._semi_minor_axis: List[np.ndarray] = list()
|
|
61
|
+
self._agent_heights: List[np.ndarray] = list()
|
|
58
62
|
self._tags: List[np.ndarray] = list()
|
|
59
63
|
self._data: Dict[str, List[np.ndarray]] = {q.name: [] for q in self.quantities}
|
|
60
64
|
self.times: Sequence[float] = list()
|
|
@@ -62,7 +66,7 @@ class Evacuation:
|
|
|
62
66
|
self.lower_bounds = {q.name: [] for q in self.quantities}
|
|
63
67
|
self.upper_bounds = {q.name: [] for q in self.quantities}
|
|
64
68
|
|
|
65
|
-
self._init_callback = None
|
|
69
|
+
self._init_callback = lambda: None
|
|
66
70
|
|
|
67
71
|
@property
|
|
68
72
|
def id(self):
|
|
@@ -146,12 +150,36 @@ class Evacuation:
|
|
|
146
150
|
return self._positions
|
|
147
151
|
|
|
148
152
|
@property
|
|
149
|
-
def
|
|
153
|
+
def body_angles(self) -> List[np.ndarray]:
|
|
150
154
|
"""
|
|
151
155
|
"""
|
|
152
156
|
if len(self._positions) == 0 and len(self._tags) == 0:
|
|
153
157
|
self._init_callback()
|
|
154
|
-
return self.
|
|
158
|
+
return self._body_angles
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def semi_major_axis(self) -> List[np.ndarray]:
|
|
162
|
+
"""
|
|
163
|
+
"""
|
|
164
|
+
if len(self._positions) == 0 and len(self._tags) == 0:
|
|
165
|
+
self._init_callback()
|
|
166
|
+
return self._semi_major_axis
|
|
167
|
+
|
|
168
|
+
@property
|
|
169
|
+
def semi_minor_axis(self) -> List[np.ndarray]:
|
|
170
|
+
"""
|
|
171
|
+
"""
|
|
172
|
+
if len(self._positions) == 0 and len(self._tags) == 0:
|
|
173
|
+
self._init_callback()
|
|
174
|
+
return self._semi_minor_axis
|
|
175
|
+
|
|
176
|
+
@property
|
|
177
|
+
def agent_heights(self) -> List[np.ndarray]:
|
|
178
|
+
"""
|
|
179
|
+
"""
|
|
180
|
+
if len(self._positions) == 0 and len(self._tags) == 0:
|
|
181
|
+
self._init_callback()
|
|
182
|
+
return self._agent_heights
|
|
155
183
|
|
|
156
184
|
def clear_cache(self):
|
|
157
185
|
"""Remove all data from the internal cache that has been loaded so far to free memory.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import numpy as np
|
|
4
|
+
from typing_extensions import Literal
|
|
5
|
+
from ..bndf import Obstruction
|
|
6
|
+
from ..bndf.utils import sort_patches_cartesian
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def export_obst_raw(obst: Obstruction, output_dir: str, ordering: Literal['C', 'F'] = 'C'):
|
|
10
|
+
"""Exports the 3d arrays to raw binary files with corresponding .yaml meta files.
|
|
11
|
+
|
|
12
|
+
:param smoke3d: The :class:`Smoke3D` object to export.
|
|
13
|
+
:param output_dir: The directory in which to save all files.
|
|
14
|
+
:param ordering: Whether to write the data in C or Fortran ordering.
|
|
15
|
+
"""
|
|
16
|
+
from pathos.pools import ProcessPool as Pool
|
|
17
|
+
from multiprocess import Lock, Manager
|
|
18
|
+
filename_base = "obst-" + str(obst.id)
|
|
19
|
+
# Create all requested directories if they don't exist yet
|
|
20
|
+
Path(os.path.join(output_dir, filename_base + "-data")).mkdir(parents=True, exist_ok=True)
|
|
21
|
+
|
|
22
|
+
meta = {"BoundingBox": obst.bounding_box.as_list(), "QuantityNum": len(obst.quantities)}
|
|
23
|
+
m = Manager()
|
|
24
|
+
lock = m.Lock()
|
|
25
|
+
meta["Quantities"] = m.list()
|
|
26
|
+
|
|
27
|
+
def worker(quantity, bndf_data):
|
|
28
|
+
quantity_name = quantity.name.replace(" ", "_").replace(".", "-")
|
|
29
|
+
filename = filename_base + "_quantity-" + quantity_name + ".dat"
|
|
30
|
+
|
|
31
|
+
out = {"Quantity": quantity.name.replace(" ", "_").replace(".", "-"), "DataValMax": -100000.,
|
|
32
|
+
"DataValMin": 100000., "ScaleFactor": 1, "DataFile": os.path.join(filename_base + "-data", filename),
|
|
33
|
+
"Orientations": list()}
|
|
34
|
+
for bndf in bndf_data:
|
|
35
|
+
out["DataValMax"] = max(out["DataValMax"], np.max(bndf.upper_bounds))
|
|
36
|
+
out["DataValMin"] = min(out["DataValMin"], np.min(bndf.lower_bounds))
|
|
37
|
+
out["DataValMax"] = float(out["DataValMax"])
|
|
38
|
+
out["DataValMin"] = float(out["DataValMin"])
|
|
39
|
+
out["ScaleFactor"] = 255.0 / out["DataValMax"]
|
|
40
|
+
|
|
41
|
+
# Abort if no useful data is available
|
|
42
|
+
if meta[quantity]["DataValMax"] <= 0:
|
|
43
|
+
return
|
|
44
|
+
|
|
45
|
+
with open(os.path.join(output_dir, quantity_name, filename_base + "-data", filename), 'wb') as rawfile:
|
|
46
|
+
orientations = set()
|
|
47
|
+
for orientation in (-3, -2, -1, 1, 2, 3):
|
|
48
|
+
patches = list()
|
|
49
|
+
for bndf in bndf_data:
|
|
50
|
+
if orientation in bndf.data:
|
|
51
|
+
orientations.add(orientation)
|
|
52
|
+
patches.append(bndf.data[orientation])
|
|
53
|
+
|
|
54
|
+
if len(patches) == 0:
|
|
55
|
+
continue
|
|
56
|
+
|
|
57
|
+
# Combine patches to a single face for plotting
|
|
58
|
+
patches = sort_patches_cartesian(patches)
|
|
59
|
+
|
|
60
|
+
shape_dim1 = sum([patch_row[0].shape[0] for patch_row in patches])
|
|
61
|
+
shape_dim2 = sum([patch.shape[1] for patch in patches[0]])
|
|
62
|
+
n_t = patches[0][0].n_t # Number of timesteps
|
|
63
|
+
|
|
64
|
+
face = np.empty(shape=(n_t, shape_dim1, shape_dim2))
|
|
65
|
+
dim1_pos = 0
|
|
66
|
+
dim2_pos = 0
|
|
67
|
+
for patch_row in patches:
|
|
68
|
+
d1 = patch_row[0].shape[0]
|
|
69
|
+
for patch in patch_row:
|
|
70
|
+
d2 = patch.shape[1]
|
|
71
|
+
face[:, dim1_pos:dim1_pos + d1, dim2_pos:dim2_pos + d2] = patch.data
|
|
72
|
+
dim2_pos += d2
|
|
73
|
+
dim1_pos += d1
|
|
74
|
+
dim2_pos = 0
|
|
75
|
+
|
|
76
|
+
face = (face * meta["ScaleFactor"]).astype(np.uint8)
|
|
77
|
+
|
|
78
|
+
if abs(orientation) == 1:
|
|
79
|
+
spacing1 = (meta["BoundingBox"][3] - meta["BoundingBox"][2]) / face.shape[1]
|
|
80
|
+
spacing2 = (meta["BoundingBox"][5] - meta["BoundingBox"][4]) / face.shape[2]
|
|
81
|
+
elif abs(orientation) == 2:
|
|
82
|
+
spacing1 = (meta["BoundingBox"][1] - meta["BoundingBox"][0]) / face.shape[0]
|
|
83
|
+
spacing2 = (meta["BoundingBox"][5] - meta["BoundingBox"][4]) / face.shape[2]
|
|
84
|
+
else:
|
|
85
|
+
spacing1 = (meta["BoundingBox"][1] - meta["BoundingBox"][0]) / face.shape[0]
|
|
86
|
+
spacing2 = (meta["BoundingBox"][3] - meta["BoundingBox"][2]) / face.shape[1]
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
out["Orientations"].append({
|
|
90
|
+
"Orientation": orientation,
|
|
91
|
+
"MeshPos": f"{meta['BoundingBox'][0]:.6} {meta['BoundingBox'][2]:.6} {meta['BoundingBox'][4]:.6}",
|
|
92
|
+
"Spacing": f"{bndf_data[0].times[1] - bndf_data[0].times[0]:.6} {spacing1:.6} {spacing2:.6}",
|
|
93
|
+
"DimSize": f"{face.shape[2]} {face.shape[1]} {face.shape[2]}"
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
for d in face[:, [2, 0, 1]]: # Make time the first dimension so we can easily iterate over it
|
|
97
|
+
if ordering == 'F':
|
|
98
|
+
d = d.T
|
|
99
|
+
d.tofile(rawfile)
|
|
100
|
+
|
|
101
|
+
out["NumOrientations"] = len(orientations)
|
|
102
|
+
|
|
103
|
+
with lock:
|
|
104
|
+
meta["Quantities"].append(out)
|
|
105
|
+
|
|
106
|
+
worker_args = list()
|
|
107
|
+
for i, quantity in enumerate(obst.quantities):
|
|
108
|
+
bndf_data = obst.get_boundary_data(quantity)
|
|
109
|
+
worker_args.append((quantity, bndf_data))
|
|
110
|
+
Pool(8).map(lambda args: worker(*args), worker_args)
|
|
111
|
+
|
|
112
|
+
meta["Quantities"] = list(meta["Quantities"])
|
|
113
|
+
|
|
114
|
+
with open(os.path.join(output_dir, filename_base + ".yaml"), 'w') as metafile:
|
|
115
|
+
import yaml
|
|
116
|
+
yaml.dump(meta, metafile)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import numpy as np
|
|
4
|
+
from typing_extensions import Literal
|
|
5
|
+
from ..slcf import Slice
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def export_slcf_raw(slc: Slice, output_dir: str, ordering: Literal['C', 'F'] = 'C'):
|
|
9
|
+
"""Exports the 3d arrays to raw binary files with corresponding .yaml meta files.
|
|
10
|
+
|
|
11
|
+
:param slc: The :class:`Slice` object to export.
|
|
12
|
+
:param output_dir: The directory in which to save all files.
|
|
13
|
+
:param ordering: Whether to write the data in C or Fortran ordering.
|
|
14
|
+
"""
|
|
15
|
+
from pathos.pools import ProcessPool as Pool
|
|
16
|
+
from multiprocess import Lock, Manager
|
|
17
|
+
slc2d = slc.type == '2D'
|
|
18
|
+
meta = {"DataValMax": float(slc.vmax), "DataValMin": float(slc.vmin), "ScaleFactor": 255. / (float(slc.vmax) - float(slc.vmin)),
|
|
19
|
+
"MeshNum": len(slc.subslices), "Quantity": slc.quantity.name}
|
|
20
|
+
|
|
21
|
+
filename_base = ("slice" + ("2D-" if slc2d else "3D-") + slc.id.lower()).replace(" ", "_").replace(".", "-")
|
|
22
|
+
# Create all requested directories if they don't exist yet
|
|
23
|
+
Path(os.path.join(output_dir, filename_base + "-data")).mkdir(parents=True, exist_ok=True)
|
|
24
|
+
|
|
25
|
+
m = Manager()
|
|
26
|
+
meta["Meshes"] = m.list()
|
|
27
|
+
lock = m.Lock()
|
|
28
|
+
|
|
29
|
+
def worker(mesh, subslice):
|
|
30
|
+
mesh_id = mesh.id.replace(" ", "_").replace(".", "-")
|
|
31
|
+
filename = filename_base + "_mesh-" + mesh_id + ".dat"
|
|
32
|
+
|
|
33
|
+
data = ((subslice.data - meta["DataValMin"]) * meta["ScaleFactor"]).astype(np.uint8)
|
|
34
|
+
shape = data.shape
|
|
35
|
+
if slc2d:
|
|
36
|
+
shape = shape[:subslice.orientation] + (1,) + shape[subslice.orientation:]
|
|
37
|
+
|
|
38
|
+
with open(os.path.join(output_dir, filename_base + "-data", filename), 'wb') as rawfile:
|
|
39
|
+
for d in data:
|
|
40
|
+
if ordering == 'F':
|
|
41
|
+
d = d.T
|
|
42
|
+
d.tofile(rawfile)
|
|
43
|
+
|
|
44
|
+
spacing = [slc.times[1] - slc.times[0],
|
|
45
|
+
mesh.coordinates['x'][1] - mesh.coordinates['x'][0],
|
|
46
|
+
mesh.coordinates['y'][1] - mesh.coordinates['y'][0],
|
|
47
|
+
mesh.coordinates['z'][1] - mesh.coordinates['z'][0]]
|
|
48
|
+
with lock:
|
|
49
|
+
meta["Meshes"].append({
|
|
50
|
+
"Mesh": mesh_id,
|
|
51
|
+
"DataFile": os.path.join(filename_base + "-data", filename),
|
|
52
|
+
"MeshPos": f"{mesh.coordinates['x'][0]:.6} {mesh.coordinates['y'][0]:.6} {mesh.coordinates['z'][0]:.6}",
|
|
53
|
+
"Spacing": f"{spacing[0]:.6} {spacing[1]:.6} {spacing[2]:.6} {spacing[3]:.6}",
|
|
54
|
+
"DimSize": f"{shape[0]} {shape[1]} {shape[2]} {shape[3]}"
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
Pool(8).map(lambda args: worker(*args), list(slc._subslices.items()))
|
|
58
|
+
|
|
59
|
+
meta["Meshes"] = list(meta["Meshes"])
|
|
60
|
+
|
|
61
|
+
with open(os.path.join(output_dir, filename_base + ".yaml"), 'w') as metafile:
|
|
62
|
+
import yaml
|
|
63
|
+
yaml.dump(meta, metafile)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import numpy as np
|
|
4
|
+
from typing_extensions import Literal
|
|
5
|
+
from ..smoke3d import Smoke3D
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def export_smoke_raw(smoke3d: Smoke3D, output_dir: str, ordering: Literal['C', 'F'] = 'C'):
|
|
9
|
+
"""Exports the 3d arrays to raw binary files with corresponding .yaml meta files.
|
|
10
|
+
|
|
11
|
+
:param smoke3d: The :class:`Smoke3D` object to export.
|
|
12
|
+
:param output_dir: The directory in which to save all files.
|
|
13
|
+
:param ordering: Whether to write the data in C or Fortran ordering.
|
|
14
|
+
"""
|
|
15
|
+
from pathos.pools import ProcessPool as Pool
|
|
16
|
+
from multiprocess import Lock, Manager
|
|
17
|
+
filename_base = ("smoke-" + smoke3d.quantity.name.lower()).replace(" ", "_").replace(".", "-")
|
|
18
|
+
# Create all requested directories if they don't exist yet
|
|
19
|
+
Path(os.path.join(output_dir, filename_base + "-data")).mkdir(parents=True, exist_ok=True)
|
|
20
|
+
|
|
21
|
+
meta = {"DataValMax": -100000., "DataValMin": 100000., "ScaleFactor": 1, "MeshNum": len(smoke3d.subsmokes),
|
|
22
|
+
"Quantity": smoke3d.quantity.name}
|
|
23
|
+
|
|
24
|
+
for subsmoke in smoke3d._subsmokes.values():
|
|
25
|
+
meta["DataValMax"] = max(meta["DataValMax"], np.max(subsmoke.data))
|
|
26
|
+
meta["DataValMin"] = min(meta["DataValMin"], np.min(subsmoke.data))
|
|
27
|
+
meta["DataValMax"] = float(meta["DataValMax"])
|
|
28
|
+
meta["DataValMin"] = float(meta["DataValMin"])
|
|
29
|
+
meta["ScaleFactor"] = 255.0 / meta["DataValMax"]
|
|
30
|
+
|
|
31
|
+
# Abort if no useful data is available
|
|
32
|
+
if meta["DataValMax"] <= 0:
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
m = Manager()
|
|
36
|
+
meta["Meshes"] = m.list()
|
|
37
|
+
lock = m.Lock()
|
|
38
|
+
|
|
39
|
+
def worker(mesh, subsmoke):
|
|
40
|
+
mesh_id = mesh.id.replace(" ", "_").replace(".", "-")
|
|
41
|
+
filename = filename_base + "_mesh-" + mesh_id + ".dat"
|
|
42
|
+
|
|
43
|
+
data = (subsmoke.data * meta["ScaleFactor"]).astype(np.uint8)
|
|
44
|
+
|
|
45
|
+
with open(os.path.join(output_dir, filename_base + "-data", filename), 'wb') as rawfile:
|
|
46
|
+
for d in data:
|
|
47
|
+
if ordering == 'F':
|
|
48
|
+
d = d.T
|
|
49
|
+
d.tofile(rawfile)
|
|
50
|
+
|
|
51
|
+
spacing = [smoke3d.times[1] - smoke3d.times[0],
|
|
52
|
+
mesh.coordinates['x'][1] - mesh.coordinates['x'][0],
|
|
53
|
+
mesh.coordinates['y'][1] - mesh.coordinates['y'][0],
|
|
54
|
+
mesh.coordinates['z'][1] - mesh.coordinates['z'][0]]
|
|
55
|
+
with lock:
|
|
56
|
+
meta["Meshes"].append({
|
|
57
|
+
"Mesh": mesh_id,
|
|
58
|
+
"DataFile": os.path.join(filename_base + "-data", filename),
|
|
59
|
+
"MeshPos": f"{mesh.coordinates['x'][0]:.6} {mesh.coordinates['y'][0]:.6} {mesh.coordinates['z'][0]:.6}",
|
|
60
|
+
"Spacing": f"{spacing[0]:.6} {spacing[1]:.6} {spacing[2]:.6} {spacing[3]:.6}",
|
|
61
|
+
"DimSize": f"{data.shape[0]} {data.shape[1]} {data.shape[2]} {data.shape[3]}"
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
Pool(8).map(lambda args: worker(*args), list(smoke3d._subsmokes.items()))
|
|
65
|
+
|
|
66
|
+
meta["Meshes"] = list(meta["Meshes"])
|
|
67
|
+
|
|
68
|
+
with open(os.path.join(output_dir, filename_base + ".yaml"), 'w') as metafile:
|
|
69
|
+
import yaml
|
|
70
|
+
yaml.dump(meta, metafile)
|