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.
Files changed (165) hide show
  1. DeepSDFStruct/SDF.py +1734 -0
  2. DeepSDFStruct/__init__.py +66 -0
  3. DeepSDFStruct/deep_sdf/__init__.py +69 -0
  4. DeepSDFStruct/deep_sdf/create_screenshots_from_plyfiles.py +65 -0
  5. DeepSDFStruct/deep_sdf/data.py +258 -0
  6. DeepSDFStruct/deep_sdf/metrics/__init__.py +14 -0
  7. DeepSDFStruct/deep_sdf/metrics/mesh_to_analytical.py +24 -0
  8. DeepSDFStruct/deep_sdf/models.py +197 -0
  9. DeepSDFStruct/deep_sdf/networks/__init__.py +8 -0
  10. DeepSDFStruct/deep_sdf/networks/analytic_round_cross.py +105 -0
  11. DeepSDFStruct/deep_sdf/networks/deep_sdf_decoder.py +155 -0
  12. DeepSDFStruct/deep_sdf/networks/hierarchical_deep_sdf_decoder.py +139 -0
  13. DeepSDFStruct/deep_sdf/networks/hierarchical_positional_sdf_decoder.py +190 -0
  14. DeepSDFStruct/deep_sdf/networks/resnet_positional_sdf_decoder.py +108 -0
  15. DeepSDFStruct/deep_sdf/nn_utils.py +70 -0
  16. DeepSDFStruct/deep_sdf/plotting.py +143 -0
  17. DeepSDFStruct/deep_sdf/reconstruction.py +165 -0
  18. DeepSDFStruct/deep_sdf/training.py +840 -0
  19. DeepSDFStruct/deep_sdf/workspace.py +363 -0
  20. DeepSDFStruct/design_of_experiments.py +235 -0
  21. DeepSDFStruct/flexicubes/__init__.py +15 -0
  22. DeepSDFStruct/flexicubes/flexicubes.py +1005 -0
  23. DeepSDFStruct/flexicubes/tables.py +2338 -0
  24. DeepSDFStruct/flexisquares/__init__.py +15 -0
  25. DeepSDFStruct/flexisquares/flexisquares.py +967 -0
  26. DeepSDFStruct/flexisquares/tables.py +63 -0
  27. DeepSDFStruct/lattice_structure.py +254 -0
  28. DeepSDFStruct/local_shapes.py +226 -0
  29. DeepSDFStruct/mesh.py +1184 -0
  30. DeepSDFStruct/optimization.py +357 -0
  31. DeepSDFStruct/parametrization.py +215 -0
  32. DeepSDFStruct/pretrained_models.py +128 -0
  33. DeepSDFStruct/sampling.py +670 -0
  34. DeepSDFStruct/sdf_operations.py +990 -0
  35. DeepSDFStruct/sdf_primitives.py +1416 -0
  36. DeepSDFStruct/splinepy_unitcells/__init__.py +35 -0
  37. DeepSDFStruct/splinepy_unitcells/chi_3D.py +1617 -0
  38. DeepSDFStruct/splinepy_unitcells/cross_lattice.py +165 -0
  39. DeepSDFStruct/splinepy_unitcells/double_lattice_extruded.py +298 -0
  40. DeepSDFStruct/splinepy_unitcells/snappy_3d.py +544 -0
  41. DeepSDFStruct/torch_spline.py +446 -0
  42. DeepSDFStruct/trained_models/analytic_round_cross/LatentCodes/latest.pth +0 -0
  43. DeepSDFStruct/trained_models/analytic_round_cross/ModelParameters/latest.pth +0 -0
  44. DeepSDFStruct/trained_models/analytic_round_cross/OptimizerParameters/latest.pth +0 -0
  45. DeepSDFStruct/trained_models/analytic_round_cross/specs.json +45 -0
  46. DeepSDFStruct/trained_models/chi_and_cross/LatentCodes/latest.pth +0 -0
  47. DeepSDFStruct/trained_models/chi_and_cross/Logs.pth +0 -0
  48. DeepSDFStruct/trained_models/chi_and_cross/ModelParameters/latest.pth +0 -0
  49. DeepSDFStruct/trained_models/chi_and_cross/OptimizerParameters/latest.pth +0 -0
  50. DeepSDFStruct/trained_models/chi_and_cross/specs.json +76 -0
  51. DeepSDFStruct/trained_models/primitives/LatentCodes/latest.pth +0 -0
  52. DeepSDFStruct/trained_models/primitives/ModelParameters/latest.pth +0 -0
  53. DeepSDFStruct/trained_models/primitives/OptimizerParameters/latest.pth +0 -0
  54. DeepSDFStruct/trained_models/primitives/specs.json +46 -0
  55. DeepSDFStruct/trained_models/primitives_2d/LatentCodes/latest.pth +0 -0
  56. DeepSDFStruct/trained_models/primitives_2d/ModelParameters/latest.pth +0 -0
  57. DeepSDFStruct/trained_models/primitives_2d/OptimizerParameters/latest.pth +0 -0
  58. DeepSDFStruct/trained_models/primitives_2d/specs.json +46 -0
  59. DeepSDFStruct/trained_models/round_cross/LatentCodes/latest.pth +0 -0
  60. DeepSDFStruct/trained_models/round_cross/Logs.pth +0 -0
  61. DeepSDFStruct/trained_models/round_cross/ModelParameters/latest.pth +0 -0
  62. DeepSDFStruct/trained_models/round_cross/OptimizerParameters/latest.pth +0 -0
  63. DeepSDFStruct/trained_models/round_cross/specs.json +45 -0
  64. DeepSDFStruct/trained_models/test_experiment/LatentCodes/latent_code_data_map.json +106 -0
  65. DeepSDFStruct/trained_models/test_experiment/specs.json +45 -0
  66. DeepSDFStruct/trained_models/test_experiment/training_summary.json +10 -0
  67. DeepSDFStruct/trained_models/test_experiment_hierarchical/LatentCodes/latent_code_data_map.json +106 -0
  68. DeepSDFStruct/trained_models/test_experiment_hierarchical/specs.json +45 -0
  69. DeepSDFStruct/trained_models/test_experiment_hierarchical/training_summary.json +10 -0
  70. DeepSDFStruct/trained_models/test_experiment_homogenization/LatentCodes/latent_code_data_map.json +5006 -0
  71. DeepSDFStruct/trained_models/test_experiment_homogenization/LatentCodes/latest.pth +0 -0
  72. DeepSDFStruct/trained_models/test_experiment_homogenization/Logs.png +0 -0
  73. DeepSDFStruct/trained_models/test_experiment_homogenization/ModelParameters/latest.pth +0 -0
  74. DeepSDFStruct/trained_models/test_experiment_homogenization/OptimizerParameters/latest.pth +0 -0
  75. DeepSDFStruct/trained_models/test_experiment_homogenization/specs.json +83 -0
  76. DeepSDFStruct/trained_models/test_experiment_homogenization/training_summary.json +10 -0
  77. DeepSDFStruct/utils.py +96 -0
  78. DeepSDFStruct/visualization/latent_viewer.py +211 -0
  79. DeepSDFStruct/visualization/latent_viewer_cli.py +8 -0
  80. benchmarks/generate_sdf_showcase.py +622 -0
  81. benchmarks/sdf_from_mesh_benchmark.py +52 -0
  82. benchmarks/sdf_from_mesh_comparison.md +33 -0
  83. benchmarks/sdf_showcase/operations/boolean/difference_sphere_box.png +0 -0
  84. benchmarks/sdf_showcase/operations/boolean/union_sphere_box.png +0 -0
  85. benchmarks/sdf_showcase/operations/transformations/circular_array_sphere.png +0 -0
  86. benchmarks/sdf_showcase/operations/transformations/dilate_sphere.png +0 -0
  87. benchmarks/sdf_showcase/operations/transformations/mirror_sphere.png +0 -0
  88. benchmarks/sdf_showcase/operations/transformations/repeat_sphere.png +0 -0
  89. benchmarks/sdf_showcase/operations/transformations/revolve_circle.png +0 -0
  90. benchmarks/sdf_showcase/operations/transformations/shell_sphere.png +0 -0
  91. benchmarks/sdf_showcase/operations/transformations/twist_torus.png +0 -0
  92. benchmarks/sdf_showcase/primitives/2D/circle.png +0 -0
  93. benchmarks/sdf_showcase/primitives/2D/equilateral_triangle.png +0 -0
  94. benchmarks/sdf_showcase/primitives/2D/hexagon.png +0 -0
  95. benchmarks/sdf_showcase/primitives/2D/polygon_pentagon.png +0 -0
  96. benchmarks/sdf_showcase/primitives/2D/rectangle.png +0 -0
  97. benchmarks/sdf_showcase/primitives/2D/rounded_rectangle.png +0 -0
  98. benchmarks/sdf_showcase/primitives/3D/box.png +0 -0
  99. benchmarks/sdf_showcase/primitives/3D/capped_cone.png +0 -0
  100. benchmarks/sdf_showcase/primitives/3D/capped_cylinder.png +0 -0
  101. benchmarks/sdf_showcase/primitives/3D/capsule.png +0 -0
  102. benchmarks/sdf_showcase/primitives/3D/cone.png +0 -0
  103. benchmarks/sdf_showcase/primitives/3D/corner_spheres.png +0 -0
  104. benchmarks/sdf_showcase/primitives/3D/cross_ms.png +0 -0
  105. benchmarks/sdf_showcase/primitives/3D/cylinder.png +0 -0
  106. benchmarks/sdf_showcase/primitives/3D/dodecahedron.png +0 -0
  107. benchmarks/sdf_showcase/primitives/3D/ellipsoid.png +0 -0
  108. benchmarks/sdf_showcase/primitives/3D/icosahedron.png +0 -0
  109. benchmarks/sdf_showcase/primitives/3D/octahedron.png +0 -0
  110. benchmarks/sdf_showcase/primitives/3D/pyramid.png +0 -0
  111. benchmarks/sdf_showcase/primitives/3D/rounded_box.png +0 -0
  112. benchmarks/sdf_showcase/primitives/3D/rounded_cone.png +0 -0
  113. benchmarks/sdf_showcase/primitives/3D/rounded_cylinder.png +0 -0
  114. benchmarks/sdf_showcase/primitives/3D/sphere.png +0 -0
  115. benchmarks/sdf_showcase/primitives/3D/tetrahedron.png +0 -0
  116. benchmarks/sdf_showcase/primitives/3D/torus.png +0 -0
  117. benchmarks/sdf_showcase/primitives/3D/wireframe_box.png +0 -0
  118. deepsdfstruct-1.7.2.dist-info/METADATA +44 -0
  119. deepsdfstruct-1.7.2.dist-info/RECORD +165 -0
  120. deepsdfstruct-1.7.2.dist-info/WHEEL +5 -0
  121. deepsdfstruct-1.7.2.dist-info/licenses/LICENSE +208 -0
  122. deepsdfstruct-1.7.2.dist-info/licenses/NOTICE +67 -0
  123. deepsdfstruct-1.7.2.dist-info/scm_file_list.json +178 -0
  124. deepsdfstruct-1.7.2.dist-info/scm_version.json +8 -0
  125. deepsdfstruct-1.7.2.dist-info/top_level.txt +4 -0
  126. docs/Makefile +20 -0
  127. docs/api_reference.rst +6 -0
  128. docs/conf.py +60 -0
  129. docs/index.rst +136 -0
  130. docs/make.bat +35 -0
  131. docs/qr_code_github.png +0 -0
  132. docs/qr_code_paper.png +0 -0
  133. docs/readme_images/example_output_01.png +0 -0
  134. docs/readme_images/example_output_02.png +0 -0
  135. docs/readme_images/example_output_03.png +0 -0
  136. docs/readme_images/example_output_04.png +0 -0
  137. tests/data/chairs/1005.obj +282 -0
  138. tests/data/chairs/1024.obj +222 -0
  139. tests/data/chairs/README.md +1 -0
  140. tests/data/circular_balls_test_case.stl +0 -0
  141. tests/data/cone.stl +1794 -0
  142. tests/data/example_disconnectd_mesh.inp +1784 -0
  143. tests/data/example_line_mesh.vtk +0 -0
  144. tests/data/stanford_bunny.stl +0 -0
  145. tests/data/sweep_test_case.stl +0 -0
  146. tests/test_DOE.py +49 -0
  147. tests/test_elongate_sdf.py +195 -0
  148. tests/test_flexisquares.py +187 -0
  149. tests/test_generate_dataset.py +76 -0
  150. tests/test_lattice_evaluation.py +137 -0
  151. tests/test_mesh_export.py +137 -0
  152. tests/test_mesh_functions.py +49 -0
  153. tests/test_networks.py +71 -0
  154. tests/test_pretrained_models.py +40 -0
  155. tests/test_reconstruction.py +101 -0
  156. tests/test_sdf_from_mesh.py +52 -0
  157. tests/test_sdf_functions.py +117 -0
  158. tests/test_sdf_primitives.py +668 -0
  159. tests/test_sdf_trimesh_comparison.py +482 -0
  160. tests/test_splinepy_unitcells.py +64 -0
  161. tests/test_structural_optimization.py +178 -0
  162. tests/test_torch_spline.py +216 -0
  163. tests/test_train_model.py +110 -0
  164. tests/test_training_data_ids.py +41 -0
  165. tests/tmp_outputs/temp_file.txt +0 -0
