fullwave25 1.3.1.dev0__py3-none-any.whl → 1.3.2.dev1__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.
- fullwave/__init__.py +1 -1
- fullwave/solver/binary_manager.py +1 -1
- fullwave/solver/solver.py +183 -35
- {fullwave25-1.3.1.dev0.dist-info → fullwave25-1.3.2.dev1.dist-info}/METADATA +1 -1
- {fullwave25-1.3.1.dev0.dist-info → fullwave25-1.3.2.dev1.dist-info}/RECORD +7 -7
- {fullwave25-1.3.1.dev0.dist-info → fullwave25-1.3.2.dev1.dist-info}/WHEEL +1 -1
- {fullwave25-1.3.1.dev0.dist-info → fullwave25-1.3.2.dev1.dist-info}/licenses/LICENSE +0 -0
fullwave/__init__.py
CHANGED
|
@@ -66,7 +66,7 @@ try:
|
|
|
66
66
|
__version__ = version("fullwave")
|
|
67
67
|
except PackageNotFoundError:
|
|
68
68
|
# Update via bump-my-version, not manually
|
|
69
|
-
__version__ = "1.3.
|
|
69
|
+
__version__ = "1.3.2-dev1"
|
|
70
70
|
|
|
71
71
|
VERSION = __version__ # for convenience
|
|
72
72
|
logger.info("Fullwave version: %s", __version__)
|
|
@@ -28,7 +28,7 @@ CACHE_DIR = Path.home() / ".cache" / "fullwave25" / "bins"
|
|
|
28
28
|
|
|
29
29
|
# Pinned release tag for the solver binaries.
|
|
30
30
|
# Update this only when new binaries are uploaded to a GitHub release.
|
|
31
|
-
BINARY_RELEASE_TAG = "fullwave_bin_v1.4.
|
|
31
|
+
BINARY_RELEASE_TAG = "fullwave_bin_v1.4.3"
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
def _download_url(filename: str, tag: str) -> str:
|
fullwave/solver/solver.py
CHANGED
|
@@ -1197,11 +1197,21 @@ class Solver:
|
|
|
1197
1197
|
|
|
1198
1198
|
n_source_timesteps = source.icmat.shape[1]
|
|
1199
1199
|
|
|
1200
|
-
|
|
1200
|
+
gib = 1024.0**3
|
|
1201
1201
|
|
|
1202
1202
|
base_depth = depth // n_gpus
|
|
1203
1203
|
remainder = depth % n_gpus
|
|
1204
1204
|
|
|
1205
|
+
box, hole = (None, None)
|
|
1206
|
+
if not self.use_exponential_attenuation:
|
|
1207
|
+
box, hole = self._relaxation_regions(medium)
|
|
1208
|
+
# Every GPU holds every source matrix and every zero pressure coordinate.
|
|
1209
|
+
source_points = sum(
|
|
1210
|
+
getattr(source, name, 0) or 0
|
|
1211
|
+
for name in ("n_sources", "n_sources_add", "n_sources_u", "n_sources_v", "n_sources_w")
|
|
1212
|
+
)
|
|
1213
|
+
body_start = 0
|
|
1214
|
+
|
|
1205
1215
|
for rank, dev_id in enumerate(device_ids):
|
|
1206
1216
|
depth_this = base_depth + (1 if rank < remainder else 0)
|
|
1207
1217
|
|
|
@@ -1213,10 +1223,12 @@ class Solver:
|
|
|
1213
1223
|
n_halo_sides = 2
|
|
1214
1224
|
local_depth = depth_this + n_halo_sides * halo_depth
|
|
1215
1225
|
slab = local_depth * lateral
|
|
1226
|
+
low = max(body_start - (halo_depth if rank > 0 else 0), 0)
|
|
1227
|
+
high = min(body_start + depth_this + (halo_depth if rank < n_gpus - 1 else 0), depth)
|
|
1228
|
+
body_start += depth_this
|
|
1216
1229
|
|
|
1217
1230
|
n_sources = max(source.n_sources // n_gpus, 0)
|
|
1218
1231
|
n_sensors = max(sensor.n_sensors // n_gpus, 0)
|
|
1219
|
-
n_air_local = max(medium.n_air // n_gpus, 0)
|
|
1220
1232
|
|
|
1221
1233
|
if self.use_exponential_attenuation:
|
|
1222
1234
|
total = self._mem_exponential(
|
|
@@ -1231,29 +1243,32 @@ class Solver:
|
|
|
1231
1243
|
is_3d=self.is_3d,
|
|
1232
1244
|
)
|
|
1233
1245
|
else:
|
|
1246
|
+
band, interior = self._band_and_interior(low, high, grid.shape, box, hole)
|
|
1234
1247
|
total = self._mem_relaxation(
|
|
1235
1248
|
slab,
|
|
1236
1249
|
n_deriv_levels,
|
|
1237
|
-
|
|
1250
|
+
source_points,
|
|
1238
1251
|
n_source_timesteps,
|
|
1239
1252
|
save_gpu_memory=self.save_gpu_memory,
|
|
1240
|
-
n_air=
|
|
1253
|
+
n_air=medium.n_air,
|
|
1241
1254
|
n_sensors=n_sensors,
|
|
1242
1255
|
n_relax=self.n_relax_mechanisms,
|
|
1243
1256
|
float_bytes=float_bytes,
|
|
1244
1257
|
int_bytes=int_bytes,
|
|
1245
1258
|
is_3d=self.is_3d,
|
|
1259
|
+
band=band,
|
|
1260
|
+
interior=interior,
|
|
1246
1261
|
)
|
|
1247
1262
|
|
|
1248
1263
|
mode = "exponential" if self.use_exponential_attenuation else "relaxation"
|
|
1249
1264
|
saving = ", save_gpu_memory=True" if self.save_gpu_memory else ""
|
|
1250
1265
|
logger.info(
|
|
1251
1266
|
"GPU memory estimate [GPU %s] (%s mode%s): "
|
|
1252
|
-
"%.2f
|
|
1267
|
+
"%.2f GiB (depth=%d +%d halo, lateral=%d)",
|
|
1253
1268
|
dev_id.strip(),
|
|
1254
1269
|
mode,
|
|
1255
1270
|
saving,
|
|
1256
|
-
total /
|
|
1271
|
+
total / gib,
|
|
1257
1272
|
depth_this,
|
|
1258
1273
|
n_halo_sides * halo_depth,
|
|
1259
1274
|
lateral,
|
|
@@ -1337,8 +1352,20 @@ class Solver:
|
|
|
1337
1352
|
float_bytes: int,
|
|
1338
1353
|
int_bytes: int,
|
|
1339
1354
|
is_3d: bool,
|
|
1355
|
+
band: int | None = None,
|
|
1356
|
+
interior: int | None = None,
|
|
1340
1357
|
) -> int:
|
|
1341
|
-
"""Return estimated GPU bytes for relaxation (power-law) solver.
|
|
1358
|
+
"""Return estimated GPU bytes for the relaxation (power-law) solver.
|
|
1359
|
+
|
|
1360
|
+
The count follows the allocation of the region trimmed kernel, the same
|
|
1361
|
+
count as ``nrelax_device_bytes`` in the solver's ``gpu_memory_nrelax.cuh``.
|
|
1362
|
+
Over the whole slab the card holds the pressure and one velocity for each
|
|
1363
|
+
axis at two time levels, ``kappa_x2``, ``rho``, ``K``, the two finite
|
|
1364
|
+
amplitude maps and ``dcmap``, and mechanism 1 of the pressure memory, its
|
|
1365
|
+
``a``, ``b`` and one memory variable for each axis. The mechanisms above
|
|
1366
|
+
the first hold the same over the interior box alone, and the momentum
|
|
1367
|
+
absorbing layer holds its ``a``, ``b`` and one memory variable for each
|
|
1368
|
+
axis over the band around the hole alone.
|
|
1342
1369
|
|
|
1343
1370
|
Parameters
|
|
1344
1371
|
----------
|
|
@@ -1347,7 +1374,7 @@ class Solver:
|
|
|
1347
1374
|
n_deriv_levels : int
|
|
1348
1375
|
Number of derivative-map levels.
|
|
1349
1376
|
n_sources : int
|
|
1350
|
-
|
|
1377
|
+
Source points this GPU holds, summed over every source kind.
|
|
1351
1378
|
n_source_timesteps : int
|
|
1352
1379
|
Number of source time steps.
|
|
1353
1380
|
save_gpu_memory : bool
|
|
@@ -1362,8 +1389,13 @@ class Solver:
|
|
|
1362
1389
|
Bytes per float (4).
|
|
1363
1390
|
int_bytes : int
|
|
1364
1391
|
Bytes per int (4).
|
|
1365
|
-
is_3d: bool
|
|
1366
|
-
Whether the simulation is 3D
|
|
1392
|
+
is_3d : bool
|
|
1393
|
+
Whether the simulation is 3D.
|
|
1394
|
+
band : int | None
|
|
1395
|
+
Grid points of the momentum layer band on this GPU. None takes the slab.
|
|
1396
|
+
interior : int | None
|
|
1397
|
+
Grid points of this GPU's share of the interior box of the mechanisms
|
|
1398
|
+
above the first. None takes the slab.
|
|
1367
1399
|
|
|
1368
1400
|
Returns
|
|
1369
1401
|
-------
|
|
@@ -1373,36 +1405,152 @@ class Solver:
|
|
|
1373
1405
|
"""
|
|
1374
1406
|
fb = float_bytes
|
|
1375
1407
|
ib = int_bytes
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
mem +=
|
|
1383
|
-
|
|
1384
|
-
mem +=
|
|
1385
|
-
|
|
1386
|
-
mem +=
|
|
1387
|
-
|
|
1388
|
-
mem += 2 * (2 * n_relax) * slab * fb
|
|
1389
|
-
# (dmap + dcmap)
|
|
1390
|
-
mem += 9 * 2 * n_deriv_levels * fb + slab * ib
|
|
1391
|
-
# source (icmat + coords)
|
|
1408
|
+
axes = 3 if is_3d else 2
|
|
1409
|
+
band = slab if band is None else band
|
|
1410
|
+
interior = slab if interior is None else interior
|
|
1411
|
+
per_mechanism = 2 + axes
|
|
1412
|
+
|
|
1413
|
+
mem = 2 * (axes + 1) * slab * fb
|
|
1414
|
+
mem += 5 * slab * fb
|
|
1415
|
+
mem += slab * ib
|
|
1416
|
+
mem += per_mechanism * slab * fb
|
|
1417
|
+
mem += per_mechanism * max(n_relax - 1, 0) * interior * fb
|
|
1418
|
+
mem += per_mechanism * band * fb
|
|
1419
|
+
mem += 9 * 2 * n_deriv_levels * fb
|
|
1392
1420
|
if n_sources > 0:
|
|
1393
|
-
|
|
1394
|
-
mem +=
|
|
1395
|
-
|
|
1396
|
-
# air
|
|
1421
|
+
samples = n_sources if save_gpu_memory else n_sources * n_source_timesteps
|
|
1422
|
+
mem += samples * fb + axes * n_sources * ib
|
|
1397
1423
|
if n_air > 0:
|
|
1398
|
-
mem +=
|
|
1399
|
-
# sensor
|
|
1424
|
+
mem += axes * n_air * ib
|
|
1400
1425
|
if n_sensors > 0:
|
|
1401
|
-
mem += n_sensors * fb
|
|
1402
|
-
mem += (ndim + 1) * n_sensors * ib
|
|
1403
|
-
mem += n_sensors * ib
|
|
1426
|
+
mem += n_sensors * (fb + (axes + 2) * ib)
|
|
1404
1427
|
return mem
|
|
1405
1428
|
|
|
1429
|
+
@staticmethod
|
|
1430
|
+
def _center_line_span(values: NDArray, axis: int, *, zeros: bool) -> tuple[int, int]:
|
|
1431
|
+
"""Return the first and one past the last index of a map's center line along one axis.
|
|
1432
|
+
|
|
1433
|
+
Parameters
|
|
1434
|
+
----------
|
|
1435
|
+
values : NDArray
|
|
1436
|
+
The map, on the host or on the GPU.
|
|
1437
|
+
axis : int
|
|
1438
|
+
The axis the line runs along. The other axes sit at their centers.
|
|
1439
|
+
zeros : bool
|
|
1440
|
+
True spans the zero cells, False the nonzero cells.
|
|
1441
|
+
|
|
1442
|
+
Returns
|
|
1443
|
+
-------
|
|
1444
|
+
tuple[int, int]
|
|
1445
|
+
The span, empty as ``(0, 0)`` when no cell matches.
|
|
1446
|
+
|
|
1447
|
+
"""
|
|
1448
|
+
index = tuple(
|
|
1449
|
+
slice(None) if a == axis else size // 2 for a, size in enumerate(values.shape)
|
|
1450
|
+
)
|
|
1451
|
+
line = values[index]
|
|
1452
|
+
line = line.get() if hasattr(line, "get") else np.asarray(line)
|
|
1453
|
+
found = np.flatnonzero(line == 0 if zeros else line != 0)
|
|
1454
|
+
if found.size == 0:
|
|
1455
|
+
return (0, 0)
|
|
1456
|
+
return (int(found[0]), int(found[-1]) + 1)
|
|
1457
|
+
|
|
1458
|
+
def _relaxation_regions(
|
|
1459
|
+
self,
|
|
1460
|
+
medium: fullwave.MediumRelaxationMaps,
|
|
1461
|
+
) -> tuple[list[tuple[int, int]] | None, list[tuple[int, int]] | None]:
|
|
1462
|
+
"""Return the interior box and the momentum layer hole the kernel will measure.
|
|
1463
|
+
|
|
1464
|
+
The kernel stores every mechanism above the first over the box where its
|
|
1465
|
+
``a`` is nonzero, and the momentum absorbing layer over the band around the
|
|
1466
|
+
box where the first momentum ``a`` is zero. Both are read here along the
|
|
1467
|
+
center lines of each axis, which is how the kernel finds the hole, and a
|
|
1468
|
+
clean box shape is assumed for both.
|
|
1469
|
+
|
|
1470
|
+
Parameters
|
|
1471
|
+
----------
|
|
1472
|
+
medium : fullwave.MediumRelaxationMaps
|
|
1473
|
+
The extended medium after the absorbing layer is built.
|
|
1474
|
+
|
|
1475
|
+
Returns
|
|
1476
|
+
-------
|
|
1477
|
+
tuple
|
|
1478
|
+
The box and the hole as one ``(start, end)`` span for each axis. None
|
|
1479
|
+
stands for a map the medium does not carry, which counts as the whole
|
|
1480
|
+
slab.
|
|
1481
|
+
|
|
1482
|
+
"""
|
|
1483
|
+
maps = medium.relaxation_param_dict_for_fw2
|
|
1484
|
+
box_maps = [maps.get(f"a_pml_u{nu}") for nu in range(2, self.n_relax_mechanisms + 1)]
|
|
1485
|
+
box_maps = [values for values in box_maps if values is not None]
|
|
1486
|
+
box = None
|
|
1487
|
+
if self.n_relax_mechanisms > 1 and len(box_maps) == self.n_relax_mechanisms - 1:
|
|
1488
|
+
box = []
|
|
1489
|
+
for axis in range(box_maps[0].ndim):
|
|
1490
|
+
spans = [self._center_line_span(values, axis, zeros=False) for values in box_maps]
|
|
1491
|
+
spans = [span for span in spans if span[1] > span[0]]
|
|
1492
|
+
box.append(
|
|
1493
|
+
(min(s for s, _ in spans), max(e for _, e in spans)) if spans else (0, 0)
|
|
1494
|
+
)
|
|
1495
|
+
hole = None
|
|
1496
|
+
if maps.get("a_pml_x1") is not None:
|
|
1497
|
+
values = maps["a_pml_x1"]
|
|
1498
|
+
hole = [self._center_line_span(values, axis, zeros=True) for axis in range(values.ndim)]
|
|
1499
|
+
if any(end <= start for start, end in hole):
|
|
1500
|
+
hole = [(0, 0)] * values.ndim
|
|
1501
|
+
return box, hole
|
|
1502
|
+
|
|
1503
|
+
@staticmethod
|
|
1504
|
+
def _band_and_interior(
|
|
1505
|
+
low: int,
|
|
1506
|
+
high: int,
|
|
1507
|
+
shape: tuple[int, ...],
|
|
1508
|
+
box: list[tuple[int, int]] | None,
|
|
1509
|
+
hole: list[tuple[int, int]] | None,
|
|
1510
|
+
) -> tuple[int, int]:
|
|
1511
|
+
"""Return one GPU's band and interior box cells, as the kernel counts them.
|
|
1512
|
+
|
|
1513
|
+
Parameters
|
|
1514
|
+
----------
|
|
1515
|
+
low : int
|
|
1516
|
+
The first grid row the GPU holds, its halo included.
|
|
1517
|
+
high : int
|
|
1518
|
+
One past the last grid row the GPU holds, its halo included.
|
|
1519
|
+
shape : tuple[int, ...]
|
|
1520
|
+
The extended grid shape.
|
|
1521
|
+
box : list[tuple[int, int]] | None
|
|
1522
|
+
The interior box, one span for each axis, or None for the whole slab.
|
|
1523
|
+
hole : list[tuple[int, int]] | None
|
|
1524
|
+
The momentum layer hole, one span for each axis, or None for the whole slab.
|
|
1525
|
+
|
|
1526
|
+
Returns
|
|
1527
|
+
-------
|
|
1528
|
+
tuple[int, int]
|
|
1529
|
+
The band cells and the interior cells of this GPU.
|
|
1530
|
+
|
|
1531
|
+
"""
|
|
1532
|
+
rows = high - low
|
|
1533
|
+
lateral = int(np.prod(shape[1:]))
|
|
1534
|
+
if box is None:
|
|
1535
|
+
interior = rows * lateral
|
|
1536
|
+
else:
|
|
1537
|
+
box_rows = max(0, min(high, box[0][1]) - max(low, box[0][0]))
|
|
1538
|
+
interior = box_rows * int(np.prod([end - start for start, end in box[1:]]))
|
|
1539
|
+
if hole is None:
|
|
1540
|
+
return rows * lateral, interior
|
|
1541
|
+
hole_low = min(max(hole[0][0] - low, 0), rows)
|
|
1542
|
+
hole_high = max(min(max(hole[0][1] - low, 0), rows), hole_low)
|
|
1543
|
+
hole_rows = hole_high - hole_low
|
|
1544
|
+
band = (rows - hole_rows) * lateral
|
|
1545
|
+
hole_columns = hole[1][1] - hole[1][0]
|
|
1546
|
+
strip_columns = shape[1] - hole_columns
|
|
1547
|
+
if len(shape) == 3:
|
|
1548
|
+
strip_depths = shape[2] - (hole[2][1] - hole[2][0])
|
|
1549
|
+
band += hole_rows * (strip_columns * shape[2] + hole_columns * strip_depths)
|
|
1550
|
+
else:
|
|
1551
|
+
band += hole_rows * strip_columns
|
|
1552
|
+
return band, interior
|
|
1553
|
+
|
|
1406
1554
|
def print_info(self) -> None:
|
|
1407
1555
|
"""Print the Solver instance information."""
|
|
1408
1556
|
print(str(self))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: fullwave25
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.2.dev1
|
|
4
4
|
Summary: Fullwave 2.5: Ultrasound wave propagation simulation with heterogeneous power law attenuation modelling capabilities
|
|
5
5
|
Author: Masashi Sode, Gianmarco Pinton
|
|
6
6
|
Maintainer: Masashi Sode
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
fullwave/__init__.py,sha256
|
|
1
|
+
fullwave/__init__.py,sha256=NH2N7h95BRQQeaDSq2WKJweRYAIykaSH3leGkwbn1zc,2382
|
|
2
2
|
fullwave/grid.py,sha256=YbxAAgdYKR8AXwobtTZzHm9C4KR4D5--51zgbs0aQGY,7435
|
|
3
3
|
fullwave/medium.py,sha256=Tz8Cwda6zLF8UFxjWFkRcAdko_KmF4l1zfmjWaqxu-M,68626
|
|
4
4
|
fullwave/sensor.py,sha256=McHyaSKxM11_Kfb_2hfnOtV9Z1UMBCLkeovncLT8_bA,9308
|
|
@@ -21,13 +21,13 @@ fullwave/medium_builder/presets/domain_water_gel.py,sha256=nFiL0CkmDeJWo7aR2Khn0
|
|
|
21
21
|
fullwave/medium_builder/presets/data/.keep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
22
|
fullwave/medium_builder/presets/data/abdominal_wall/i2365f_etfw1.mat,sha256=N3JFFxc9HW1S-NaTPcPlFgXWGIzlrr9X40JbDapTo4g,67348
|
|
23
23
|
fullwave/solver/__init__.py,sha256=E0Jg5akBpicqTjku1puw9rAIoKiw7TwtYNDPiv8G5IY,30
|
|
24
|
-
fullwave/solver/binary_manager.py,sha256=
|
|
24
|
+
fullwave/solver/binary_manager.py,sha256=jMiXkKcXVBFtAhxguR-XMEsg-5emrI2WAGhslFqhpGo,5041
|
|
25
25
|
fullwave/solver/cuda_utils.py,sha256=n7p3TJYbLAXmIzSMS5Q_8m4OWg5U9VG5_3hAxa0uTYI,11407
|
|
26
26
|
fullwave/solver/input_file_writer.py,sha256=JamQHuA3-YrdLpdMFT6Ymw7noiCrtMr-DNo6LFxCvmM,57993
|
|
27
27
|
fullwave/solver/launcher.py,sha256=zh-3HY4iKGmjreALu9WczDpWX3d74nOcIns9xVvnUIg,10531
|
|
28
28
|
fullwave/solver/pml_builder.py,sha256=Pfy3AklZT-p6TX61A5ntFmpt2mJb5TDaV-gdtpjIwNo,87341
|
|
29
29
|
fullwave/solver/shipped_database.py,sha256=lPqlgY-ShDyRqtH65m5RyNIMVlqswECVDNh5XCk1Yzg,3194
|
|
30
|
-
fullwave/solver/solver.py,sha256=
|
|
30
|
+
fullwave/solver/solver.py,sha256=oQOrL-9YSi5C9vP6rOyfZW8soTHnWBLusi1rMIwI978,65346
|
|
31
31
|
fullwave/solver/source_type.py,sha256=li4-4tpu4bd1i9DqyDXZKOhkzW4IV6OcxB97C13c5MU,11180
|
|
32
32
|
fullwave/solver/utils.py,sha256=0Q9PKl-4hohWXGzuldqo2XubI-LEHMjs0kYgb4oTLC0,5561
|
|
33
33
|
fullwave/solver/bins/_gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda118,sha256=bIzyHFzr_bsIBSlCcRA3M9LlTSRrBVn6ASJHyozvcwU,1245432
|
|
@@ -53,7 +53,7 @@ fullwave/utils/relaxation_parameters.py,sha256=wHUNMtJGAJwgCyUYd24_qtQZflMnkQTYh
|
|
|
53
53
|
fullwave/utils/scatterer.py,sha256=CLqD085f9pqX4cF1YiT2IkzT5P0o1xp45Do7lf5BLnM,24049
|
|
54
54
|
fullwave/utils/signal_filter.py,sha256=_Tf42aBygGtIUrcSPybYqvZoAW2o_4dd-hHTEvZ8--E,5219
|
|
55
55
|
fullwave/utils/signal_process.py,sha256=MP38r37JSPHN4sT-lIReXS5BT2GT_tkRxD0Y1wQ-lNs,5153
|
|
56
|
-
fullwave25-1.3.
|
|
57
|
-
fullwave25-1.3.
|
|
58
|
-
fullwave25-1.3.
|
|
59
|
-
fullwave25-1.3.
|
|
56
|
+
fullwave25-1.3.2.dev1.dist-info/METADATA,sha256=AsODJVy-vpzXYnlKv0DELscEsdv7s1JYyzXYNbdbU-A,21747
|
|
57
|
+
fullwave25-1.3.2.dev1.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
58
|
+
fullwave25-1.3.2.dev1.dist-info/licenses/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
|
|
59
|
+
fullwave25-1.3.2.dev1.dist-info/RECORD,,
|
|
File without changes
|