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

@@ -159,7 +159,10 @@ def compute_system(
159
159
  s0 = utils.normalize(s0)
160
160
 
161
161
  Vv = space_from_string(
162
- space_string=f"{element.family_name}_{element.degree}", mesh=mesh, dim=mesh.geometry.dim
162
+ space_string=f"{element.family_name}_{element.degree}",
163
+ mesh=mesh,
164
+ dim=mesh.geometry.dim,
165
+ discontinuous=element.discontinuous,
163
166
  )
164
167
 
165
168
  fiber = dolfinx.fem.Function(Vv)
@@ -60,7 +60,10 @@ def compute_system(
60
60
  n0 = utils.normalize(n0)
61
61
 
62
62
  Vv = space_from_string(
63
- space_string=f"{element.family_name}_{element.degree}", mesh=mesh, dim=mesh.geometry.dim
63
+ space_string=f"{element.family_name}_{element.degree}",
64
+ mesh=mesh,
65
+ dim=mesh.geometry.dim,
66
+ discontinuous=element.discontinuous,
64
67
  )
65
68
 
66
69
  fiber = dolfinx.fem.Function(Vv)
@@ -1,3 +1,4 @@
1
+ import json
1
2
  from pathlib import Path
2
3
  from typing import NamedTuple, Sequence
3
4
 
@@ -21,14 +22,21 @@ def save_microstructure(
21
22
  ) -> None:
22
23
  from ..utils import 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
+ from scifem.xdmf import create_pointcloud
30
+
31
+ create_pointcloud(functions=functions, filename=Path(outdir) / "microstructure-viz.xdmf")
32
+ else:
33
+ try:
34
+ with dolfinx.io.VTXWriter(
35
+ mesh.comm, Path(outdir) / "microstructure-viz.bp", functions, engine="BP4"
36
+ ) as file:
37
+ file.write(0.0)
38
+ except RuntimeError:
39
+ pass
32
40
 
33
41
  # Save with proper function space
34
42
  filename = Path(outdir) / "microstructure.bp"
@@ -43,6 +51,16 @@ def save_microstructure(
43
51
  attributes=attributes,
44
52
  )
45
53
 
54
+ def json_serial(obj):
55
+ if isinstance(obj, (np.ndarray)):
56
+ return obj.tolist()
57
+ raise TypeError("Type %s not serializable" % type(obj))
58
+
59
+ if mesh.comm.rank == 0:
60
+ (Path(outdir) / "microstructure.json").write_text(
61
+ json.dumps(attributes, indent=4, default=json_serial)
62
+ )
63
+
46
64
 
47
65
  def normalize(u):
48
66
  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)
@@ -249,7 +270,9 @@ def model_to_mesh(
249
270
  return GMshModel(mesh, ct, ft, et, vt)
250
271
 
251
272
 
252
- def parse_element(space_string: str, mesh: dolfinx.mesh.Mesh, dim: int) -> basix.ufl._ElementBase:
273
+ def parse_element(
274
+ space_string: str, mesh: dolfinx.mesh.Mesh, dim: int, discontinuous: bool = False
275
+ ) -> basix.ufl._ElementBase:
253
276
  """
254
277
  Parse a string representation of a basix element family
255
278
  """
@@ -262,8 +285,9 @@ def parse_element(space_string: str, mesh: dolfinx.mesh.Mesh, dim: int) -> basix
262
285
  else:
263
286
  kwargs["shape"] = (dim,)
264
287
 
288
+ # breakpoint()
265
289
  if family_str in ["Lagrange", "P", "CG"]:
266
- el = basix.ufl.element(family=basix.ElementFamily.P, discontinuous=False, **kwargs)
290
+ el = basix.ufl.element(family=basix.ElementFamily.P, discontinuous=discontinuous, **kwargs)
267
291
  elif family_str in ["Discontinuous Lagrange", "DG", "dP"]:
268
292
  el = basix.ufl.element(family=basix.ElementFamily.P, discontinuous=True, **kwargs)
269
293
 
@@ -277,7 +301,7 @@ def parse_element(space_string: str, mesh: dolfinx.mesh.Mesh, dim: int) -> basix
277
301
 
278
302
 
279
303
  def space_from_string(
280
- space_string: str, mesh: dolfinx.mesh.Mesh, dim: int
304
+ space_string: str, mesh: dolfinx.mesh.Mesh, dim: int, discontinuous: bool = False
281
305
  ) -> dolfinx.fem.functionspace:
282
306
  """
283
307
  Constructed a finite elements space from a string
@@ -292,8 +316,10 @@ def space_from_string(
292
316
  The mesh
293
317
  dim : int
294
318
  1 for scalar space, 3 for vector space.
319
+ discontinuous: bool
320
+ If true force element to be discontinuous, by default False
295
321
  """
296
- el = parse_element(space_string, mesh, dim)
322
+ el = parse_element(space_string, mesh, dim, discontinuous=discontinuous)
297
323
  return dolfinx.fem.functionspace(mesh, el)
298
324
 
299
325
 
@@ -340,6 +366,7 @@ def array2element(arr: np.ndarray) -> basix.finite_element.FiniteElement:
340
366
  degree=degree,
341
367
  discontinuous=discontinuous,
342
368
  shape=(3,),
369
+ lagrange_variant=basix.LagrangeVariant.unset,
343
370
  )
344
371
 
345
372
 
@@ -438,3 +465,88 @@ def gmsh2dolfin(comm: MPI.Intracomm, msh_file, rank: int = 0) -> GMshGeometry:
438
465
  )