@@ -0,0 +1,70 @@
1
+ import torch
2
+ import torch.nn as nn
3
+
4
+ activations = {
5
+ "relu": nn.ReLU(),
6
+ "tanh": nn.Tanh(),
7
+ "gelu": nn.GELU(),
8
+ "silu": nn.SiLU(),
9
+ "leaky_relu": nn.LeakyReLU(),
10
+ "elu": nn.ELU(),
11
+ "selu": nn.SELU(),
12
+ "sigmoid": nn.Sigmoid(),
13
+ "softplus": nn.Softplus(),
14
+ }
15
+
16
+
17
+ class ClampedL1Loss(torch.nn.Module):
18
+ def __init__(self, clamp_val=0.1):
19
+ super().__init__()
20
+ self.clamp_val = clamp_val
21
+ self.loss = torch.nn.L1Loss()
22
+
23
+ def forward(self, input, target):
24
+ input_clamped = input.clamp(-self.clamp_val, self.clamp_val)
25
+ target_clamped = target.clamp(-self.clamp_val, self.clamp_val)
26
+ return self.loss(input_clamped, target_clamped)
27
+
28
+
29
+ class LeakyClampedL1Loss(torch.nn.Module):
30
+ """L1 loss that clamps values within [-clamp_val, clamp_val], but applies a
31
+ leaky linear continuation outside that range instead of hard clamping.
32
+
33
+ This behaves like a `clamp` in the center and a `LeakyReLU`-style slope
34
+ outside. Both input and target are transformed the same way before L1.
35
+ """
36
+
37
+ def __init__(self, clamp_val=0.1, leak=0.01):
38
+ super().__init__()
39
+ self.clamp_val = clamp_val
40
+ self.leak = leak
41
+ self.loss = torch.nn.L1Loss()
42
+
43
+ def _leaky_clamp(self, x: torch.Tensor) -> torch.Tensor:
44
+ cv = self.clamp_val
45
+ lk = self.leak
46
+ # If x > c -> c + l*(x-c); if x < -c -> -c + l*(x + c); else x
47
+ pos = torch.where(x > cv, cv + lk * (x - cv), x)
48
+ out = torch.where(pos < -cv, -cv + lk * (pos + cv), pos)
49
+ return out
50
+
51
+ def forward(self, input, target):
52
+ input_trans = self._leaky_clamp(input)
53
+ target_trans = self._leaky_clamp(target)
54
+ return self.loss(input_trans, target_trans)
55
+
56
+
57
+ def get_loss_function(loss_fun_spec: str):
58
+ """Return a loss function instance for the given spec string."""
59
+ if loss_fun_spec == "clampedL1":
60
+ return ClampedL1Loss()
61
+ elif loss_fun_spec == "leakyClampedL1":
62
+ return LeakyClampedL1Loss()
63
+ elif loss_fun_spec == "L1":
64
+ return torch.nn.L1Loss()
65
+ elif loss_fun_spec == "MSE":
66
+ return torch.nn.MSELoss()
67
+ elif loss_fun_spec == "huber":
68
+ return torch.nn.HuberLoss()
69
+ else:
70
+ raise ValueError(f"Unsupported loss function: {loss_fun_spec}")
@@ -0,0 +1,143 @@
1
+ """
2
+ Training Visualization and Logging
3
+ ==================================
4
+
5
+ This module provides utilities for visualizing DeepSDF training progress
6
+ and generating plots of training metrics.
7
+
8
+ Functions
9
+ ---------
10
+
11
+ plot_logs
12
+ Plot training loss curves with smoothing and optional learning rate overlay.
13
+ Useful for monitoring training progress and diagnosing convergence issues.
14
+
15
+ plot_reconstruction_loss
16
+ Visualize loss during shape reconstruction, showing how well the model
17
+ fits to target geometries.
18
+
19
+ extract_paths
20
+ Helper for extracting file paths from nested data structures.
21
+
22
+ running_mean
23
+ Compute running average for smoothing noisy loss curves.
24
+
25
+ The module integrates with the workspace utilities to load training logs
26
+ and generate publication-quality plots for analysis and presentation.
27
+ """
28
+
29
+ import numpy as np
30
+ import os
31
+ import logging
32
+ import torch
33
+ import matplotlib.pyplot as plt
34
+
35
+ import DeepSDFStruct.deep_sdf.workspace as ws
36
+
37
+ logger = logging.getLogger(__name__)
38
+
39
+
40
+ def extract_paths(data, current_path=""):
41
+ paths = []
42
+
43
+ if isinstance(data, dict):
44
+ for key, value in data.items():
45
+ new_path = f"{current_path}/{key}" if current_path else key
46
+ paths.extend(extract_paths(value, new_path))
47
+
48
+ elif isinstance(data, list):
49
+ for item in data:
50
+ paths.extend(extract_paths(item, current_path))
51
+
52
+ else:
53
+ paths.append(f"{current_path}/{data}")
54
+
55
+ return paths
56
+
57
+
58
+ def running_mean(x, N):
59
+ cumsum = np.cumsum(np.insert(x, 0, 0))
60
+ return (cumsum[N:] - cumsum[:-N]) / float(N)
61
+
62
+
63
+ def plot_logs(experiment_directory, show_lr=False, ax=None, filename=None):
64
+
65
+ logs = torch.load(os.path.join(experiment_directory, ws.logs_filename))
66
+
67
+ num_iters = len(logs["loss"])
68
+ iters_per_epoch = num_iters / logs["epoch"]
69
+
70
+ smoothed_loss_41 = running_mean(logs["loss"], 41)
71
+
72
+ show_plt = False
73
+
74
+ if show_lr:
75
+ if ax is None:
76
+ fig, ax = plt.subplots(2, 1)
77
+ fig.tight_layout()
78
+ show_plt = True
79
+ else:
80
+ if ax is None:
81
+ fig, ax = plt.subplots()
82
+ show_plt = True
83
+ ax = [ax]
84
+
85
+ ax[0].plot(
86
+ np.arange(num_iters) / iters_per_epoch,
87
+ logs["loss"],
88
+ "#82c6eb",
89
+ np.arange(20, num_iters - 20) / iters_per_epoch,
90
+ smoothed_loss_41,
91
+ "#2a9edd",
92
+ )
93
+ ax[0].set_yscale("log")
94
+
95
+ ax[0].set(xlabel="Epoch", ylabel="Loss")
96
+ ax[0].legend(["Loss", "Loss (Running Mean)", "Loss (Running Mean 41)"])
97
+
98
+ if show_lr:
99
+ combined_lrs = np.array(logs["learning_rate"])
100
+ ax[1].plot(
101
+ np.arange(combined_lrs.shape[0]),
102
+ combined_lrs[:, 0],
103
+ np.arange(combined_lrs.shape[0]),
104
+ combined_lrs[:, 1],
105
+ )
106
+ ax[1].set(xlabel="Epoch", ylabel="Learning Rate")
107
+ ax[1].legend(["Decoder", "Latent Vector"])
108
+
109
+ for axis in ax:
110
+ axis.grid()
111
+ if filename is not None:
112
+ plt.savefig(filename, bbox_inches="tight")
113
+ plt.close()
114
+ elif show_plt:
115
+ plt.show()
116
+
117
+
118
+ def plot_reconstruction_loss(loss_history, iters_per_epoch, filename=None):
119
+
120
+ losses = np.array(loss_history)
121
+ num_iters = len(losses)
122
+
123
+ latest_epoch = num_iters / iters_per_epoch
124
+ logger.info("latest epoch is {}".format(latest_epoch))
125
+ logger.info("{} iters per epoch".format(iters_per_epoch))
126
+
127
+ smoothed_loss_41 = running_mean(losses, 41)
128
+
129
+ fig, ax = plt.subplots()
130
+
131
+ ax.plot(
132
+ np.arange(num_iters) / iters_per_epoch,
133
+ losses,
134
+ "#82c6eb",
135
+ np.arange(20, num_iters - 20) / iters_per_epoch,
136
+ smoothed_loss_41,
137
+ "#2a9edd",
138
+ )
139
+ ax.set_yscale("log")
140
+ ax.set(xlabel="Epoch", ylabel="Loss")
141
+ ax.legend(["Loss", "Loss (Running Mean 41)"])
142
+ ax.grid()
143
+ plt.savefig(filename, bbox_inches="tight")
@@ -0,0 +1,165 @@
1
+ """
2
+ Shape Reconstruction and Latent Code Optimization
3
+ =================================================
4
+
5
+ This module provides methods for reconstructing shapes from SDF samples
6
+ by optimizing latent codes. This is a key capability of DeepSDF models,
7
+ enabling fitting of new geometries not seen during training.
8
+
9
+ Key Functions
10
+ -------------
11
+
12
+ reconstruct_from_samples
13
+ Optimize a latent code to match given SDF samples. Uses gradient
14
+ descent to find the latent representation that best reproduces
15
+ the target geometry.
16
+
17
+ The reconstruction process:
18
+ 1. Start with initial latent code (often zeros or random)
19
+ 2. Forward pass through decoder to get SDF predictions
20
+ 3. Compute loss between predictions and target samples
21
+ 4. Backpropagate and update latent code
22
+ 5. Repeat until convergence
23
+
24
+ This enables:
25
+ - Fitting trained models to new geometries
26
+ - Shape interpolation by blending latent codes
27
+ - Shape editing by modifying latent codes
28
+ - Compression by storing only latent codes
29
+
30
+ Examples
31
+ --------
32
+ Reconstruct a shape from samples::
33
+
34
+ from DeepSDFStruct.deep_sdf.reconstruction import reconstruct_from_samples
35
+ from DeepSDFStruct.sampling import sample_sdf_near_surface
36
+
37
+ # Sample target geometry
38
+ target_samples = sample_sdf_near_surface(target_sdf, n_samples=100000)
39
+
40
+ # Reconstruct using trained model
41
+ reconstructed_sdf = reconstruct_from_samples(
42
+ model,
43
+ target_samples,
44
+ num_iterations=1000,
45
+ lr=5e-4
46
+ )
47
+ """
48
+
49
+ from DeepSDFStruct.SDF import SDFBase
50
+ from DeepSDFStruct.deep_sdf.nn_utils import ClampedL1Loss
51
+ from torch.utils.data import TensorDataset, DataLoader
52
+ from DeepSDFStruct.sampling import SampledSDF
53
+ from DeepSDFStruct.deep_sdf.plotting import plot_reconstruction_loss
54
+ from DeepSDFStruct.torch_spline import TorchSpline, TorchScaling
55
+ from tqdm import trange
56
+ import torch
57
+ import torch.nn as nn
58
+
59
+
60
+ def reconstruct_from_samples(
61
+ sdf: SDFBase,
62
+ sdfSample: SampledSDF,
63
+ num_iterations=1000,
64
+ lr=5e-4,
65
+ loss_fn="ClampedL1",
66
+ batch_size=512,
67
+ drop_last=True,
68
+ use_tanh_on_gt=False,
69
+ loss_plot_path=None,
70
+ optimizer_name="adam",
71
+ deformation_function=None | TorchSpline | TorchScaling,
72
+ ):
73
+ if optimizer_name == "adam":
74
+ optimizer = torch.optim.Adam(sdf.parameters(), lr=lr)
75
+ elif optimizer_name == "lbfgs":
76
+ optimizer = torch.optim.LBFGS(
77
+ sdf.parameters(),
78
+ lr=lr,
79
+ max_iter=20, # inner Newton iterations
80
+ history_size=100, # curvature memory
81
+ line_search_fn="strong_wolfe",
82
+ )
83
+ else:
84
+ raise NotImplementedError(f"Optimizer {optimizer_name} not available.")
85
+
86
+ verts_min = sdfSample.samples.min(axis=0)
87
+ verts_max = sdfSample.samples.max(axis=0)
88
+
89
+ print("Min/Max in PHYSICAL space:\n")
90
+ for name, mn, mx in zip(["x", "y", "z"], verts_min.values, verts_max.values):
91
+ print(f"{name}: min={mn:.6f}, max={mx:.6f}")
92
+
93
+ if deformation_function is not None:
94
+ queries_parameter_space = deformation_function.inverse_target_points(
95
+ sdfSample.samples
96
+ ).detach()
97
+ else:
98
+ queries_parameter_space = sdfSample.samples.detach()
99
+
100
+ queries_min = queries_parameter_space.min(dim=0).values
101
+ queries_max = queries_parameter_space.max(dim=0).values
102
+
103
+ print("\nMin/Max in QUERY space:\n")
104
+ for name, mn, mx in zip(
105
+ ["x", "y", "z"], queries_min.tolist(), queries_max.tolist()
106
+ ):
107
+ print(f"{name}: min={mn:.6f}, max={mx:.6f}")
108
+
109
+ gt_dist = sdfSample.distances
110
+ if use_tanh_on_gt:
111
+ gt_dist = torch.tanh(gt_dist)
112
+
113
+ pbar = trange(num_iterations, desc="Reconstructing SDF from mesh", leave=True)
114
+
115
+ if loss_fn == "L1":
116
+ Loss = torch.nn.L1Loss()
117
+ elif loss_fn == "ClampedL1":
118
+ Loss = ClampedL1Loss(clamp_val=0.1)
119
+ elif loss_fn == "MSE":
120
+ Loss = torch.nn.MSELoss()
121
+ else:
122
+ raise NotImplementedError(f"Loss function {loss_fn} not available.")
123
+
124
+ dataset = TensorDataset(queries_parameter_space, gt_dist)
125
+ if drop_last and (batch_size > len(dataset)):
126
+ print(
127
+ "Warning: drop_last was set to true, "
128
+ f"but batch size ({batch_size}) is larger "
129
+ f"than the size of the dataset ({len(dataset)})."
130
+ " setting drop_last=False"
131
+ )
132
+ drop_last = False
133
+ dataloader = DataLoader(
134
+ dataset, batch_size=batch_size, shuffle=True, drop_last=drop_last
135
+ )
136
+
137
+ loss_history = []
138
+ for e in pbar:
139
+ for querie_batch, gt_batch in dataloader:
140
+
141
+ def closure() -> torch.Tensor:
142
+ optimizer.zero_grad()
143
+ pred_dist = sdf(querie_batch)
144
+ loss = Loss(pred_dist, gt_batch)
145
+ loss.backward()
146
+ return loss
147
+
148
+ if optimizer_name == "adam":
149
+ loss = closure()
150
+ optimizer.step()
151
+ elif optimizer_name == "lbfgs":
152
+ loss = optimizer.step(closure)
153
+ loss_num = loss.detach().item()
154
+ pbar.set_postfix({"loss": f"{loss_num:.5f}"})
155
+ loss_history.append(loss_num)
156
+
157
+ if loss_plot_path is not None:
158
+ plot_reconstruction_loss(
159
+ loss_history, iters_per_epoch=len(dataloader), filename=loss_plot_path
160
+ )
161
+
162
+ params = list(sdf.parameters())
163
+ print(params)
164
+
165
+ return params