stentfit.core.artery_geom
Attributes
Functions
|
Sample evenly-spaced points around a circle in the XY plane, at z=0. |
|
Sweep a circular cross-section along a centreline into a tube mesh. |
|
Turn a lumen-only tube mesh into a hollow-walled tube. |
|
Build a straight centreline of the given length along the z-axis. |
|
Build a straight → arc → straight centreline, in the XZ plane. |
|
Build an S-shaped centreline: straight → arc right → straight → arc left → straight. |
|
Build a straight tube mesh of constant radius. |
|
Build a tube mesh of constant radius along a single-bend centreline. |
|
Build a tube mesh of constant radius along an S-shaped centreline. |
|
Perturb a straight tube mesh's radius with a smooth, organic-looking pattern. |
|
Propagate a rotation-minimising frame (tangent, normal, binormal) along a centreline. |
|
Bend a straight tube mesh's node coordinates onto an artery centreline. |
|
Count elements that ended up inverted (negative signed volume). |
|
Mesh the artery wall as a hollow 3D solid with GMSH and write it as a 4C |
|
Import the artery solid mesh into BeamMe, from a 4C |
|
Tie the stent beam mesh to the artery solid's lumen surface and write the combined 4C input. |
Module Contents
- stentfit.core.artery_geom._make_circle_points(radius: float, n_circumference: int) numpy.ndarray
Sample evenly-spaced points around a circle in the XY plane, at z=0.
- Parameters:
radius – Circle radius.
n_circumference – Number of points around the circle.
- Returns:
(n_circumference, 3)array of points.
- stentfit.core.artery_geom._build_tube_mesh(centerline: numpy.ndarray, radii: numpy.ndarray, n_circumference: int = 32, cap_ends: bool = True, noise_amplitude: float = 0.0, noise_seed: int | None = None) trimesh.Trimesh
Sweep a circular cross-section along a centreline into a tube mesh.
A local frame (tangent, normal, binormal) is propagated along the centreline by parallel-transporting the normal at each step (a rotation-minimising-frame approximation), so the cross-section doesn’t twist. If
noise_amplitudeis positive, a “biological” wall-roughness field is added as a fractional radius deviation: a smooth low-frequency component along the length (75% weight, mimicking natural stenosis/dilatation) plus a small-scale per-vertex component (25% weight, mimicking endothelial texture), clamped so the radius never drops below 10% of its nominal value. Both ends are capped with a triangle fan ifcap_ends.- Parameters:
centerline –
(n, 3)points along the tube’s centreline.radii – Per-section radius, one value per centreline point.
n_circumference – Number of vertices around each cross-section.
cap_ends – Close both ends of the tube with a triangle fan.
noise_amplitude – Fractional wall-roughness noise, as a fraction of the radius.
noise_seed – Seed for the wall noise.
Nonedraws a fresh pattern each call.
- Returns:
The tube surface mesh, with normals fixed to point outward.
- stentfit.core.artery_geom._add_outer_wall(inner_mesh: trimesh.Trimesh, centerline: numpy.ndarray, radii: numpy.ndarray, wall_thickness: float, n_circumference: int) trimesh.Trimesh
Turn a lumen-only tube mesh into a hollow-walled tube.
Builds a second, larger, independently-capped tube at
radii + wall_thicknessas the outer wall, flipsinner_mesh’s normals so they face into the wall material instead of outward, and concatenates both into one mesh representing the wall’s inner and outer boundary together.- Parameters:
inner_mesh – The lumen surface, from
_build_tube_mesh().centerline –
(n, 3)points along the tube’s centreline, matchinginner_mesh.radii – Per-section lumen radius, matching
inner_mesh.wall_thickness – Wall thickness added to
radiifor the outer surface.n_circumference – Number of vertices around each cross-section.
- Returns:
The combined outer + inner (inverted) surface mesh.
- stentfit.core.artery_geom.straight_centreline(length: float, n_points: int = 100) numpy.ndarray
Build a straight centreline of the given length along the z-axis.
- Parameters:
length – Centreline length, in mm.
n_points – Number of points along the centreline.
- Returns:
(n_points, 3)array of points, atx = y = 0.
- stentfit.core.artery_geom.curved_centreline(length: float, bend_radius: float, bend_angle_deg: float = 45.0, n_points: int = 100) numpy.ndarray
Build a straight → arc → straight centreline, in the XZ plane.
The middle section is a circular arc of
bend_radiussweepingbend_angle_deg; the two straight segments before and after it are equal length, sized so the whole centreline’s arc length adds up tolength. Points are sampled at even arc-length steps along the whole path.- Parameters:
length – Total centreline arc length, in mm.
bend_radius – Radius of the circular arc, in mm.
bend_angle_deg – Total bend angle, in degrees.
n_points – Number of points along the centreline.
- Raises:
ValueError – If the arc alone (
bend_radius * bend_angle) is longer thanlength, leaving no room for the two straight segments.- Returns:
(n_points, 3)array of points.
- stentfit.core.artery_geom.s_bend_centreline(length: float, bend_radius: float, bend_angle_deg: float = 30.0, n_points: int = 100) numpy.ndarray
Build an S-shaped centreline: straight → arc right → straight → arc left → straight.
Walked piecewise in 3D, tracking position and heading segment by segment, so each arc continues smoothly from where the previous segment left off. The two arcs both use
bend_radius/bend_angle_degbut curve in opposite directions; the three straight segments share what’s left oflengthequally. Each of the 5 segments gets roughlyn_points / 5points (floored at 10), so the actual point count may come out slightly different fromn_points.- Parameters:
length – Total centreline arc length, in mm.
bend_radius – Radius of each circular arc, in mm.
bend_angle_deg – Bend angle of each arc, in degrees.
n_points – Target number of points along the centreline.
- Raises:
ValueError – If the two arcs alone are longer than
length, leaving no room for the three straight segments.- Returns:
Array of points along the centreline.
- stentfit.core.artery_geom.generate_straight_artery(radius: float = 1.5, length: float = 25.0, wall_thickness: float = 0.0, n_circumference: int = 32, n_axial: int = 100, noise_amplitude: float = 0.0, noise_seed: int | None = None) trimesh.Trimesh
Build a straight tube mesh of constant radius.
The simplest of the three artery shapes: a
straight_centreline()with a uniform radius, tubed by_build_tube_mesh(). Ifwall_thicknessis positive, a second, larger tube is added as the outer wall (_add_outer_wall()); otherwise the mesh is the lumen surface only.- Parameters:
radius – Lumen radius, in mm.
length – Artery length, in mm.
wall_thickness – Wall thickness, in mm.
0builds the lumen surface only, with no separate wall.n_circumference – Number of vertices around each cross-section.
n_axial – Number of cross-sections along the length.
noise_amplitude – Fractional wall-roughness noise, as a fraction of the radius.
noise_seed – Seed for the wall noise.
Nonedraws a fresh pattern each call.
- Returns:
The artery wall mesh.
- stentfit.core.artery_geom.generate_curved_artery(radius: float = 1.5, length: float = 30.0, bend_radius: float = 20.0, bend_angle_deg: float = 45.0, wall_thickness: float = 0.0, n_circumference: int = 32, n_axial: int = 100, noise_amplitude: float = 0.0, noise_seed: int | None = None) trimesh.Trimesh
Build a tube mesh of constant radius along a single-bend centreline.
Same construction as
generate_straight_artery(), but tubed along acurved_centreline()(straight → arc → straight) instead of a straight line.- Parameters:
radius – Lumen radius, in mm.
length – Total artery length along the centreline, in mm.
bend_radius – Radius of the circular arc, in mm.
bend_angle_deg – Total bend angle, in degrees.
wall_thickness – Wall thickness, in mm.
0builds the lumen surface only, with no separate wall.n_circumference – Number of vertices around each cross-section.
n_axial – Number of cross-sections along the length.
noise_amplitude – Fractional wall-roughness noise, as a fraction of the radius.
noise_seed – Seed for the wall noise.
Nonedraws a fresh pattern each call.
- Returns:
The artery wall mesh.
- stentfit.core.artery_geom.generate_s_bend_artery(radius: float = 1.5, length: float = 40.0, bend_radius: float = 25.0, bend_angle_deg: float = 25.0, wall_thickness: float = 0.0, n_circumference: int = 32, n_axial: int = 150, noise_amplitude: float = 0.0, noise_seed: int | None = None) trimesh.Trimesh
Build a tube mesh of constant radius along an S-shaped centreline.
Same construction as
generate_straight_artery(), but tubed along as_bend_centreline()(two opposite bends).n_axialis only a target: the S-bend centreline’s actual point count can come out slightly different, so the radius array is sized to match the centreline it actually returns rather thann_axialdirectly.- Parameters:
radius – Lumen radius, in mm.
length – Total artery length along the centreline, in mm.
bend_radius – Radius of each circular arc, in mm.
bend_angle_deg – Bend angle of each arc, in degrees.
wall_thickness – Wall thickness, in mm.
0builds the lumen surface only, with no separate wall.n_circumference – Number of vertices around each cross-section.
n_axial – Target number of cross-sections along the length.
noise_amplitude – Fractional wall-roughness noise, as a fraction of the radius.
noise_seed – Seed for the wall noise.
Nonedraws a fresh pattern each call.
- Returns:
The artery wall mesh.
- stentfit.core.artery_geom._MESH_SPEC
- stentfit.core.artery_geom._apply_radial_noise(coords: numpy.ndarray, length: float, amplitude: float, seed: int | None) numpy.ndarray
Perturb a straight tube mesh’s radius with a smooth, organic-looking pattern.
Sums 4 sinusoidal modes, each oscillating along both the axial (z) and circumferential (phi) directions with a random amplitude sign and phase, to build a wall-roughness field that reads as smooth and undulating rather than uniform per-vertex noise. The field is normalised to peak at 1 before scaling by
amplitude, and tapered to zero within the last 10% of the length at each end, so the flat inlet/outlet caps stay flat. Only the radius changes;zis left untouched.- Parameters:
coords –
(n, 3)node coordinates of the straight tube mesh.length – Tube length along z, used to scale the noise wavelengths and end taper.
amplitude – Fractional radial noise, as a fraction of the local radius.
seed – Seed for the noise pattern.
Nonedraws a fresh pattern each call.
- Returns:
The perturbed coordinates.
- stentfit.core.artery_geom._compute_rmf(cl: numpy.ndarray) tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray]
Propagate a rotation-minimising frame (tangent, normal, binormal) along a centreline.
The tangent is the local curve direction; the normal starts perpendicular to the first tangent and is then parallel-transported along the curve (projected onto each new tangent’s perpendicular plane and renormalised), so the frame doesn’t twist. The binormal completes the frame. Same construction as
_build_tube_mesh()’s frame.- Parameters:
cl –
(n, 3)centreline points.- Returns:
(T, N, B)— the per-point tangent, normal, and binormal, each(n, 3).
- stentfit.core.artery_geom._warp_coords_to_centreline(coords: numpy.ndarray, centreline: numpy.ndarray) numpy.ndarray
Bend a straight tube mesh’s node coordinates onto an artery centreline.
Each node’s
zis treated as its arc-length position along the straight tube (clamped to the centreline’s own arc range), used to interpolate that point’s position and rotation-minimising frame (_compute_rmf()) oncentreline. The node’s localx/yoffset is then re-expressed along the interpolated normal/binormal instead of the original straight-tube axes — the same warping convention used for the stent beam mesh, so the two stay aligned.- Parameters:
coords –
(n, 3)node coordinates of the straight tube mesh.centreline – Points the straight tube is warped onto.
- Returns:
The warped coordinates.
- stentfit.core.artery_geom._count_inverted(coords: numpy.ndarray, conn: numpy.ndarray, mesh_type: str) int
Count elements that ended up inverted (negative signed volume).
For each element, takes the scalar triple product of the first three edge vectors from one corner node (nodes 0,1,2,3 for a tet; nodes 0,1,3,4 for a hex, treating one corner as a representative tetrahedron). A negative value means that element’s node ordering now describes a flipped, degenerate shape — a sign that a large warp or noise amplitude has folded the mesh over on itself.
- Parameters:
coords –
(n, 3)node coordinates.conn –
(n_elem, nnode)element connectivity, with 1-based node IDs.mesh_type – Element type: any
'TET*'label, or'HEX8'.
- Returns:
Number of elements with negative signed volume.
- stentfit.core.artery_geom.mesh_artery_gmsh(r_inner: float, r_outer: float, centreline: numpy.ndarray, out_path: str | pathlib.Path, mesh_type: str = 'TET4', element_size: float | None = None, noise_amplitude: float = 0.0, noise_seed: int | None = None, material_id: int = 1, youngs_modulus: float = 1.0, poisson_ratio: float = 0.3, density: float = 1.0) pathlib.Path
Mesh the artery wall as a hollow 3D solid with GMSH and write it as a 4C
.yaml.Builds a straight annular tube between
r_innerandr_outer— unstructured tets (TET4/TET10, via an OCC cylinder-minus-cylinder boolean cut) or structured hexahedra (HEX8, via transfinite annular sectors extruded along the tube) — then classifies its boundary nodes intoDSURFACEsets purely from their coordinates: the inner surface is the lumen (DSURFACE 1), and the two flat ends are the inlet/outlet (DSURFACE 2/3). Optional radial wall-roughness noise is applied, then the whole straight tube is warped ontocentrelineusing the same frame convention as the stent warp, so the solid stays aligned with the beam mesh. Elements that end up inverted by the warp or noise are counted and reported as a warning. Writes the mesh plus a placeholderMAT_Struct_StVenantKirchhoffmaterial as a 4C solid input file.- Parameters:
r_inner – Lumen (inner) radius, in mm.
r_outer – Outer wall radius, in mm.
centreline – Points the straight tube is warped onto.
out_path – File path the 4C
.yamlsolid is written to.mesh_type – Element type:
'TET4','TET10', or'HEX8'.element_size – Target element size, in mm.
Noneuses roughly one element across the wall thickness (r_outer - r_inner).noise_amplitude – Fractional radial wall-roughness noise.
noise_seed – Seed for the wall noise.
Nonedraws a fresh pattern each call.material_id – Material ID written into the 4C input.
youngs_modulus – Placeholder material Young’s modulus, in MPa.
poisson_ratio – Placeholder material Poisson’s ratio.
density – Placeholder material density.
- Raises:
ValueError – If
r_outer <= r_innerorr_inner <= 0, or ifmesh_typeisn’t one of the supported keys.- Returns:
out_path, for chaining into a caller’s own return value.
- stentfit.core.artery_geom.import_artery_solid(source) tuple[beamme.four_c.input_file.InputFile, beamme.core.mesh.Mesh]
Import the artery solid mesh into BeamMe, from a 4C
.yamlor a CubitPy model.Duck-types
source: a CubitPy model (detected by acmdattribute or class name) is imported viaimport_cubitpy_model; anything else is treated as a path to a 4C.yamlsolid (e.g. frommesh_artery_gmsh()) and imported viaimport_four_c_model. The CubitPy path is legacy — Cubit Coreform is no longer used in this project (no macOS build), so in practicesourceis always a.yamlpath.- Parameters:
source – A CubitPy model, or a path to a 4C
.yamlsolid.- Returns:
(input_file, solid)— the BeamMeInputFileand the imported solidMesh.
- stentfit.core.artery_geom.assemble_beam_solid(input_file: beamme.four_c.input_file.InputFile, solid_mesh: beamme.core.mesh.Mesh, beam_mesh: beamme.core.mesh.Mesh, lumen_surface_index: int = 0, bc_type=None, contact_discretization: str = 'mortar', mortar_shape: str = 'line2', n_gauss_points: int = 6, output_path: str | pathlib.Path | None = None) tuple[beamme.four_c.input_file.InputFile, beamme.core.mesh.Mesh]
Tie the stent beam mesh to the artery solid’s lumen surface and write the combined 4C input.
Merges
beam_meshintosolid_mesh, couples the beam elements to the solid’s lumen surface set (lumen_surface_index) via BeamMe’s mortar beam-to-solid method (add_beam_interaction_condition), and — for the meshtying variants — writes the matching header options (set_beam_to_solid_meshtying). Contact uses a different header setter, not yet wired up here. Ifoutput_pathis given, dumps the assembled input file there.- Parameters:
input_file – BeamMe
InputFilethe solid (and, once merged, the beams) is added to.solid_mesh – Artery solid mesh, from
import_artery_solid(). Modified in place: the beam elements are merged into it.beam_mesh – Warped stent beam mesh, from
align().lumen_surface_index – Index into the solid’s surface geometry sets for the lumen surface the beams couple to.
bc_type – BeamMe beam-to-solid coupling type.
Nonedefaults to tied meshtying (bme.bc.beam_to_solid_surface_meshtying).contact_discretization – Mortar discretization passed to
set_beam_to_solid_meshtying.mortar_shape – Mortar shape function passed to
set_beam_to_solid_meshtying.n_gauss_points – Number of Gauss points passed to
set_beam_to_solid_meshtying.output_path – File path to dump the assembled 4C input to.
Noneskips writing.
- Raises:
ValueError – If
solid_meshhas no surface geometry set to couple to.- Returns:
(input_file, solid_mesh)— the input file with the solid (and merged beams) added, and the combined mesh.