439
466
 
440
467
  return GMshGeometry(mesh, ct, ft, et, vt, markers)
468
+
469
+
470
+ def create_xdmf_pointcloud(filename: Path, us: typing.Sequence[dolfinx.fem.Function]) -> None:
471
+ # Adopted from https://gist.github.com/jorgensd/8bae61ad7a0c211570dff0116a68a356
472
+ if len(us) == 0:
473
+ return
474
+
475
+ import adios2
476
+
477
+ u = us[0]
478
+ points = u.function_space.tabulate_dof_coordinates()
479
+ h5name = filename.with_suffix(".h5")
480
+
481
+ bs = u.function_space.dofmap.index_map_bs
482
+ comm = u.function_space.mesh.comm
483
+ num_dofs_global = u.function_space.dofmap.index_map.size_global
484
+ num_dofs_local = u.function_space.dofmap.index_map.size_local
485
+ local_range = np.array(u.function_space.dofmap.index_map.local_range, dtype=np.int64)
486
+
487
+ # Write XDMF on rank 0
488
+ if comm.rank == 0:
489
+ xdmf = ET.Element("XDMF")
490
+ xdmf.attrib["Version"] = "3.0"
491
+ xdmf.attrib["xmlns:xi"] = "http://www.w3.org/2001/XInclude"
492
+ domain = ET.SubElement(xdmf, "Domain")
493
+ grid = ET.SubElement(domain, "Grid")
494
+ grid.attrib["GridType"] = "Uniform"
495
+ grid.attrib["Name"] = "Point Cloud"
496
+ topology = ET.SubElement(grid, "Topology")
497
+ topology.attrib["NumberOfElements"] = str(num_dofs_global)
498
+ topology.attrib["TopologyType"] = "PolyVertex"
499
+ topology.attrib["NodesPerElement"] = "1"
500
+ geometry = ET.SubElement(grid, "Geometry")
501
+ geometry.attrib["GeometryType"] = "XY" if points.shape[1] == 2 else "XYZ"
502
+ for u in us:
503
+ it0 = ET.SubElement(geometry, "DataItem")
504
+ it0.attrib["Dimensions"] = f"{num_dofs_global} {points.shape[1]}"
505
+ it0.attrib["Format"] = "HDF"
506
+ it0.text = f"{h5name.name}:/Step0/Points"
507
+ attrib = ET.SubElement(grid, "Attribute")
508
+ attrib.attrib["Name"] = u.name
509
+ if bs == 1:
510
+ attrib.attrib["AttributeType"] = "Scalar"
511
+ else:
512
+ attrib.attrib["AttributeType"] = "Vector"
513
+ attrib.attrib["Center"] = "Node"
514
+ it1 = ET.SubElement(attrib, "DataItem")
515
+ it1.attrib["Dimensions"] = f"{num_dofs_global} {bs}"
516
+ it1.attrib["Format"] = "HDF"
517
+ it1.text = f"{h5name.name}:/Step0/Values_{u.name}"
518
+ text = [
519
+ '<?xml version="1.0"?>\n<!DOCTYPE Xdmf SYSTEM "Xdmf.dtd" []>\n',
520
+ ET.tostring(xdmf, encoding="unicode"),
521
+ ]
522
+ filename.write_text("".join(text))
523
+ # Create ADIOS2 reader
524
+ # start = time.perf_counter()
525
+ adios = adios2.ADIOS(comm)
526
+ io = adios.DeclareIO("Point cloud writer")
527
+ io.SetEngine("HDF5")
528
+ outfile = io.Open(h5name.as_posix(), adios2.Mode.Write)
529
+ points_out = points[:num_dofs_local, :]
530
+
531
+ pointvar = io.DefineVariable(
532
+ "Points",
533
+ points_out,
534
+ shape=[num_dofs_global, points.shape[1]],
535
+ start=[local_range[0], 0],
536
+ count=[num_dofs_local, points.shape[1]],
537
+ )
538
+ outfile.Put(pointvar, points_out)
539
+ for u in us:
540
+ data = u.x.array[: num_dofs_local * bs].reshape(-1, bs)
541
+
542
+ valuevar = io.DefineVariable(
543
+ f"Values_{u.name}",
544
+ data,
545
+ shape=[num_dofs_global, bs],
546
+ start=[local_range[0], 0],
547
+ count=[num_dofs_local, bs],
548
+ )
549
+ outfile.Put(valuevar, data)
550
+ outfile.PerformPuts()
551
+ outfile.Close()
552
+ 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.1
4
4
  Summary: A python library for cardiac geometries
