cardiac-geometriesx 0.3.1__py3-none-any.whl → 0.4.0__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.

Potentially problematic release.


This version of cardiac-geometriesx might be problematic. Click here for more details.

@@ -1,3 +1,4 @@
1
+ import json
1
2
  from pathlib import Path
2
3
  from typing import NamedTuple, Sequence
3
4
 
@@ -19,16 +20,21 @@ class Microstructure(NamedTuple):
19
20
  def save_microstructure(
20
21
  mesh: dolfinx.mesh.Mesh, functions: Sequence[dolfinx.fem.Function], outdir: str | Path
21
22
  ) -> None:
22
- from ..utils import element2array
23
+ from ..utils import create_xdmf_pointcloud, element2array
23
24
 
25
+ if len(functions) == 0:
26
+ return
24
27
  # Save for paraview visualization
25
- try:
26
- with dolfinx.io.VTXWriter(
27
- mesh.comm, Path(outdir) / "microstructure-viz.bp", functions, engine="BP4"
28
- ) as file:
29
- file.write(0.0)
30
- except RuntimeError:
31
- pass
28
+ if functions[0].function_space.ufl_element().family_name == "quadrature":
29
+ create_xdmf_pointcloud(us=functions, filename=Path(outdir) / "microstructure-viz.xdmf")
30
+ else:
31
+ try:
32
+ with dolfinx.io.VTXWriter(
33
+ mesh.comm, Path(outdir) / "microstructure-viz.bp", functions, engine="BP4"
34
+ ) as file:
35
+ file.write(0.0)
36
+ except RuntimeError:
37
+ pass
32
38
 
33
39
  # Save with proper function space
34
40
  filename = Path(outdir) / "microstructure.bp"
@@ -43,6 +49,16 @@ def save_microstructure(
43
49
  attributes=attributes,
44
50
  )
45
51
 
52
+ def json_serial(obj):
53
+ if isinstance(obj, (np.ndarray)):
54
+ return obj.tolist()
55
+ raise TypeError("Type %s not serializable" % type(obj))
56
+
57
+ if mesh.comm.rank == 0:
58
+ (Path(outdir) / "microstructure.json").write_text(
59
+ json.dumps(attributes, indent=4, default=json_serial)
60
+ )
61
+
46
62
 
47
63
  def normalize(u):
48
64
  return u / np.linalg.norm(u, axis=0)
@@ -147,13 +147,22 @@ class Geometry:
147
147
  else:
148
148
  markers = {}
149
149
 
150
+ if (folder / "microstructure.json").exists():
151
+ if comm.rank == 0:
152
+ microstructure = json.loads((folder / "microstructure.json").read_text())
153
+ else:
154
+ microstructure = {}
155
+ microstructure = comm.bcast(microstructure, root=0)
156
+ else:
157
+ microstructure = {}
158
+
150
159
  functions = {}
151
160
  microstructure_path = folder / "microstructure.bp"
152
161
  if microstructure_path.exists():
153
- function_space = adios4dolfinx.read_attributes(
154
- comm=MPI.COMM_WORLD, filename=microstructure_path, name="function_space"
155
- )
156
- for name, el in function_space.items():
162
+ # function_space = adios4dolfinx.read_attributes(
163
+ # comm=MPI.COMM_WORLD, filename=microstructure_path, name="function_space"
164
+ # )
165
+ for name, el in microstructure.items():
157
166
  element = utils.array2element(el)
158
167
  V = dolfinx.fem.functionspace(mesh, element)
159
168
  f = dolfinx.fem.Function(V, name=name)
@@ -1,5 +1,6 @@
1
1
  import tempfile
2
2
  import typing
3
+ import xml.etree.ElementTree as ET
3
4
  from enum import Enum
4
5
  from pathlib import Path
5
6
  from typing import Iterable, NamedTuple
@@ -25,6 +26,23 @@ class GMshModel(NamedTuple):
25
26
  vertex_tags: dolfinx.mesh.MeshTags
26
27
 
27
28
 
29
+ def distribute_entity_data(
30
+ mesh: dolfinx.mesh.Mesh,
31
+ tdim: int,
32
+ marked_entities: np.ndarray,
33
+ entity_values: np.ndarray,
34
+ ) -> tuple[np.ndarray, np.ndarray]:
35
+ if dolfinx.__version__ >= "0.9.0":
36
+ local_entities, local_values = dolfinx.io.utils.distribute_entity_data(
37
+ mesh, tdim, marked_entities, entity_values
38
+ )
39
+ else:
40
+ local_entities, local_values = dolfinx.io.utils.distribute_entity_data(
41
+ mesh._cpp_object, tdim, marked_entities, entity_values
42
+ )
43
+ return local_entities, local_values
44
+
45
+
28
46
  # copied from https://github.com/FEniCS/dolfinx/blob/main/python/dolfinx/io/gmshio.py
