DeepSDFStruct 1.7.2__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.
- DeepSDFStruct/SDF.py +1734 -0
- DeepSDFStruct/__init__.py +66 -0
- DeepSDFStruct/deep_sdf/__init__.py +69 -0
- DeepSDFStruct/deep_sdf/create_screenshots_from_plyfiles.py +65 -0
- DeepSDFStruct/deep_sdf/data.py +258 -0
- DeepSDFStruct/deep_sdf/metrics/__init__.py +14 -0
- DeepSDFStruct/deep_sdf/metrics/mesh_to_analytical.py +24 -0
- DeepSDFStruct/deep_sdf/models.py +197 -0
- DeepSDFStruct/deep_sdf/networks/__init__.py +8 -0
- DeepSDFStruct/deep_sdf/networks/analytic_round_cross.py +105 -0
- DeepSDFStruct/deep_sdf/networks/deep_sdf_decoder.py +155 -0
- DeepSDFStruct/deep_sdf/networks/hierarchical_deep_sdf_decoder.py +139 -0
- DeepSDFStruct/deep_sdf/networks/hierarchical_positional_sdf_decoder.py +190 -0
- DeepSDFStruct/deep_sdf/networks/resnet_positional_sdf_decoder.py +108 -0
- DeepSDFStruct/deep_sdf/nn_utils.py +70 -0
- DeepSDFStruct/deep_sdf/plotting.py +143 -0
- DeepSDFStruct/deep_sdf/reconstruction.py +165 -0
- DeepSDFStruct/deep_sdf/training.py +840 -0
- DeepSDFStruct/deep_sdf/workspace.py +363 -0
- DeepSDFStruct/design_of_experiments.py +235 -0
- DeepSDFStruct/flexicubes/__init__.py +15 -0
- DeepSDFStruct/flexicubes/flexicubes.py +1005 -0
- DeepSDFStruct/flexicubes/tables.py +2338 -0
- DeepSDFStruct/flexisquares/__init__.py +15 -0
- DeepSDFStruct/flexisquares/flexisquares.py +967 -0
- DeepSDFStruct/flexisquares/tables.py +63 -0
- DeepSDFStruct/lattice_structure.py +254 -0
- DeepSDFStruct/local_shapes.py +226 -0
- DeepSDFStruct/mesh.py +1184 -0
- DeepSDFStruct/optimization.py +357 -0
- DeepSDFStruct/parametrization.py +215 -0
- DeepSDFStruct/pretrained_models.py +128 -0
- DeepSDFStruct/sampling.py +670 -0
- DeepSDFStruct/sdf_operations.py +990 -0
- DeepSDFStruct/sdf_primitives.py +1416 -0
- DeepSDFStruct/splinepy_unitcells/__init__.py +35 -0
- DeepSDFStruct/splinepy_unitcells/chi_3D.py +1617 -0
- DeepSDFStruct/splinepy_unitcells/cross_lattice.py +165 -0
- DeepSDFStruct/splinepy_unitcells/double_lattice_extruded.py +298 -0
- DeepSDFStruct/splinepy_unitcells/snappy_3d.py +544 -0
- DeepSDFStruct/torch_spline.py +446 -0
- DeepSDFStruct/trained_models/analytic_round_cross/LatentCodes/latest.pth +0 -0
- DeepSDFStruct/trained_models/analytic_round_cross/ModelParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/analytic_round_cross/OptimizerParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/analytic_round_cross/specs.json +45 -0
- DeepSDFStruct/trained_models/chi_and_cross/LatentCodes/latest.pth +0 -0
- DeepSDFStruct/trained_models/chi_and_cross/Logs.pth +0 -0
- DeepSDFStruct/trained_models/chi_and_cross/ModelParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/chi_and_cross/OptimizerParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/chi_and_cross/specs.json +76 -0
- DeepSDFStruct/trained_models/primitives/LatentCodes/latest.pth +0 -0
- DeepSDFStruct/trained_models/primitives/ModelParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/primitives/OptimizerParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/primitives/specs.json +46 -0
- DeepSDFStruct/trained_models/primitives_2d/LatentCodes/latest.pth +0 -0
- DeepSDFStruct/trained_models/primitives_2d/ModelParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/primitives_2d/OptimizerParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/primitives_2d/specs.json +46 -0
- DeepSDFStruct/trained_models/round_cross/LatentCodes/latest.pth +0 -0
- DeepSDFStruct/trained_models/round_cross/Logs.pth +0 -0
- DeepSDFStruct/trained_models/round_cross/ModelParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/round_cross/OptimizerParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/round_cross/specs.json +45 -0
- DeepSDFStruct/trained_models/test_experiment/LatentCodes/latent_code_data_map.json +106 -0
- DeepSDFStruct/trained_models/test_experiment/specs.json +45 -0
- DeepSDFStruct/trained_models/test_experiment/training_summary.json +10 -0
- DeepSDFStruct/trained_models/test_experiment_hierarchical/LatentCodes/latent_code_data_map.json +106 -0
- DeepSDFStruct/trained_models/test_experiment_hierarchical/specs.json +45 -0
- DeepSDFStruct/trained_models/test_experiment_hierarchical/training_summary.json +10 -0
- DeepSDFStruct/trained_models/test_experiment_homogenization/LatentCodes/latent_code_data_map.json +5006 -0
- DeepSDFStruct/trained_models/test_experiment_homogenization/LatentCodes/latest.pth +0 -0
- DeepSDFStruct/trained_models/test_experiment_homogenization/Logs.png +0 -0
- DeepSDFStruct/trained_models/test_experiment_homogenization/ModelParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/test_experiment_homogenization/OptimizerParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/test_experiment_homogenization/specs.json +83 -0
- DeepSDFStruct/trained_models/test_experiment_homogenization/training_summary.json +10 -0
- DeepSDFStruct/utils.py +96 -0
- DeepSDFStruct/visualization/latent_viewer.py +211 -0
- DeepSDFStruct/visualization/latent_viewer_cli.py +8 -0
- benchmarks/generate_sdf_showcase.py +622 -0
- benchmarks/sdf_from_mesh_benchmark.py +52 -0
- benchmarks/sdf_from_mesh_comparison.md +33 -0
- benchmarks/sdf_showcase/operations/boolean/difference_sphere_box.png +0 -0
- benchmarks/sdf_showcase/operations/boolean/union_sphere_box.png +0 -0
- benchmarks/sdf_showcase/operations/transformations/circular_array_sphere.png +0 -0
- benchmarks/sdf_showcase/operations/transformations/dilate_sphere.png +0 -0
- benchmarks/sdf_showcase/operations/transformations/mirror_sphere.png +0 -0
- benchmarks/sdf_showcase/operations/transformations/repeat_sphere.png +0 -0
- benchmarks/sdf_showcase/operations/transformations/revolve_circle.png +0 -0
- benchmarks/sdf_showcase/operations/transformations/shell_sphere.png +0 -0
- benchmarks/sdf_showcase/operations/transformations/twist_torus.png +0 -0
- benchmarks/sdf_showcase/primitives/2D/circle.png +0 -0
- benchmarks/sdf_showcase/primitives/2D/equilateral_triangle.png +0 -0
- benchmarks/sdf_showcase/primitives/2D/hexagon.png +0 -0
- benchmarks/sdf_showcase/primitives/2D/polygon_pentagon.png +0 -0
- benchmarks/sdf_showcase/primitives/2D/rectangle.png +0 -0
- benchmarks/sdf_showcase/primitives/2D/rounded_rectangle.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/box.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/capped_cone.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/capped_cylinder.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/capsule.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/cone.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/corner_spheres.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/cross_ms.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/cylinder.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/dodecahedron.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/ellipsoid.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/icosahedron.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/octahedron.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/pyramid.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/rounded_box.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/rounded_cone.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/rounded_cylinder.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/sphere.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/tetrahedron.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/torus.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/wireframe_box.png +0 -0
- deepsdfstruct-1.7.2.dist-info/METADATA +44 -0
- deepsdfstruct-1.7.2.dist-info/RECORD +165 -0
- deepsdfstruct-1.7.2.dist-info/WHEEL +5 -0
- deepsdfstruct-1.7.2.dist-info/licenses/LICENSE +208 -0
- deepsdfstruct-1.7.2.dist-info/licenses/NOTICE +67 -0
- deepsdfstruct-1.7.2.dist-info/scm_file_list.json +178 -0
- deepsdfstruct-1.7.2.dist-info/scm_version.json +8 -0
- deepsdfstruct-1.7.2.dist-info/top_level.txt +4 -0
- docs/Makefile +20 -0
- docs/api_reference.rst +6 -0
- docs/conf.py +60 -0
- docs/index.rst +136 -0
- docs/make.bat +35 -0
- docs/qr_code_github.png +0 -0
- docs/qr_code_paper.png +0 -0
- docs/readme_images/example_output_01.png +0 -0
- docs/readme_images/example_output_02.png +0 -0
- docs/readme_images/example_output_03.png +0 -0
- docs/readme_images/example_output_04.png +0 -0
- tests/data/chairs/1005.obj +282 -0
- tests/data/chairs/1024.obj +222 -0
- tests/data/chairs/README.md +1 -0
- tests/data/circular_balls_test_case.stl +0 -0
- tests/data/cone.stl +1794 -0
- tests/data/example_disconnectd_mesh.inp +1784 -0
- tests/data/example_line_mesh.vtk +0 -0
- tests/data/stanford_bunny.stl +0 -0
- tests/data/sweep_test_case.stl +0 -0
- tests/test_DOE.py +49 -0
- tests/test_elongate_sdf.py +195 -0
- tests/test_flexisquares.py +187 -0
- tests/test_generate_dataset.py +76 -0
- tests/test_lattice_evaluation.py +137 -0
- tests/test_mesh_export.py +137 -0
- tests/test_mesh_functions.py +49 -0
- tests/test_networks.py +71 -0
- tests/test_pretrained_models.py +40 -0
- tests/test_reconstruction.py +101 -0
- tests/test_sdf_from_mesh.py +52 -0
- tests/test_sdf_functions.py +117 -0
- tests/test_sdf_primitives.py +668 -0
- tests/test_sdf_trimesh_comparison.py +482 -0
- tests/test_splinepy_unitcells.py +64 -0
- tests/test_structural_optimization.py +178 -0
- tests/test_torch_spline.py +216 -0
- tests/test_train_model.py +110 -0
- tests/test_training_data_ids.py +41 -0
- tests/tmp_outputs/temp_file.txt +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""
|
|
2
|
+
FlexiSquares Lookup Tables
|
|
3
|
+
==========================
|
|
4
|
+
|
|
5
|
+
This module contains precomputed lookup tables for the FlexiSquares algorithm.
|
|
6
|
+
These tables encode the topology of all possible Marching Squares configurations.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# (0,1) ─ 2 ─ (1,1)
|
|
10
|
+
# | |
|
|
11
|
+
# 0 1
|
|
12
|
+
# | |
|
|
13
|
+
# (0,0) ─ 3 ─ (1,0)
|
|
14
|
+
|
|
15
|
+
# (2) ─ 2 ─ (3)
|
|
16
|
+
# | |
|
|
17
|
+
# 0 1
|
|
18
|
+
# | |
|
|
19
|
+
# (0) ─ 3 ─ (1)
|
|
20
|
+
|
|
21
|
+
# Edges are:
|
|
22
|
+
# e0: bottom → top along left side → (0,0)-(0,1) → corners (0,2)
|
|
23
|
+
# e1: bottom → top along right side → (1,0)-(1,1) → corners (1,3)
|
|
24
|
+
# e2: left → right along bottom → (0,0)-(1,0) → corners (0,1)
|
|
25
|
+
# e3: left → right along top → (0,1)-(1,1) → corners (2,3)
|
|
26
|
+
dmc_table = [
|
|
27
|
+
[[-1, -1], [-1, -1]], # 0: 0000 no intersections
|
|
28
|
+
[[0, 3], [-1, -1]], # 1: 0001
|
|
29
|
+
[[1, 3], [-1, -1]], # 2: 0010
|
|
30
|
+
[[0, 1], [-1, -1]], # 3: 0011
|
|
31
|
+
[[2, 0], [-1, -1]], # 4: 0100
|
|
32
|
+
[[2, 3], [-1, -1]], # 5: 0101
|
|
33
|
+
[[0, 3], [2, 1]], # 6: 0110 # ambigous (two lines)
|
|
34
|
+
[[1, 2], [-1, -1]], # 7: 0111
|
|
35
|
+
[[1, 2], [-1, -1]], # 8: 1000
|
|
36
|
+
[[0, 2], [3, 1]], # 9: 1001 # ambiguous (two lines)
|
|
37
|
+
[[2, 3], [-1, -1]], # 10: 1010
|
|
38
|
+
[[0, 2], [-1, -1]], # 11: 1011
|
|
39
|
+
[[0, 1], [-1, -1]], # 12: 1100
|
|
40
|
+
[[3, 1], [-1, -1]], # 13: 1101
|
|
41
|
+
[[0, 3], [-1, -1]], # 14: 1110
|
|
42
|
+
[[-1, -1], [-1, -1]], # 15: 1111 full fill (no contour)
|
|
43
|
+
]
|
|
44
|
+
# connect center to ->
|
|
45
|
+
tet_table = [
|
|
46
|
+
[[-1, -1], [-1, -1]], # 0: 0000 no intersections
|
|
47
|
+
[[-1, -1], [-1, -1]], # 1: 0001
|
|
48
|
+
[[-1, -1], [-1, -1]], # 2: 0010
|
|
49
|
+
[[0, 1], [-1, -1]], # 3: 0011
|
|
50
|
+
[[-1, -1], [-1, -1]], # 4: 0100
|
|
51
|
+
[[2, 0], [-1, -1]], # 5: 0101
|
|
52
|
+
[[1, 2], [-1, -1]], # 6: 0110 # ambigous (two lines)
|
|
53
|
+
[[2, 0], [0, 1]], # 7: 0111
|
|
54
|
+
[[-1, -1], [-1, -1]], # 8: 1000
|
|
55
|
+
[[0, 3], [-1, -1]], # 9: 1001 # ambiguous (two lines)
|
|
56
|
+
[[1, 3], [-1, -1]], # 10: 1010
|
|
57
|
+
[[1, 3], [0, 1]], # 11: 1011
|
|
58
|
+
[[3, 2], [-1, -1]], # 12: 1100
|
|
59
|
+
[[3, 2], [2, 0]], # 13: 1101
|
|
60
|
+
[[1, 3], [3, 2]], # 14: 1110
|
|
61
|
+
[[-1, -1], [-1, -1]], # 15: 1111 full fill (no contour)
|
|
62
|
+
]
|
|
63
|
+
num_vd_table = [0, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 0]
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Lattice Structure Generation
|
|
3
|
+
=============================
|
|
4
|
+
|
|
5
|
+
This module provides tools for creating periodic lattice structures with
|
|
6
|
+
deformable geometries. Lattices are built by tiling a unit cell (microtile)
|
|
7
|
+
in a regular pattern and applying optional smooth deformations via B-splines.
|
|
8
|
+
|
|
9
|
+
The main class, LatticeSDFStruct, enables creation of complex microstructured
|
|
10
|
+
materials with spatially-varying properties, useful for applications in:
|
|
11
|
+
- Topology optimization
|
|
12
|
+
- Additive manufacturing
|
|
13
|
+
- Metamaterial design
|
|
14
|
+
- Lightweight structural components
|
|
15
|
+
|
|
16
|
+
Key Features
|
|
17
|
+
------------
|
|
18
|
+
- Periodic tiling of arbitrary unit cell geometries
|
|
19
|
+
- Smooth deformations via spline-based mapping
|
|
20
|
+
- Spatially-varying parametrization (e.g., varying strut thickness)
|
|
21
|
+
- Support for 2D and 3D lattices
|
|
22
|
+
- Integration with boundary conditions and capping
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import logging
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
import numpy as _np
|
|
29
|
+
import torch as _torch
|
|
30
|
+
|
|
31
|
+
from splinepy import BSpline as _BSpline
|
|
32
|
+
from .SDF import SDFBase as _SDFBase
|
|
33
|
+
import DeepSDFStruct
|
|
34
|
+
import gustaf as gus
|
|
35
|
+
|
|
36
|
+
logger = logging.getLogger(DeepSDFStruct.__name__)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class LatticeSDFStruct(_SDFBase):
|
|
40
|
+
"""Helper class to facilitate the construction of periodic lattice SDF structures.
|
|
41
|
+
|
|
42
|
+
This class creates periodic lattice structures by tiling a unit cell geometry
|
|
43
|
+
(microtile) in a regular pattern and optionally deforming the result through
|
|
44
|
+
a spline-based mapping. The microtile can be parametrized to have spatially-
|
|
45
|
+
varying properties (e.g., thickness that varies across the structure).
|
|
46
|
+
|
|
47
|
+
The lattice is defined in parametric space [0,1]^d and can be mapped to
|
|
48
|
+
physical space through a deformation spline. Boundary conditions can be
|
|
49
|
+
applied to cap the structure at domain boundaries.
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
tiling : list of int or int, optional
|
|
54
|
+
Number of repetitions of the microtile in each parametric dimension.
|
|
55
|
+
If an int, uses the same tiling in all dimensions.
|
|
56
|
+
microtile : SDFBase, optional
|
|
57
|
+
The unit cell geometry to be tiled. Should be defined in the
|
|
58
|
+
unit cube [0,1]^d.
|
|
59
|
+
parametrization : torch.nn.Module, optional
|
|
60
|
+
Function that provides spatially-varying parameters for the microtile
|
|
61
|
+
(e.g., varying strut thickness). Takes parametric coordinates and
|
|
62
|
+
returns parameter values.
|
|
63
|
+
cap_border_dict : CapBorderDict, optional
|
|
64
|
+
Dictionary specifying whether material should be added or removed
|
|
65
|
+
at domain faces (for capping the structure at boundaries).
|
|
66
|
+
cap_outside_of_unitcube : bool, default True
|
|
67
|
+
If True, caps geometry outside the unit cube.
|
|
68
|
+
|
|
69
|
+
Attributes
|
|
70
|
+
----------
|
|
71
|
+
tiling : list of int
|
|
72
|
+
Number of tiles in each dimension.
|
|
73
|
+
microtile : SDFBase
|
|
74
|
+
The unit cell geometry.
|
|
75
|
+
geometric_dim : int
|
|
76
|
+
Geometric dimensionality (2 or 3).
|
|
77
|
+
parametric_dimension : int
|
|
78
|
+
Parametric dimensionality (equal to geometric_dim).
|
|
79
|
+
|
|
80
|
+
Notes
|
|
81
|
+
-----
|
|
82
|
+
The microtile should ideally have periodic boundary conditions to ensure
|
|
83
|
+
smooth connections between adjacent tiles. For parametrized microtiles,
|
|
84
|
+
the microtile must provide:
|
|
85
|
+
- `evaluation_points`: Points where parameters are evaluated
|
|
86
|
+
- `para_dim`: Dimensionality of the parameter space
|
|
87
|
+
- `_set_param`: Method to update parameters
|
|
88
|
+
|
|
89
|
+
Examples
|
|
90
|
+
--------
|
|
91
|
+
>>> from DeepSDFStruct.lattice_structure import LatticeSDFStruct
|
|
92
|
+
>>> from DeepSDFStruct.sdf_primitives import SphereSDF
|
|
93
|
+
>>> from DeepSDFStruct.torch_spline import TorchSpline
|
|
94
|
+
>>> import torch
|
|
95
|
+
>>>
|
|
96
|
+
>>> # Create a simple unit cell
|
|
97
|
+
>>> unit_cell = SphereSDF(center=[0.5, 0.5, 0.5], radius=0.3)
|
|
98
|
+
>>>
|
|
99
|
+
>>> # Create lattice with 3x3x3 tiling
|
|
100
|
+
>>> lattice = LatticeSDFStruct(
|
|
101
|
+
... tiling=[3, 3, 3],
|
|
102
|
+
... microtile=unit_cell
|
|
103
|
+
... )
|
|
104
|
+
>>>
|
|
105
|
+
>>> # Query lattice SDF
|
|
106
|
+
>>> points = torch.rand(100, 3)
|
|
107
|
+
>>> distances = lattice(points)
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
def __init__(
|
|
111
|
+
self,
|
|
112
|
+
tiling: list[int] | int | None = None,
|
|
113
|
+
microtile: _SDFBase | None = None,
|
|
114
|
+
parametrization: _torch.nn.Module | None = None,
|
|
115
|
+
bounds=None,
|
|
116
|
+
):
|
|
117
|
+
"""Helper class to facilitate the construction of microstructures.
|
|
118
|
+
|
|
119
|
+
Parameters
|
|
120
|
+
----------
|
|
121
|
+
deformation_function : spline
|
|
122
|
+
Outer function that describes the contour of the microstructured
|
|
123
|
+
geometry
|
|
124
|
+
tiling : list of integers
|
|
125
|
+
microtiles per parametric dimension
|
|
126
|
+
microtile : SDFBase
|
|
127
|
+
Representation of the building block defined in the unit cube
|
|
128
|
+
parametrization_function : Callable (optional)
|
|
129
|
+
Function to describe spline parameters
|
|
130
|
+
"""
|
|
131
|
+
if not isinstance(parametrization, _torch.nn.Module):
|
|
132
|
+
raise TypeError("Parametrization must be of type _Parametrization")
|
|
133
|
+
super().__init__(parametrization=parametrization)
|
|
134
|
+
self.geometric_dim = len(tiling)
|
|
135
|
+
assert (
|
|
136
|
+
microtile.geometric_dim == self.geometric_dim
|
|
137
|
+
), f"dimension of microtile ({self.microtile.geometric_dim}) does not match the tiling ({tiling})"
|
|
138
|
+
self.tiling = tiling
|
|
139
|
+
self.microtile = microtile
|
|
140
|
+
if bounds is not None:
|
|
141
|
+
if isinstance(bounds, (list, tuple)):
|
|
142
|
+
bounds = _torch.tensor(
|
|
143
|
+
bounds, device=microtile.get_device(), dtype=microtile.get_dtype()
|
|
144
|
+
)
|
|
145
|
+
else:
|
|
146
|
+
match self.geometric_dim:
|
|
147
|
+
case 2:
|
|
148
|
+
bounds = _torch.tensor(
|
|
149
|
+
[[0.0, 0.0], [1.0, 1.0]],
|
|
150
|
+
device=microtile.get_device(),
|
|
151
|
+
dtype=microtile.get_dtype(),
|
|
152
|
+
)
|
|
153
|
+
case 3:
|
|
154
|
+
bounds = _torch.tensor(
|
|
155
|
+
[[0.0, 0.0, 0.0], [1.0, 1.0, 1.0]],
|
|
156
|
+
device=microtile.get_device(),
|
|
157
|
+
dtype=microtile.get_dtype(),
|
|
158
|
+
)
|
|
159
|
+
case _:
|
|
160
|
+
raise ValueError(
|
|
161
|
+
f"Geometric dimension must be either 2 or 3. Got {self.geometric_dim}"
|
|
162
|
+
)
|
|
163
|
+
self.register_buffer("bounds", bounds)
|
|
164
|
+
|
|
165
|
+
@property
|
|
166
|
+
def parametric_dimension(self):
|
|
167
|
+
return len(self.tiling)
|
|
168
|
+
|
|
169
|
+
def _get_domain_bounds(self):
|
|
170
|
+
return self.get_buffer("bounds")
|
|
171
|
+
|
|
172
|
+
def _compute(self, samples: _torch.Tensor):
|
|
173
|
+
"""Function, that - if required - parametrizes the microtiles.
|
|
174
|
+
|
|
175
|
+
In order to use said function, the Microtile needs to provide a couple
|
|
176
|
+
of attributes:
|
|
177
|
+
|
|
178
|
+
- evaluation_points - a list of points defined in the unit cube
|
|
179
|
+
that will be evaluated in the parametrization function to provide
|
|
180
|
+
the required set of data points
|
|
181
|
+
- para_dim - dimensionality of the parametrization
|
|
182
|
+
function and number of design variables for said microtile
|
|
183
|
+
|
|
184
|
+
Parameters
|
|
185
|
+
----------
|
|
186
|
+
None
|
|
187
|
+
|
|
188
|
+
Returns
|
|
189
|
+
-------
|
|
190
|
+
: Callable
|
|
191
|
+
Function that describes the local tile parameters
|
|
192
|
+
"""
|
|
193
|
+
bounds = self._get_domain_bounds()
|
|
194
|
+
if self.parametrization is not None:
|
|
195
|
+
samples_parameter_space = (samples - bounds[0]) / (bounds[1] - bounds[0])
|
|
196
|
+
samples_parameter_space = _torch.clamp(samples_parameter_space, 0.0, 1.0)
|
|
197
|
+
parameters = self.parametrization(samples_parameter_space)
|
|
198
|
+
self.microtile._set_param(parameters)
|
|
199
|
+
|
|
200
|
+
queries_transformed = _torch.zeros_like(samples)
|
|
201
|
+
for i_dim, t in enumerate(self.tiling):
|
|
202
|
+
queries_transformed[:, i_dim] = transform(
|
|
203
|
+
samples[:, i_dim], t, bounds=bounds[:, i_dim]
|
|
204
|
+
)
|
|
205
|
+
sdf_values = self.microtile(queries_transformed)
|
|
206
|
+
|
|
207
|
+
return sdf_values
|
|
208
|
+
|
|
209
|
+
def _sanity_check(self):
|
|
210
|
+
"""Check all members and consistency of user data.
|
|
211
|
+
|
|
212
|
+
Parameters
|
|
213
|
+
----------
|
|
214
|
+
updated_properties : bool
|
|
215
|
+
Sets the updated_properties variable to value, which indicates,
|
|
216
|
+
wheither the microstructure needs to be rebuilt
|
|
217
|
+
|
|
218
|
+
Returns
|
|
219
|
+
-------
|
|
220
|
+
passes: bool
|
|
221
|
+
"""
|
|
222
|
+
pass
|
|
223
|
+
|
|
224
|
+
def plot_samples(self, samples, sdf_values):
|
|
225
|
+
vp = gus.Vertices(vertices=samples)
|
|
226
|
+
vp.vertex_data["distance"] = sdf_values
|
|
227
|
+
vp.show_options["cmap"] = "coolwarm"
|
|
228
|
+
gus.show(vp, axes=1)
|
|
229
|
+
|
|
230
|
+
def plot_intermesh(self, verts: _torch.Tensor, faces: _torch.Tensor):
|
|
231
|
+
gus_faces = gus.Faces(vertices=verts.cpu().detach(), faces=faces.cpu().detach())
|
|
232
|
+
gus.show(gus_faces, axes=1)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def constantLatvec(value):
|
|
236
|
+
return _BSpline([0, 0, 0], [[-1, 1], [-1, 1], [-1, 1]], [value])
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def transform(x, t, bounds=[0, 1]):
|
|
240
|
+
# transform x from [bounds[0], bounds[1]] to [-1,1]
|
|
241
|
+
x_norm = (x - bounds[0]) / (bounds[1] - bounds[0])
|
|
242
|
+
x_transformed = 2 * _torch.abs(t * x_norm / 2 - _torch.floor((t * x_norm + 1) / 2))
|
|
243
|
+
return 2 * x_transformed - 1
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def check_tiling_input(tiling):
|
|
247
|
+
if isinstance(tiling, list) or isinstance(tiling, tuple):
|
|
248
|
+
if len(tiling) != 3:
|
|
249
|
+
raise ValueError("Tiling must be a list of 3 integers")
|
|
250
|
+
tiling = _np.array(tiling)
|
|
251
|
+
elif isinstance(tiling, int):
|
|
252
|
+
tiling = _np.array([tiling, tiling, tiling])
|
|
253
|
+
else:
|
|
254
|
+
raise ValueError("Tiling must be a list or an integer")
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Local Shapes for Microstructure Design
|
|
3
|
+
======================================
|
|
4
|
+
|
|
5
|
+
This module provides tools for creating microstructured geometries with
|
|
6
|
+
localized shape variations. Unlike uniform lattices, local shapes allow
|
|
7
|
+
different regions of a structure to have distinct geometric properties,
|
|
8
|
+
enabling graded and functionally-graded materials.
|
|
9
|
+
|
|
10
|
+
Key Features
|
|
11
|
+
------------
|
|
12
|
+
|
|
13
|
+
LocalShapesSDF
|
|
14
|
+
A specialized SDF class for microstructures with spatially-varying
|
|
15
|
+
unit cell shapes. Enables:
|
|
16
|
+
- Region-specific unit cell geometries
|
|
17
|
+
- Smooth transitions between different shapes
|
|
18
|
+
- Integration with parametrization functions
|
|
19
|
+
- Support for 2D and 3D microstructures
|
|
20
|
+
|
|
21
|
+
The module extends the lattice structure capabilities to support more
|
|
22
|
+
complex, heterogeneous microstructural designs where different regions
|
|
23
|
+
may require different geometric features (e.g., varying strut patterns,
|
|
24
|
+
different connectivity, or distinct topologies).
|
|
25
|
+
|
|
26
|
+
This is particularly useful for:
|
|
27
|
+
- Multi-material structures
|
|
28
|
+
- Functionally graded materials
|
|
29
|
+
- Transition zones between different lattice types
|
|
30
|
+
- Adaptive microstructures
|
|
31
|
+
|
|
32
|
+
Examples
|
|
33
|
+
--------
|
|
34
|
+
Create a microstructure with local shape variations::
|
|
35
|
+
|
|
36
|
+
from DeepSDFStruct.local_shapes import LocalShapesSDF
|
|
37
|
+
from DeepSDFStruct.sdf_primitives import SphereSDF
|
|
38
|
+
|
|
39
|
+
# Define unit cell
|
|
40
|
+
unit_cell = SphereSDF([0.5, 0.5, 0.5], radius=0.3)
|
|
41
|
+
|
|
42
|
+
# Create local shapes structure
|
|
43
|
+
local_struct = LocalShapesSDF(
|
|
44
|
+
tiling=[3, 3, 3],
|
|
45
|
+
unit_cell=unit_cell,
|
|
46
|
+
parametrization=param_func,
|
|
47
|
+
bounds=torch.tensor([[-1, -1, -1], [1, 1, 1]])
|
|
48
|
+
)
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
import logging
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
import numpy as _np
|
|
55
|
+
import torch as _torch
|
|
56
|
+
|
|
57
|
+
from .SDF import SDFBase as _SDFBase
|
|
58
|
+
from .SDF import CapBorderDict
|
|
59
|
+
import DeepSDFStruct
|
|
60
|
+
from DeepSDFStruct.lattice_structure import check_tiling_input, transform
|
|
61
|
+
|
|
62
|
+
logger = logging.getLogger(DeepSDFStruct.__name__)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class LocalShapesSDF(_SDFBase):
|
|
66
|
+
"""Helper class to facilitatae the construction of Lattice SDF Structures."""
|
|
67
|
+
|
|
68
|
+
def __init__(
|
|
69
|
+
self,
|
|
70
|
+
tiling: list[int] | int | None = None,
|
|
71
|
+
unit_cell: _SDFBase | None = None,
|
|
72
|
+
parametrization: _torch.nn.Module | None = None,
|
|
73
|
+
bounds=_torch.tensor([[-1.0, -1.0, -1.0], [1.0, 1.0, 1.0]]),
|
|
74
|
+
):
|
|
75
|
+
"""Helper class to facilitatae the construction of microstructures.
|
|
76
|
+
|
|
77
|
+
Parameters
|
|
78
|
+
----------
|
|
79
|
+
deformation_function : spline
|
|
80
|
+
Outer function that describes the contour of the microstructured
|
|
81
|
+
geometry
|
|
82
|
+
tiling : list of integers
|
|
83
|
+
microtiles per parametric dimension
|
|
84
|
+
microtile : SDFBase
|
|
85
|
+
Representation of the building block defined in the unit cube
|
|
86
|
+
parametrization_function : Callable (optional)
|
|
87
|
+
Function to describe spline parameters
|
|
88
|
+
"""
|
|
89
|
+
if not isinstance(parametrization, _torch.nn.Module):
|
|
90
|
+
raise TypeError("Parametrization must be of type _Parametrization")
|
|
91
|
+
check_tiling_input(tiling)
|
|
92
|
+
super().__init__(parametrization=parametrization)
|
|
93
|
+
self.tiling = (
|
|
94
|
+
[tiling] * unit_cell.geometric_dim if isinstance(tiling, int) else tiling
|
|
95
|
+
)
|
|
96
|
+
self.unit_cell = unit_cell
|
|
97
|
+
self.bounds = bounds
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def tiling(self):
|
|
101
|
+
"""Number of microtiles per parametric dimension.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
None
|
|
106
|
+
|
|
107
|
+
Returns
|
|
108
|
+
-------
|
|
109
|
+
tiling : list<int>
|
|
110
|
+
"""
|
|
111
|
+
if hasattr(self, "_tiling"):
|
|
112
|
+
return self._tiling
|
|
113
|
+
else:
|
|
114
|
+
return None
|
|
115
|
+
|
|
116
|
+
@tiling.setter
|
|
117
|
+
def tiling(self, tiling):
|
|
118
|
+
"""Setter for the tiling attribute, defining the number of microtiles
|
|
119
|
+
per parametric dimension.
|
|
120
|
+
|
|
121
|
+
Parameters
|
|
122
|
+
----------
|
|
123
|
+
tiling : int / list<int>
|
|
124
|
+
Number of tiles for each dimension respectively
|
|
125
|
+
Returns
|
|
126
|
+
-------
|
|
127
|
+
None
|
|
128
|
+
"""
|
|
129
|
+
if (
|
|
130
|
+
not isinstance(tiling, list)
|
|
131
|
+
and not isinstance(tiling, int)
|
|
132
|
+
and not isinstance(tiling, tuple)
|
|
133
|
+
):
|
|
134
|
+
raise ValueError(
|
|
135
|
+
"Tiling mus be either list of integers of integer " "value"
|
|
136
|
+
)
|
|
137
|
+
self._tiling = tiling
|
|
138
|
+
|
|
139
|
+
@property
|
|
140
|
+
def unit_cell(self):
|
|
141
|
+
"""Microtile that is either a spline, a list of splines, or a class
|
|
142
|
+
that provides a `create_tile` function."""
|
|
143
|
+
if hasattr(self, "_microtile"):
|
|
144
|
+
return self._microtile
|
|
145
|
+
else:
|
|
146
|
+
self._logi(
|
|
147
|
+
"microtile is empty. "
|
|
148
|
+
"Please checkout splinepy.microstructure.tiles.show() for "
|
|
149
|
+
"predefined tile collections."
|
|
150
|
+
)
|
|
151
|
+
return None
|
|
152
|
+
|
|
153
|
+
@unit_cell.setter
|
|
154
|
+
def unit_cell(self, microtile):
|
|
155
|
+
"""Setter for microtile.
|
|
156
|
+
|
|
157
|
+
Microtile must be either a spline, a list of splines, or a class that
|
|
158
|
+
provides (at least) a `create_tile` function and a `dim` member.
|
|
159
|
+
|
|
160
|
+
Parameters
|
|
161
|
+
----------
|
|
162
|
+
microtile : spline / list<splines> / user-object
|
|
163
|
+
arbitrary long list of splines that define the microtile
|
|
164
|
+
|
|
165
|
+
Returns
|
|
166
|
+
-------
|
|
167
|
+
None
|
|
168
|
+
"""
|
|
169
|
+
# place single tiles into a list to provide common interface
|
|
170
|
+
if not isinstance(microtile, _SDFBase):
|
|
171
|
+
raise TypeError(f"Microtile must be SDF, not {type(microtile)}")
|
|
172
|
+
# Assign Microtile object to member variable
|
|
173
|
+
self._microtile = microtile
|
|
174
|
+
|
|
175
|
+
def _get_domain_bounds(self):
|
|
176
|
+
return self.bounds
|
|
177
|
+
|
|
178
|
+
def _compute(self, samples: _torch.Tensor):
|
|
179
|
+
"""Function, that - if required - parametrizes the microtiles.
|
|
180
|
+
|
|
181
|
+
In order to use said function, the Microtile needs to provide a couple
|
|
182
|
+
of attributes:
|
|
183
|
+
|
|
184
|
+
- evaluation_points - a list of points defined in the unit cube
|
|
185
|
+
that will be evaluated in the parametrization function to provide
|
|
186
|
+
the required set of data points
|
|
187
|
+
- para_dim - dimensionality of the parametrization
|
|
188
|
+
function and number of design variables for said microtile
|
|
189
|
+
|
|
190
|
+
Parameters
|
|
191
|
+
----------
|
|
192
|
+
None
|
|
193
|
+
|
|
194
|
+
Returns
|
|
195
|
+
-------
|
|
196
|
+
: Callable
|
|
197
|
+
Function that describes the local tile parameters
|
|
198
|
+
"""
|
|
199
|
+
if self.parametrization is not None:
|
|
200
|
+
parameters = self.parametrization(samples)
|
|
201
|
+
self.unit_cell._set_param(parameters)
|
|
202
|
+
|
|
203
|
+
queries_transformed = _torch.zeros_like(samples)
|
|
204
|
+
if self.unit_cell.geometric_dim == 2:
|
|
205
|
+
tx, ty = self._tiling
|
|
206
|
+
queries_transformed[:, 0] = transform(
|
|
207
|
+
samples[:, 0], tx, bounds=self.bounds[:, 0]
|
|
208
|
+
)
|
|
209
|
+
queries_transformed[:, 1] = transform(
|
|
210
|
+
samples[:, 1], ty, bounds=self.bounds[:, 1]
|
|
211
|
+
)
|
|
212
|
+
elif self.unit_cell.geometric_dim == 3:
|
|
213
|
+
tx, ty, tz = self._tiling
|
|
214
|
+
queries_transformed[:, 0] = transform(
|
|
215
|
+
samples[:, 0], tx, bounds=self.bounds[:, 0]
|
|
216
|
+
)
|
|
217
|
+
queries_transformed[:, 1] = transform(
|
|
218
|
+
samples[:, 1], ty, bounds=self.bounds[:, 1]
|
|
219
|
+
)
|
|
220
|
+
queries_transformed[:, 2] = transform(
|
|
221
|
+
samples[:, 2], tz, bounds=self.bounds[:, 2]
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
sdf_values = self.unit_cell(queries_transformed)
|
|
225
|
+
|
|
226
|
+
return sdf_values
|