5
5
  Author-email: Henrik Finsberg <henriknf@simula.no>
6
6
  License: MIT
@@ -17,6 +17,7 @@ Requires-Dist: structlog
17
17
  Requires-Dist: cardiac-geometries-core
18
18
  Requires-Dist: rich-click
19
19
  Requires-Dist: adios4dolfinx
20
+ Requires-Dist: scifem
20
21
  Provides-Extra: dev
21
22
  Requires-Dist: bump-my-version ; extra == 'dev'
22
23
  Requires-Dist: ipython ; extra == 'dev'
@@ -0,0 +1,16 @@
1
+ cardiac_geometries/__init__.py,sha256=2W_ywAeLjyRk5MqSPAodHa4UN2lOnW1h8tmGLQ3gaJ0,150
2
+ cardiac_geometries/cli.py,sha256=GKcsMNhVFoxWDr-o3jiDCXmTvPgCSEB9Kws8AvYIK4Q,19678
3
+ cardiac_geometries/geometry.py,sha256=s-1BIDKvP9M3uu3Sl8JpGRnTnXZAa9Aq3FfpIIEAxhY,5982
4
+ cardiac_geometries/gui.py,sha256=9WYR850wLrqsUrVUC37E2SaO0OWA_oagSe-YNrsxz3k,8376
5
+ cardiac_geometries/mesh.py,sha256=Ejciny48mnKKN20RrY9DwLY7_Lh1jb6Kldj4CW1wr1o,26909
6
+ cardiac_geometries/utils.py,sha256=8QKkdK3JFZMH3qF4PzvEVfk7vMB5Ciui-KFIct2Kd2g,20560
7
+ cardiac_geometries/fibers/__init__.py,sha256=WpRrn9Iakl-3m8IGtFkqP0LXGjw5EZHZ8Eg9JCnCdrg,137
8
+ cardiac_geometries/fibers/lv_ellipsoid.py,sha256=nJYkwvacH1xMhuWAV06NRR4fFzyprowfWv4UIQkCPQM,5830
9
+ cardiac_geometries/fibers/slab.py,sha256=TYQhckJ8mwXz_08Cx3QsPQMtemkaxZ955SnSMrDfBPE,3898
10
+ cardiac_geometries/fibers/utils.py,sha256=rOGWyJTRQ7M1W5_JBOIuVPw5LGBVB0u_LGxBicfc--w,3190
11
+ cardiac_geometriesx-0.4.1.dist-info/LICENSE,sha256=lo5K2rJPZOSv6luutGHbzzi3IpXNaB9E2UWq60qvNx0,1111
12
+ cardiac_geometriesx-0.4.1.dist-info/METADATA,sha256=zbG7thVfZ1t_0dusLr0y8-YhOfo4pUNBD9POw9Ge2Q0,4185
13
+ cardiac_geometriesx-0.4.1.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
14
+ cardiac_geometriesx-0.4.1.dist-info/entry_points.txt,sha256=xOBnlc6W-H9oCDYLNz3kpki26OmpfYSoFSrmi_4V-Ec,52
15
+ cardiac_geometriesx-0.4.1.dist-info/top_level.txt,sha256=J0gQxkWR2my5Vf7Qt8buDY8ZOjYdVfIweVunCGXWKNE,19
16
+ cardiac_geometriesx-0.4.1.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
 
@@ -1,16 +0,0 @@
1
- cardiac_geometries/__init__.py,sha256=2W_ywAeLjyRk5MqSPAodHa4UN2lOnW1h8tmGLQ3gaJ0,150
2
- cardiac_geometries/cli.py,sha256=GKcsMNhVFoxWDr-o3jiDCXmTvPgCSEB9Kws8AvYIK4Q,19678
3
- cardiac_geometries/geometry.py,sha256=iK8lydZEqU3sz0983yucW9IzQ2VqSXSy4D5ubdl9bOs,5636
4
- cardiac_geometries/gui.py,sha256=9WYR850wLrqsUrVUC37E2SaO0OWA_oagSe-YNrsxz3k,8376
5
- cardiac_geometries/mesh.py,sha256=Ejciny48mnKKN20RrY9DwLY7_Lh1jb6Kldj4CW1wr1o,26909
6
- cardiac_geometries/utils.py,sha256=EwEXAuB4XiJaqlZaGZ1cc6sIBSPJLCx-43As1NUcJrA,16488
7
- cardiac_geometries/fibers/__init__.py,sha256=WpRrn9Iakl-3m8IGtFkqP0LXGjw5EZHZ8Eg9JCnCdrg,137
8
- cardiac_geometries/fibers/lv_ellipsoid.py,sha256=KuWnx9yZ5KDyoeoYyDnXLZYb82DRiNveZyNIboD3uJ8,5768
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,,