29
47
  def model_to_mesh(
30
48
  model,
@@ -160,9 +178,10 @@ def model_to_mesh(
160
178
  )
161
179
 
162
180
  # Create MeshTags for cells
163
- local_entities, local_values = dolfinx.io.utils.distribute_entity_data(
164
- mesh._cpp_object, mesh.topology.dim, cells, cell_values
181
+ local_entities, local_values = distribute_entity_data(
182
+ mesh, mesh.topology.dim, cells, cell_values
165
183
  )
184
+
166
185
  mesh.topology.create_connectivity(mesh.topology.dim, 0)
167
186
  adj = dolfinx.cpp.graph.AdjacencyList_int32(local_entities)
168
187
  ct = dolfinx.mesh.meshtags_from_entities(
@@ -188,11 +207,13 @@ def model_to_mesh(
188
207
  gmsh_facet_perm = dolfinx.io.gmshio.cell_perm_array(facet_type, num_facet_nodes)
189
208
  marked_facets = marked_facets[:, gmsh_facet_perm]
190
209
 
191
- local_entities, local_values = dolfinx.io.utils.distribute_entity_data(
192
- mesh._cpp_object, tdim - 1, marked_facets, facet_values
210
+ local_entities, local_values = distribute_entity_data(
211
+ mesh, mesh.topology.dim - 1, marked_facets, facet_values
193
212
  )
213
+
194
214
  mesh.topology.create_connectivity(topology.dim - 1, tdim)
195
215
  adj = dolfinx.cpp.graph.AdjacencyList_int32(local_entities)
216
+
196
217
  ft = dolfinx.io.gmshio.meshtags_from_entities(
197
218
  mesh, tdim - 1, adj, local_values.astype(np.int32, copy=False)
198
219
  )
@@ -210,8 +231,8 @@ def model_to_mesh(
210
231
  gmsh_edge_perm = dolfinx.io.gmshio.cell_perm_array(edge_type, num_edge_nodes)
211
232
  marked_edges = marked_edges[:, gmsh_edge_perm]
212
233
 
213
- local_entities, local_values = dolfinx.io.utils.distribute_entity_data(
214
- mesh._cpp_object, tdim - 2, marked_edges, edge_values
234
+ local_entities, local_values = distribute_entity_data(
235
+ mesh, tdim - 2, marked_edges, edge_values
215
236
  )
216
237
  mesh.topology.create_connectivity(topology.dim - 2, tdim)
217
238
  adj = dolfinx.cpp.graph.AdjacencyList_int32(local_entities)
@@ -232,8 +253,8 @@ def model_to_mesh(
232
253
  gmsh_vertex_perm = dolfinx.io.gmshio.cell_perm_array(vertex_type, num_vertex_nodes)
233
254
  marked_vertices = marked_vertices[:, gmsh_vertex_perm]
234
255
 
235
- local_entities, local_values = dolfinx.io.utils.distribute_entity_data(
236
- mesh._cpp_object, tdim - 3, marked_vertices, vertex_values
256
+ local_entities, local_values = distribute_entity_data(
257
+ mesh, tdim - 3, marked_vertices, vertex_values
237
258
  )
238
259
  mesh.topology.create_connectivity(topology.dim - 3, tdim)
239
260
  adj = dolfinx.cpp.graph.AdjacencyList_int32(local_entities)
@@ -340,6 +361,7 @@ def array2element(arr: np.ndarray) -> basix.finite_element.FiniteElement:
340
361
  degree=degree,
341
362
  discontinuous=discontinuous,
342
363
  shape=(3,),
364
+ lagrange_variant=basix.LagrangeVariant.unset,
343
365
  )
344
366
 
345
367
 
@@ -438,3 +460,88 @@ def gmsh2dolfin(comm: MPI.Intracomm, msh_file, rank: int = 0) -> GMshGeometry:
438
460
  )
439
461
 
440
462
  return GMshGeometry(mesh, ct, ft, et, vt, markers)
463
+
464
+
465
+ def create_xdmf_pointcloud(filename: Path, us: typing.Sequence[dolfinx.fem.Function]) -> None:
466
+ # Adopted from https://gist.github.com/jorgensd/8bae61ad7a0c211570dff0116a68a356
467
+ if len(us) == 0:
468
+ return
469
+
470
+ import adios2
471
+
472
+ u = us[0]
473
+ points = u.function_space.tabulate_dof_coordinates()
474
+ h5name = filename.with_suffix(".h5")
475
+
476
+ bs = u.function_space.dofmap.index_map_bs
477
+ comm = u.function_space.mesh.comm
478
+ num_dofs_global = u.function_space.dofmap.index_map.size_global
479
+ num_dofs_local = u.function_space.dofmap.index_map.size_local
480
+ local_range = np.array(u.function_space.dofmap.index_map.local_range, dtype=np.int64)
481
+
482
+ # Write XDMF on rank 0
483
+ if comm.rank == 0:
484
+ xdmf = ET.Element("XDMF")
485
+ xdmf.attrib["Version"] = "3.0"
486
+ xdmf.attrib["xmlns:xi"] = "http://www.w3.org/2001/XInclude"
487
+ domain = ET.SubElement(xdmf, "Domain")
488
+ grid = ET.SubElement(domain, "Grid")
489
+ grid.attrib["GridType"] = "Uniform"
490
+ grid.attrib["Name"] = "Point Cloud"
491
+ topology = ET.SubElement(grid, "Topology")
492
+ topology.attrib["NumberOfElements"] = str(num_dofs_global)
493
+ topology.attrib["TopologyType"] = "PolyVertex"
494
+ topology.attrib["NodesPerElement"] = "1"
495
+ geometry = ET.SubElement(grid, "Geometry")
496
+ geometry.attrib["GeometryType"] = "XY" if points.shape[1] == 2 else "XYZ"
497
+ for u in us:
498
+ it0 = ET.SubElement(geometry, "DataItem")
499
+ it0.attrib["Dimensions"] = f"{num_dofs_global} {points.shape[1]}"
500
+ it0.attrib["Format"] = "HDF"
501
+ it0.text = f"{h5name.name}:/Step0/Points"
502
+ attrib = ET.SubElement(grid, "Attribute")
503
+ attrib.attrib["Name"] = u.name
504
+ if bs == 1:
505
+ attrib.attrib["AttributeType"] = "Scalar"
506
+ else:
507
+ attrib.attrib["AttributeType"] = "Vector"
508
+ attrib.attrib["Center"] = "Node"
509
+ it1 = ET.SubElement(attrib, "DataItem")
510
+ it1.attrib["Dimensions"] = f"{num_dofs_global} {bs}"
511
+ it1.attrib["Format"] = "HDF"
512
+ it1.text = f"{h5name.name}:/Step0/Values_{u.name}"
513
+ text = [
514
+ '<?xml version="1.0"?>\n<!DOCTYPE Xdmf SYSTEM "Xdmf.dtd" []>\n',
515
+ ET.tostring(xdmf, encoding="unicode"),
516
+ ]
517
+ filename.write_text("".join(text))
518
+ # Create ADIOS2 reader
519
+ # start = time.perf_counter()
520
+ adios = adios2.ADIOS(comm)
521
+ io = adios.DeclareIO("Point cloud writer")
522
+ io.SetEngine("HDF5")
523
+ outfile = io.Open(h5name.as_posix(), adios2.Mode.Write)
524
+ points_out = points[:num_dofs_local, :]
525
+
526
+ pointvar = io.DefineVariable(
527
+ "Points",
528
+ points_out,
529
+ shape=[num_dofs_global, points.shape[1]],
530
+ start=[local_range[0], 0],
531
+ count=[num_dofs_local, points.shape[1]],
532
+ )
533
+ outfile.Put(pointvar, points_out)
534
+ for u in us:
535
+ data = u.x.array[: num_dofs_local * bs].reshape(-1, bs)
536
+
537
+ valuevar = io.DefineVariable(
538
+ f"Values_{u.name}",
539
+ data,
540
+ shape=[num_dofs_global, bs],
541
+ start=[local_range[0], 0],
542
+ count=[num_dofs_local, bs],
543
+ )
544
+ outfile.Put(valuevar, data)
545
+ outfile.PerformPuts()
546
+ outfile.Close()
547
+ assert adios.RemoveIO("Point cloud writer")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cardiac-geometriesx
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: A python library for cardiac geometries
5
5
  Author-email: Henrik Finsberg <henriknf@simula.no>
6
6
  License: MIT
@@ -1,16 +1,16 @@
1
1
  cardiac_geometries/__init__.py,sha256=2W_ywAeLjyRk5MqSPAodHa4UN2lOnW1h8tmGLQ3gaJ0,150
2
2
  cardiac_geometries/cli.py,sha256=GKcsMNhVFoxWDr-o3jiDCXmTvPgCSEB9Kws8AvYIK4Q,19678
3
- cardiac_geometries/geometry.py,sha256=iK8lydZEqU3sz0983yucW9IzQ2VqSXSy4D5ubdl9bOs,5636
3
+ cardiac_geometries/geometry.py,sha256=s-1BIDKvP9M3uu3Sl8JpGRnTnXZAa9Aq3FfpIIEAxhY,5982
4
4
  cardiac_geometries/gui.py,sha256=9WYR850wLrqsUrVUC37E2SaO0OWA_oagSe-YNrsxz3k,8376
5
5
  cardiac_geometries/mesh.py,sha256=Ejciny48mnKKN20RrY9DwLY7_Lh1jb6Kldj4CW1wr1o,26909
6
- cardiac_geometries/utils.py,sha256=EwEXAuB4XiJaqlZaGZ1cc6sIBSPJLCx-43As1NUcJrA,16488
6
+ cardiac_geometries/utils.py,sha256=fMHlVzwxnk1lJd8XQPy8dgFB9C9ecSnJB2NzMXJGAAQ,20348
7
7
  cardiac_geometries/fibers/__init__.py,sha256=WpRrn9Iakl-3m8IGtFkqP0LXGjw5EZHZ8Eg9JCnCdrg,137
8
8
  cardiac_geometries/fibers/lv_ellipsoid.py,sha256=KuWnx9yZ5KDyoeoYyDnXLZYb82DRiNveZyNIboD3uJ8,5768
9
9
  cardiac_geometries/fibers/slab.py,sha256=5tMvOSqXQ4_nbdUUtho_tQjDrmICxZfN7SXNq4FKdlY,3836
10
- cardiac_geometries/fibers/utils.py,sha256=j1ERqXcdaWCwO2yjbYGlgTt2G1DxZCVzbNHuDhh_QrM,2541
11
- cardiac_geometriesx-0.3.1.dist-info/LICENSE,sha256=lo5K2rJPZOSv6luutGHbzzi3IpXNaB9E2UWq60qvNx0,1111
12
- cardiac_geometriesx-0.3.1.dist-info/METADATA,sha256=maN2Wb_hCkroXXzBdl-_UX0BxQW9jvNAQkqb38YAb40,4163
13
- cardiac_geometriesx-0.3.1.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
14
- cardiac_geometriesx-0.3.1.dist-info/entry_points.txt,sha256=xOBnlc6W-H9oCDYLNz3kpki26OmpfYSoFSrmi_4V-Ec,52
15
- cardiac_geometriesx-0.3.1.dist-info/top_level.txt,sha256=J0gQxkWR2my5Vf7Qt8buDY8ZOjYdVfIweVunCGXWKNE,19
16
- cardiac_geometriesx-0.3.1.dist-info/RECORD,,
10
+ cardiac_geometries/fibers/utils.py,sha256=x6MNtW6xN5NBGBD0Ubm4eqTDde0j_Vd-nh8agFT_AiU,3161
11
+ cardiac_geometriesx-0.4.0.dist-info/LICENSE,sha256=lo5K2rJPZOSv6luutGHbzzi3IpXNaB9E2UWq60qvNx0,1111
12
+ cardiac_geometriesx-0.4.0.dist-info/METADATA,sha256=rPU1WjGfdSGrlkgnkhIubCY3WzJ7nlMGsLfcuNdU2ME,4163
13
+ cardiac_geometriesx-0.4.0.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
14
+ cardiac_geometriesx-0.4.0.dist-info/entry_points.txt,sha256=xOBnlc6W-H9oCDYLNz3kpki26OmpfYSoFSrmi_4V-Ec,52
15
+ cardiac_geometriesx-0.4.0.dist-info/top_level.txt,sha256=J0gQxkWR2my5Vf7Qt8buDY8ZOjYdVfIweVunCGXWKNE,19
16
+ cardiac_geometriesx-0.4.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (74.1.2)
2
+ Generator: setuptools (75.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5