diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f4737e0cc..b39921ca5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,18 +18,18 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.15.13 + rev: v0.15.22 hooks: - id: ruff-check args: - --fix - id: ruff-format - repo: https://github.com/oxc-project/mirrors-oxfmt - rev: v0.50.0 + rev: v0.45.0 hooks: - id: oxfmt - repo: https://github.com/oxc-project/mirrors-oxlint - rev: v1.65.0 + rev: v1.60.0 hooks: - id: oxlint - repo: https://github.com/pre-commit/pre-commit-hooks @@ -52,7 +52,7 @@ repos: hooks: - id: actionlint - repo: https://github.com/rvben/rumdl-pre-commit - rev: v0.1.93 + rev: v0.2.37 hooks: - id: rumdl-fmt - repo: https://github.com/shellcheck-py/shellcheck-py diff --git a/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-easy-metrics.json b/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-easy-metrics.json index 18b901c7e..39971bce3 100644 --- a/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-easy-metrics.json +++ b/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-easy-metrics.json @@ -26,4 +26,4 @@ "forward_best_objective": 1481.1424852869957, "finite_outputs": true } -] \ No newline at end of file +] diff --git a/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-easy.json b/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-easy.json index c061b297c..94d53e89e 100644 --- a/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-easy.json +++ b/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-easy.json @@ -38,4 +38,4 @@ "adjoint-relative-residual": "/home/liblaf/github/liblaf/apple/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-easy-metrics-adjoint-relative-residual.png", "inverse-grad-absolute": "/home/liblaf/github/liblaf/apple/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-easy-metrics-inverse-grad-absolute.png" } -} \ No newline at end of file +} diff --git a/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-zero-metrics.json b/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-zero-metrics.json index e3eae723a..ed4812d40 100644 --- a/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-zero-metrics.json +++ b/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-zero-metrics.json @@ -404,4 +404,4 @@ "forward_best_objective": 1485.5675728610533, "finite_outputs": true } -] \ No newline at end of file +] diff --git a/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-zero.json b/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-zero.json index dc9f6ea0e..2f7ccd935 100644 --- a/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-zero.json +++ b/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-zero.json @@ -43,4 +43,4 @@ "adjoint-relative-residual": "/home/liblaf/github/liblaf/apple/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-zero-metrics-adjoint-relative-residual.png", "inverse-grad-absolute": "/home/liblaf/github/liblaf/apple/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean-zero-metrics-inverse-grad-absolute.png" } -} \ No newline at end of file +} diff --git a/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean.json b/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean.json index d95032cbc..541e835f1 100644 --- a/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean.json +++ b/exp/2026/01/28/smas/data/31-inverse-smas46-muscle46-activation-stable-neo-hookean.json @@ -88,4 +88,4 @@ } } ] -} \ No newline at end of file +} diff --git a/exp/2026/05/20/inverse-face/data/20-inverse-face-3152k-summary.json b/exp/2026/05/20/inverse-face/data/20-inverse-face-3152k-summary.json index c72671419..48ca2367c 100644 --- a/exp/2026/05/20/inverse-face/data/20-inverse-face-3152k-summary.json +++ b/exp/2026/05/20/inverse-face/data/20-inverse-face-3152k-summary.json @@ -136,4 +136,4 @@ "repeated/forward_failure": false, "repeated/adjoint_failure": false, "passed": true -} \ No newline at end of file +} diff --git a/exp/2026/05/20/inverse-face/data/20-inverse-face-fresh-nu049-smas1-noclamp-super-loose-reg-summary.json b/exp/2026/05/20/inverse-face/data/20-inverse-face-fresh-nu049-smas1-noclamp-super-loose-reg-summary.json index 7f2af9301..5e39a8d43 100644 --- a/exp/2026/05/20/inverse-face/data/20-inverse-face-fresh-nu049-smas1-noclamp-super-loose-reg-summary.json +++ b/exp/2026/05/20/inverse-face/data/20-inverse-face-fresh-nu049-smas1-noclamp-super-loose-reg-summary.json @@ -16721,4 +16721,4 @@ "repeated/forward_failure": false, "repeated/adjoint_failure": false, "passed": true -} \ No newline at end of file +} diff --git a/exp/2026/05/20/inverse-face/data/20-inverse-face-summary.json b/exp/2026/05/20/inverse-face/data/20-inverse-face-summary.json index 31070dead..ebdafb629 100644 --- a/exp/2026/05/20/inverse-face/data/20-inverse-face-summary.json +++ b/exp/2026/05/20/inverse-face/data/20-inverse-face-summary.json @@ -125,4 +125,4 @@ "repeated/forward_failure": false, "repeated/adjoint_failure": false, "passed": true -} \ No newline at end of file +} diff --git a/exp/2026/05/20/inverse-face/data/30-transfer-activation-3152k-summary.json b/exp/2026/05/20/inverse-face/data/30-transfer-activation-3152k-summary.json index 112c021e3..d07d13a71 100644 --- a/exp/2026/05/20/inverse-face/data/30-transfer-activation-3152k-summary.json +++ b/exp/2026/05/20/inverse-face/data/30-transfer-activation-3152k-summary.json @@ -57,4 +57,4 @@ "forward/line_search_steps": 0, "forward/stagnation_count": 0, "time/forward_s": 16.038381466001738 -} \ No newline at end of file +} diff --git a/exp/2026/05/20/inverse-face/data/31-transfer-activation-3152k-smas1-summary.json b/exp/2026/05/20/inverse-face/data/31-transfer-activation-3152k-smas1-summary.json index 88e5908c8..26b87edcf 100644 --- a/exp/2026/05/20/inverse-face/data/31-transfer-activation-3152k-smas1-summary.json +++ b/exp/2026/05/20/inverse-face/data/31-transfer-activation-3152k-smas1-summary.json @@ -57,4 +57,4 @@ "forward/line_search_steps": 0, "forward/stagnation_count": 0, "time/forward_s": 6.737611743999878 -} \ No newline at end of file +} diff --git a/exp/2026/05/20/inverse-face/data/40-transfer-activation-515k-smas100-summary.json b/exp/2026/05/20/inverse-face/data/40-transfer-activation-515k-smas100-summary.json index 8a94d6b97..ce007c5f4 100644 --- a/exp/2026/05/20/inverse-face/data/40-transfer-activation-515k-smas100-summary.json +++ b/exp/2026/05/20/inverse-face/data/40-transfer-activation-515k-smas100-summary.json @@ -57,4 +57,4 @@ "forward/line_search_steps": 0, "forward/stagnation_count": 0, "time/forward_s": 3.82475233200239 -} \ No newline at end of file +} diff --git a/exp/2026/05/20/inverse-face/data/41-transfer-activation-515k-smas1-summary.json b/exp/2026/05/20/inverse-face/data/41-transfer-activation-515k-smas1-summary.json index ca81a08ec..b24ce90cc 100644 --- a/exp/2026/05/20/inverse-face/data/41-transfer-activation-515k-smas1-summary.json +++ b/exp/2026/05/20/inverse-face/data/41-transfer-activation-515k-smas1-summary.json @@ -57,4 +57,4 @@ "forward/line_search_steps": 0, "forward/stagnation_count": 0, "time/forward_s": 3.6330396700068377 -} \ No newline at end of file +} diff --git a/exp/2026/05/20/inverse-face/data/42-transfer-activation-3152k-smas100-summary.json b/exp/2026/05/20/inverse-face/data/42-transfer-activation-3152k-smas100-summary.json index 5bc1f9207..a83e3f59c 100644 --- a/exp/2026/05/20/inverse-face/data/42-transfer-activation-3152k-smas100-summary.json +++ b/exp/2026/05/20/inverse-face/data/42-transfer-activation-3152k-smas100-summary.json @@ -57,4 +57,4 @@ "forward/line_search_steps": 0, "forward/stagnation_count": 0, "time/forward_s": 4.520490328024607 -} \ No newline at end of file +} diff --git a/exp/2026/05/20/inverse-face/data/43-transfer-activation-3152k-smas1-summary.json b/exp/2026/05/20/inverse-face/data/43-transfer-activation-3152k-smas1-summary.json index 40b9e0d5e..0da3a73a5 100644 --- a/exp/2026/05/20/inverse-face/data/43-transfer-activation-3152k-smas1-summary.json +++ b/exp/2026/05/20/inverse-face/data/43-transfer-activation-3152k-smas1-summary.json @@ -57,4 +57,4 @@ "forward/line_search_steps": 0, "forward/stagnation_count": 0, "time/forward_s": 6.646797652996611 -} \ No newline at end of file +} diff --git a/exp/2026/05/20/inverse-face/docs/40-transfer-activation-matrix.md b/exp/2026/05/20/inverse-face/docs/40-transfer-activation-matrix.md index 0aeca9e25..2a24f0793 100644 --- a/exp/2026/05/20/inverse-face/docs/40-transfer-activation-matrix.md +++ b/exp/2026/05/20/inverse-face/docs/40-transfer-activation-matrix.md @@ -29,7 +29,7 @@ The four concrete cases were: ## Results | case | cells | active tets | steps | target mean cm | target RMS cm | target max cm | all RMS cm | all max cm | forward s | -|---|---:|---:|---:|---:|---:|---:|---:|---:|---:| +| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | | 515k, SMAS 100 | 253876 | 58494 | 421 | 0.422151 | 0.475055 | 1.297573 | 0.368954 | 9.127733 | 3.825 | | 515k, SMAS 1 | 253876 | 58494 | 244 | 0.274502 | 0.318913 | 0.942866 | 0.243835 | 1.195187 | 3.633 | | 3152k, SMAS 100 | 1127541 | 283391 | 82 | 0.242941 | 0.309361 | 1.033624 | 0.200444 | 3.558038 | 4.520 | diff --git a/exp/2026/05/20/inverse-face/src/10-prepare-inverse-face.py b/exp/2026/05/20/inverse-face/src/10-prepare-inverse-face.py index 9ae98d0fb..e5b0e0917 100644 --- a/exp/2026/05/20/inverse-face/src/10-prepare-inverse-face.py +++ b/exp/2026/05/20/inverse-face/src/10-prepare-inverse-face.py @@ -123,7 +123,9 @@ def add_material_fields(mesh: pv.UnstructuredGrid, cfg: Config) -> None: zero_activation_fields(mesh) -def fixed_point_mask(mesh: pv.UnstructuredGrid, cfg: Config) -> tuple[np.ndarray, dict[str, int]]: +def fixed_point_mask( + mesh: pv.UnstructuredGrid, cfg: Config +) -> tuple[np.ndarray, dict[str, int]]: fixed = np.zeros(mesh.n_points, dtype=bool) counts: dict[str, int] = {} for name in cfg.fixed_point_masks: @@ -222,8 +224,12 @@ def metric_summary( "n_active_tets": int(np.asarray(mesh.cell_data["ActivationMask"]).sum()), "n_target_points": int(target_mask.sum()), "n_fixed_points": int(np.asarray(mesh.point_data["FixedBoundary"]).sum()), - "n_fixed_cranium_points": int(np.asarray(mesh.point_data["FixedCranium"]).sum()), - "n_fixed_mandible_points": int(np.asarray(mesh.point_data["FixedMandible"]).sum()), + "n_fixed_cranium_points": int( + np.asarray(mesh.point_data["FixedCranium"]).sum() + ), + "n_fixed_mandible_points": int( + np.asarray(mesh.point_data["FixedMandible"]).sum() + ), "muscle_fraction_volume": float(np.sum(muscle * volume)), "smas_fraction_volume": float(np.sum(smas * volume)), "target_displacement_mean": float(target_norm.mean()), diff --git a/exp/2026/05/27/forward-face/data/20-forward-face-3152k-a087-summary.json b/exp/2026/05/27/forward-face/data/20-forward-face-3152k-a087-summary.json index 70a9d80fb..4d107a992 100644 --- a/exp/2026/05/27/forward-face/data/20-forward-face-3152k-a087-summary.json +++ b/exp/2026/05/27/forward-face/data/20-forward-face-3152k-a087-summary.json @@ -56,4 +56,4 @@ "IsLipBottom/target_rms": 0.3993310920970844, "IsLipBottom/target_max": 1.0284059764202034, "IsLipBottom/rms_ratio_to_target": 0.30975080437456287 -} \ No newline at end of file +} diff --git a/exp/2026/05/27/forward-face/data/20-forward-face-3152k-expr001-smas100-rerun-summary.json b/exp/2026/05/27/forward-face/data/20-forward-face-3152k-expr001-smas100-rerun-summary.json index 2615451e4..f9105a622 100644 --- a/exp/2026/05/27/forward-face/data/20-forward-face-3152k-expr001-smas100-rerun-summary.json +++ b/exp/2026/05/27/forward-face/data/20-forward-face-3152k-expr001-smas100-rerun-summary.json @@ -57,4 +57,4 @@ "IsLipBottom/target_rms": 0.5516204314457805, "IsLipBottom/target_max": 1.2535219973603913, "IsLipBottom/rms_ratio_to_target": 0.27845097750790243 -} \ No newline at end of file +} diff --git a/exp/2026/05/27/forward-face/data/20-forward-face-3152k-expr001-smas100-summary.json b/exp/2026/05/27/forward-face/data/20-forward-face-3152k-expr001-smas100-summary.json index a7ada2d13..2654f1d35 100644 --- a/exp/2026/05/27/forward-face/data/20-forward-face-3152k-expr001-smas100-summary.json +++ b/exp/2026/05/27/forward-face/data/20-forward-face-3152k-expr001-smas100-summary.json @@ -57,4 +57,4 @@ "IsLipBottom/target_rms": 0.5516204314457805, "IsLipBottom/target_max": 1.2535219973603913, "IsLipBottom/rms_ratio_to_target": 0.2790818390528039 -} \ No newline at end of file +} diff --git a/exp/2026/05/27/forward-face/data/20-forward-face-3152k-summary.json b/exp/2026/05/27/forward-face/data/20-forward-face-3152k-summary.json index 15b3211b9..947ada679 100644 --- a/exp/2026/05/27/forward-face/data/20-forward-face-3152k-summary.json +++ b/exp/2026/05/27/forward-face/data/20-forward-face-3152k-summary.json @@ -56,4 +56,4 @@ "IsLipBottom/target_rms": 0.3993310920970844, "IsLipBottom/target_max": 1.0284059764202034, "IsLipBottom/rms_ratio_to_target": 0.3094006908630162 -} \ No newline at end of file +} diff --git a/exp/2026/05/27/forward-face/data/20-forward-face-515k-nosmas-summary.json b/exp/2026/05/27/forward-face/data/20-forward-face-515k-nosmas-summary.json index d74e2fae6..3b99316af 100644 --- a/exp/2026/05/27/forward-face/data/20-forward-face-515k-nosmas-summary.json +++ b/exp/2026/05/27/forward-face/data/20-forward-face-515k-nosmas-summary.json @@ -57,4 +57,4 @@ "IsLipBottom/target_rms": 0.42244197929946425, "IsLipBottom/target_max": 1.016519397545366, "IsLipBottom/rms_ratio_to_target": 0.12364134545496203 -} \ No newline at end of file +} diff --git a/exp/2026/05/27/forward-face/data/30-inverse-face-3152k-expr001-smas100-activation-only-summary.json b/exp/2026/05/27/forward-face/data/30-inverse-face-3152k-expr001-smas100-activation-only-summary.json index bacf42bc0..56427115c 100644 --- a/exp/2026/05/27/forward-face/data/30-inverse-face-3152k-expr001-smas100-activation-only-summary.json +++ b/exp/2026/05/27/forward-face/data/30-inverse-face-3152k-expr001-smas100-activation-only-summary.json @@ -145,4 +145,4 @@ "activation_inv/error_rms": 2.3418743890439707e-07, "activation_inv/error_max_norm": 7.913257834049561e-07, "passed": true -} \ No newline at end of file +} diff --git a/exp/2026/05/27/forward-face/data/30-inverse-face-3152k-expr001-smas100-diag-warm-state-summary.json b/exp/2026/05/27/forward-face/data/30-inverse-face-3152k-expr001-smas100-diag-warm-state-summary.json index 76c91a9c3..c1145d9c3 100644 --- a/exp/2026/05/27/forward-face/data/30-inverse-face-3152k-expr001-smas100-diag-warm-state-summary.json +++ b/exp/2026/05/27/forward-face/data/30-inverse-face-3152k-expr001-smas100-diag-warm-state-summary.json @@ -399,4 +399,4 @@ "activation_inv/error_rms": 0.0715948619403249, "activation_inv/error_max_norm": 0.17537109179907334, "passed": false -} \ No newline at end of file +} diff --git a/exp/2026/05/27/forward-face/data/30-inverse-face-515k-nosmas-summary.json b/exp/2026/05/27/forward-face/data/30-inverse-face-515k-nosmas-summary.json index 5efd622ac..a450b5688 100644 --- a/exp/2026/05/27/forward-face/data/30-inverse-face-515k-nosmas-summary.json +++ b/exp/2026/05/27/forward-face/data/30-inverse-face-515k-nosmas-summary.json @@ -4974,4 +4974,4 @@ "activation_inv/error_rms": 0.2491769718442089, "activation_inv/error_max_norm": 0.6141888156955176, "passed": true -} \ No newline at end of file +} diff --git a/exp/2026/05/27/forward-face/src/10-prepare-forward-face.py b/exp/2026/05/27/forward-face/src/10-prepare-forward-face.py index 64139e6ab..a390568b8 100644 --- a/exp/2026/05/27/forward-face/src/10-prepare-forward-face.py +++ b/exp/2026/05/27/forward-face/src/10-prepare-forward-face.py @@ -236,8 +236,12 @@ def metric_summary( "activation/n_tets": int(active.sum()), "target/n_points": int(target_mask.sum()), "fixed/n_points": int(fixed.sum()), - "fixed/n_cranium_points": int(np.asarray(mesh.point_data["FixedCranium"]).sum()), - "fixed/n_mandible_points": int(np.asarray(mesh.point_data["FixedMandible"]).sum()), + "fixed/n_cranium_points": int( + np.asarray(mesh.point_data["FixedCranium"]).sum() + ), + "fixed/n_mandible_points": int( + np.asarray(mesh.point_data["FixedMandible"]).sum() + ), "volume/muscle_fraction": float(np.sum(muscle * volume)), "volume/smas_fraction": float(np.sum(smas * volume)), "volume/smas_stiffness_fraction": float(np.sum(smas_stiffness * volume)), diff --git a/exp/2026/05/27/forward-face/src/20-forward-face.py b/exp/2026/05/27/forward-face/src/20-forward-face.py index 9a228da57..07663680f 100644 --- a/exp/2026/05/27/forward-face/src/20-forward-face.py +++ b/exp/2026/05/27/forward-face/src/20-forward-face.py @@ -153,7 +153,9 @@ def set_material( mesh.cell_data[FRACTION.vtk] = np.asarray(fraction, dtype=np.float64) -def unpack_symmetric(values: tuple[float, float, float, float, float, float]) -> np.ndarray: +def unpack_symmetric( + values: tuple[float, float, float, float, float, float], +) -> np.ndarray: xx, yy, zz, xy, xz, yz = values return np.asarray( [[xx, xy, xz], [xy, yy, yz], [xz, yz, zz]], @@ -304,7 +306,9 @@ def summarize( elapsed_s: float, cfg: Config, ) -> dict[str, Any]: - target_displacement = np.asarray(target.point_data["Displacement"], dtype=np.float64) + target_displacement = np.asarray( + target.point_data["Displacement"], dtype=np.float64 + ) active = np.asarray(mesh.cell_data["ActivationMask"], dtype=bool) volume = np.asarray(mesh.cell_data["Volume"], dtype=np.float64) muscle = np.asarray(mesh.cell_data["MuscleFraction"], dtype=np.float64) @@ -356,7 +360,9 @@ def make_result_mesh( metrics: dict[str, float | int | bool | str], ) -> pv.UnstructuredGrid: result = mesh.copy(deep=True) - target_displacement = np.asarray(target.point_data["Displacement"], dtype=np.float64) + target_displacement = np.asarray( + target.point_data["Displacement"], dtype=np.float64 + ) error = displacement - target_displacement result.point_data["Displacement"] = displacement result.point_data["DisplacementNorm"] = np.linalg.norm(displacement, axis=1) diff --git a/exp/2026/05/27/forward-face/src/30-inverse-face-3152k.py b/exp/2026/05/27/forward-face/src/30-inverse-face-3152k.py index 75eb911fa..28992ff68 100644 --- a/exp/2026/05/27/forward-face/src/30-inverse-face-3152k.py +++ b/exp/2026/05/27/forward-face/src/30-inverse-face-3152k.py @@ -302,7 +302,9 @@ def local_deltas_from_activation_inv( local_activation_inv = eye + matrix_from_symmetric(local_activation_inv_delta) local_activation = np.linalg.inv(local_activation_inv) local_activation_delta = pack_symmetric_np(local_activation[None, ...] - eye)[0] - return local_activation_delta, np.asarray(local_activation_inv_delta, dtype=np.float64) + return local_activation_delta, np.asarray( + local_activation_inv_delta, dtype=np.float64 + ) def activation_inv_from_local_delta( @@ -555,7 +557,9 @@ def make_result_mesh( result = mesh.copy(deep=True) add_masks(result, target_ids, active_ids) - target_displacement = np.asarray(target.point_data["Displacement"], dtype=np.float64) + target_displacement = np.asarray( + target.point_data["Displacement"], dtype=np.float64 + ) error = displacement - target_displacement result.point_data["Displacement"] = displacement result.point_data["DisplacementNorm"] = np.linalg.norm(displacement, axis=1) @@ -952,7 +956,9 @@ def summarize( ) -> dict[str, Any]: from liblaf.apple.common import ACTIVATION_INV - target_displacement = np.asarray(target.point_data["Displacement"], dtype=np.float64) + target_displacement = np.asarray( + target.point_data["Displacement"], dtype=np.float64 + ) error = displacement - target_displacement target_error = error[target_ids] target_error_norm = np.linalg.norm(target_error, axis=1) @@ -1060,10 +1066,12 @@ def main(cfg: Config) -> None: _, local_activation_inv_delta = local_deltas_from_activation_inv( recovered_local_activation_inv_delta ) - activation, activation_inv, local_activation_delta = full_activation_fields_from_local( - mesh, - active_ids, - local_activation_inv_delta, + activation, activation_inv, local_activation_delta = ( + full_activation_fields_from_local( + mesh, + active_ids, + local_activation_inv_delta, + ) ) total_elapsed_s = time.perf_counter() - total_start summary = summarize( @@ -1096,7 +1104,9 @@ def main(cfg: Config) -> None: try: save_snapshot(cfg.output_snapshot, result) except (OSError, RuntimeError, ValueError): - logger.warning("failed to save snapshot: %s", cfg.output_snapshot, exc_info=True) + logger.warning( + "failed to save snapshot: %s", cfg.output_snapshot, exc_info=True + ) save_json(cfg.output_summary, summary) cherries.log_metrics(numeric_metrics(summary, exclude=frozenset({"trace"}))) print( diff --git a/exp/2026/05/27/forward-face/src/30-inverse-face-515k.py b/exp/2026/05/27/forward-face/src/30-inverse-face-515k.py index 929585296..188156d79 100644 --- a/exp/2026/05/27/forward-face/src/30-inverse-face-515k.py +++ b/exp/2026/05/27/forward-face/src/30-inverse-face-515k.py @@ -297,7 +297,9 @@ def local_deltas_from_activation_inv( local_activation_inv = eye + matrix_from_symmetric(local_activation_inv_delta) local_activation = np.linalg.inv(local_activation_inv) local_activation_delta = pack_symmetric_np(local_activation[None, ...] - eye)[0] - return local_activation_delta, np.asarray(local_activation_inv_delta, dtype=np.float64) + return local_activation_delta, np.asarray( + local_activation_inv_delta, dtype=np.float64 + ) def activation_inv_from_local_delta( @@ -553,7 +555,9 @@ def make_result_mesh( result = mesh.copy(deep=True) add_masks(result, target_ids, active_ids) - target_displacement = np.asarray(target.point_data["Displacement"], dtype=np.float64) + target_displacement = np.asarray( + target.point_data["Displacement"], dtype=np.float64 + ) error = displacement - target_displacement result.point_data["Displacement"] = displacement result.point_data["DisplacementNorm"] = np.linalg.norm(displacement, axis=1) @@ -698,7 +702,9 @@ def adjoint_solve(self, u_grad: torch.Tensor) -> Any: device=torch.get_default_device(), ) local_activation_inv_delta = torch.nn.Parameter( - torch.zeros(6, dtype=torch.get_default_dtype(), device=torch.get_default_device()) + torch.zeros( + 6, dtype=torch.get_default_dtype(), device=torch.get_default_device() + ) ) optimizer = torch.optim.Adam( [local_activation_inv_delta], @@ -936,7 +942,9 @@ def summarize( ) -> dict[str, Any]: from liblaf.apple.common import ACTIVATION_INV - target_displacement = np.asarray(target.point_data["Displacement"], dtype=np.float64) + target_displacement = np.asarray( + target.point_data["Displacement"], dtype=np.float64 + ) error = displacement - target_displacement target_error = error[target_ids] target_error_norm = np.linalg.norm(target_error, axis=1) @@ -1039,10 +1047,12 @@ def main(cfg: Config) -> None: _, local_activation_inv_delta = local_deltas_from_activation_inv( recovered_local_activation_inv_delta ) - activation, activation_inv, local_activation_delta = full_activation_fields_from_local( - mesh, - active_ids, - local_activation_inv_delta, + activation, activation_inv, local_activation_delta = ( + full_activation_fields_from_local( + mesh, + active_ids, + local_activation_inv_delta, + ) ) total_elapsed_s = time.perf_counter() - total_start summary = summarize( @@ -1075,7 +1085,9 @@ def main(cfg: Config) -> None: try: save_snapshot(cfg.output_snapshot, result) except (OSError, RuntimeError, ValueError): - logger.warning("failed to save snapshot: %s", cfg.output_snapshot, exc_info=True) + logger.warning( + "failed to save snapshot: %s", cfg.output_snapshot, exc_info=True + ) save_json(cfg.output_summary, summary) cherries.log_metrics(numeric_metrics(summary, exclude=frozenset({"trace"}))) print( diff --git a/exp/2026/05/27/inverse-face/data/20-inverse-face-3152k-summary.json b/exp/2026/05/27/inverse-face/data/20-inverse-face-3152k-summary.json index 1bf0ccd18..e94a2b936 100644 --- a/exp/2026/05/27/inverse-face/data/20-inverse-face-3152k-summary.json +++ b/exp/2026/05/27/inverse-face/data/20-inverse-face-3152k-summary.json @@ -8190,4 +8190,4 @@ "repeated/forward_failure": false, "repeated/adjoint_failure": false, "passed": true -} \ No newline at end of file +} diff --git a/exp/2026/05/27/inverse-face/src/20-inverse-face.py b/exp/2026/05/27/inverse-face/src/20-inverse-face.py index 4e84566ff..64d6d0f6d 100644 --- a/exp/2026/05/27/inverse-face/src/20-inverse-face.py +++ b/exp/2026/05/27/inverse-face/src/20-inverse-face.py @@ -1079,9 +1079,7 @@ def summarize( "loss/data": final_loss, "loss/data_objective": float(best_record.get("loss/data", final_loss)), "loss/top_error": float(best_record.get("loss/top_error", 0.0)), - "loss/top_error_penalty": float( - best_record.get("loss/top_error_penalty", 0.0) - ), + "loss/top_error_penalty": float(best_record.get("loss/top_error_penalty", 0.0)), "loss/top_error_weight": cfg.top_error_weight, "loss/top_error_fraction": cfg.top_error_fraction, "loss/top_error_count": int(best_record.get("loss/top_error_count", 0)), diff --git a/exp/2026/06/10/surface-prestrain/data/10-surface-prestrain-forward-summary.json b/exp/2026/06/10/surface-prestrain/data/10-surface-prestrain-forward-summary.json index c0ceeaa01..84353dca0 100644 --- a/exp/2026/06/10/surface-prestrain/data/10-surface-prestrain-forward-summary.json +++ b/exp/2026/06/10/surface-prestrain/data/10-surface-prestrain-forward-summary.json @@ -101,4 +101,4 @@ "time/total_s": 308.1358953519957 } ] -} \ No newline at end of file +} diff --git a/exp/2026/06/10/surface-prestrain/data/20-surface-prestrain-expression000-summary.json b/exp/2026/06/10/surface-prestrain/data/20-surface-prestrain-expression000-summary.json index 2ac13ab63..edda4d3d2 100644 --- a/exp/2026/06/10/surface-prestrain/data/20-surface-prestrain-expression000-summary.json +++ b/exp/2026/06/10/surface-prestrain/data/20-surface-prestrain-expression000-summary.json @@ -101,4 +101,4 @@ "time/total_s": 305.3710525770439 } ] -} \ No newline at end of file +} diff --git a/exp/2026/06/10/surface-prestrain/data/21-surface-prestrain-expression000-prestrain04-summary.json b/exp/2026/06/10/surface-prestrain/data/21-surface-prestrain-expression000-prestrain04-summary.json index 7f376bd89..f48c17461 100644 --- a/exp/2026/06/10/surface-prestrain/data/21-surface-prestrain-expression000-prestrain04-summary.json +++ b/exp/2026/06/10/surface-prestrain/data/21-surface-prestrain-expression000-prestrain04-summary.json @@ -101,4 +101,4 @@ "time/total_s": 306.9689817209728 } ] -} \ No newline at end of file +} diff --git a/exp/2026/06/10/surface-prestrain/data/22-surface-metric-penalty-expression000-prestrain10-summary.json b/exp/2026/06/10/surface-prestrain/data/22-surface-metric-penalty-expression000-prestrain10-summary.json index 3089cafdc..6f980c16a 100644 --- a/exp/2026/06/10/surface-prestrain/data/22-surface-metric-penalty-expression000-prestrain10-summary.json +++ b/exp/2026/06/10/surface-prestrain/data/22-surface-metric-penalty-expression000-prestrain10-summary.json @@ -99,4 +99,4 @@ "time/total_s": 303.60624219698366 } ] -} \ No newline at end of file +} diff --git a/exp/2026/06/10/surface-prestrain/data/30-volume-area-change-diagnostics-summary.json b/exp/2026/06/10/surface-prestrain/data/30-volume-area-change-diagnostics-summary.json index 60342f63a..6d0030e35 100644 --- a/exp/2026/06/10/surface-prestrain/data/30-volume-area-change-diagnostics-summary.json +++ b/exp/2026/06/10/surface-prestrain/data/30-volume-area-change-diagnostics-summary.json @@ -613,4 +613,4 @@ "volume/total_rel_change": -0.0026985329648568923 } ] -} \ No newline at end of file +} diff --git a/exp/2026/06/10/unreachable-inverse-physics/data/10-real-mesh-area-volume-summary.json b/exp/2026/06/10/unreachable-inverse-physics/data/10-real-mesh-area-volume-summary.json index 322883c41..29fe8e7d4 100644 --- a/exp/2026/06/10/unreachable-inverse-physics/data/10-real-mesh-area-volume-summary.json +++ b/exp/2026/06/10/unreachable-inverse-physics/data/10-real-mesh-area-volume-summary.json @@ -197,4 +197,4 @@ "state": "inverse-minus-target" } ] -} \ No newline at end of file +} diff --git a/exp/2026/06/10/unreachable-inverse-physics/data/20-toy-unreachable-inverse-summary.json b/exp/2026/06/10/unreachable-inverse-physics/data/20-toy-unreachable-inverse-summary.json index 6d5043246..359570d82 100644 --- a/exp/2026/06/10/unreachable-inverse-physics/data/20-toy-unreachable-inverse-summary.json +++ b/exp/2026/06/10/unreachable-inverse-physics/data/20-toy-unreachable-inverse-summary.json @@ -9251,4 +9251,4 @@ "z_segments": 20 } ] -} \ No newline at end of file +} diff --git a/exp/2026/06/10/unreachable-inverse-physics/data/30-toy-target-magnitude-sweep-summary.json b/exp/2026/06/10/unreachable-inverse-physics/data/30-toy-target-magnitude-sweep-summary.json index 517a7ee4e..57926bfa3 100644 --- a/exp/2026/06/10/unreachable-inverse-physics/data/30-toy-target-magnitude-sweep-summary.json +++ b/exp/2026/06/10/unreachable-inverse-physics/data/30-toy-target-magnitude-sweep-summary.json @@ -24879,4 +24879,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/exp/2026/06/10/unreachable-inverse-physics/data/40-toy-forward-activation-summary.json b/exp/2026/06/10/unreachable-inverse-physics/data/40-toy-forward-activation-summary.json index b449a3055..51fb62944 100644 --- a/exp/2026/06/10/unreachable-inverse-physics/data/40-toy-forward-activation-summary.json +++ b/exp/2026/06/10/unreachable-inverse-physics/data/40-toy-forward-activation-summary.json @@ -210,4 +210,4 @@ "z_segments": 20 } ] -} \ No newline at end of file +} diff --git a/exp/2026/06/10/unreachable-inverse-physics/data/41-area-change-surfaces-summary.json b/exp/2026/06/10/unreachable-inverse-physics/data/41-area-change-surfaces-summary.json index dfcf466ba..20655ffe7 100644 --- a/exp/2026/06/10/unreachable-inverse-physics/data/41-area-change-surfaces-summary.json +++ b/exp/2026/06/10/unreachable-inverse-physics/data/41-area-change-surfaces-summary.json @@ -1945,4 +1945,4 @@ "triangle_area_rel_change/p95": 0.016074771199224683 } ] -} \ No newline at end of file +} diff --git a/exp/2026/06/10/unreachable-inverse-physics/data/42-toy-volume-field-backfill-summary.json b/exp/2026/06/10/unreachable-inverse-physics/data/42-toy-volume-field-backfill-summary.json index fdd7f0b21..fc9731344 100644 --- a/exp/2026/06/10/unreachable-inverse-physics/data/42-toy-volume-field-backfill-summary.json +++ b/exp/2026/06/10/unreachable-inverse-physics/data/42-toy-volume-field-backfill-summary.json @@ -91,4 +91,4 @@ "target_volume_rel_min": 0.0 } ] -} \ No newline at end of file +} diff --git a/exp/2026/06/10/unreachable-inverse-physics/data/50-toy-tetwild-experiments-summary.json b/exp/2026/06/10/unreachable-inverse-physics/data/50-toy-tetwild-experiments-summary.json index 9d9dc027b..41faa4c80 100644 --- a/exp/2026/06/10/unreachable-inverse-physics/data/50-toy-tetwild-experiments-summary.json +++ b/exp/2026/06/10/unreachable-inverse-physics/data/50-toy-tetwild-experiments-summary.json @@ -2167,4 +2167,4 @@ "z_segments": 0 } ] -} \ No newline at end of file +} diff --git a/exp/2026/06/10/unreachable-inverse-physics/data/50-toy-tetwild-experiments-table.md b/exp/2026/06/10/unreachable-inverse-physics/data/50-toy-tetwild-experiments-table.md index c4f05aef0..1d3f1d654 100644 --- a/exp/2026/06/10/unreachable-inverse-physics/data/50-toy-tetwild-experiments-table.md +++ b/exp/2026/06/10/unreachable-inverse-physics/data/50-toy-tetwild-experiments-table.md @@ -1,6 +1,6 @@ -| kind | case | lr | tets | active tets | signed dV | area dA | error/target | top y std | status | -| --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- | -| target | 50-toy-tetwild-stretch-lr001 | 0.01 | 369071 | 9363 | 0.195456 | 0 | | | kinematic target | -| target | 50-toy-tetwild-squash-lr001 | 0.01 | 369071 | 9363 | -0.195456 | 0 | | | kinematic target | -| inverse | 50-toy-tetwild-stretch-lr001 | 0.01 | 369071 | 9363 | 0.0494766 | 0.00807289 | 0.857958 | 0.00692003 | not_converged_best_in_last_window | -| inverse | 50-toy-tetwild-squash-lr001 | 0.01 | 369071 | 9363 | -0.0243172 | 0.00579743 | 0.908351 | 0.00441409 | not_converged_best_in_last_window | +| kind | case | lr | tets | active tets | signed dV | area dA | error/target | top y std | status | +| ------- | ---------------------------- | ---: | -----: | ----------: | ---------: | ---------: | -----------: | ---------: | --------------------------------- | +| target | 50-toy-tetwild-stretch-lr001 | 0.01 | 369071 | 9363 | 0.195456 | 0 | | | kinematic target | +| target | 50-toy-tetwild-squash-lr001 | 0.01 | 369071 | 9363 | -0.195456 | 0 | | | kinematic target | +| inverse | 50-toy-tetwild-stretch-lr001 | 0.01 | 369071 | 9363 | 0.0494766 | 0.00807289 | 0.857958 | 0.00692003 | not_converged_best_in_last_window | +| inverse | 50-toy-tetwild-squash-lr001 | 0.01 | 369071 | 9363 | -0.0243172 | 0.00579743 | 0.908351 | 0.00441409 | not_converged_best_in_last_window | diff --git a/exp/2026/06/10/unreachable-inverse-physics/src/10-real-mesh-area-volume.py b/exp/2026/06/10/unreachable-inverse-physics/src/10-real-mesh-area-volume.py index 4d9989f0f..2f143a274 100644 --- a/exp/2026/06/10/unreachable-inverse-physics/src/10-real-mesh-area-volume.py +++ b/exp/2026/06/10/unreachable-inverse-physics/src/10-real-mesh-area-volume.py @@ -187,7 +187,9 @@ def mask_from_mesh(mesh: pv.UnstructuredGrid, name: str) -> np.ndarray: return np.ones(mesh.n_points, dtype=bool) -def displacement_from(mesh: pv.UnstructuredGrid, *, preferred: str = "Displacement") -> np.ndarray: +def displacement_from( + mesh: pv.UnstructuredGrid, *, preferred: str = "Displacement" +) -> np.ndarray: if preferred in mesh.point_data: return np.asarray(mesh.point_data[preferred], dtype=np.float64) if "TargetDisplacement" in mesh.point_data: @@ -420,7 +422,9 @@ def error_row( "n_points": int(error.shape[0]), "n_mask_points": int(mask.sum()), "mask_error_mean": float(mask_error.mean()), - "mask_error_rms": float(np.linalg.norm(error[mask]) / math.sqrt(int(mask.sum()))), + "mask_error_rms": float( + np.linalg.norm(error[mask]) / math.sqrt(int(mask.sum())) + ), "mask_error_max": float(mask_error.max()), "mask_target_displacement_rms": float( np.linalg.norm(target_displacement[mask]) / math.sqrt(int(mask.sum())) @@ -434,7 +438,9 @@ def error_row( } -def flatten_for_csv(rows: list[dict[str, Any]]) -> tuple[list[str], list[dict[str, Any]]]: +def flatten_for_csv( + rows: list[dict[str, Any]], +) -> tuple[list[str], list[dict[str, Any]]]: keys = sorted({key for row in rows for key in row}) flat_rows: list[dict[str, Any]] = [] for row in rows: @@ -472,8 +478,7 @@ def write_table(path: Path, rows: list[dict[str, Any]]) -> None: metric_rows = [ row for row in rows - if row.get("state") - in {"target", "target-face-only-diagnostic", "inverse"} + if row.get("state") in {"target", "target-face-only-diagnostic", "inverse"} ] error_rows = { row["case"]: row for row in rows if row.get("state") == "inverse-minus-target" @@ -524,7 +529,9 @@ def main(cfg: Config) -> None: msg = f"{case.name} selected no points with {case.target_mask}" raise ValueError(msg) target_displacement_raw = displacement_from(target) - target_displacement_face_only = restrict_displacement(target_displacement_raw, mask) + target_displacement_face_only = restrict_displacement( + target_displacement_raw, mask + ) target_displacement_for_volume = ( target_displacement_raw if case.target_volume_is_physical @@ -540,7 +547,9 @@ def main(cfg: Config) -> None: msg = f"{case.name} has non-positive rest tetra volume" raise ValueError(msg) surface = surface_triangles(base) - rest_surface_area = triangle_areas(np.asarray(base.points, dtype=np.float64), surface) + rest_surface_area = triangle_areas( + np.asarray(base.points, dtype=np.float64), surface + ) diagnostic_path = ( cfg.output_summary.parent / "10-real-mesh-area-volume-vtu" @@ -573,7 +582,9 @@ def main(cfg: Config) -> None: rest_surface_area=rest_surface_area, rest_signed_volume=rest_signed_volume, volume_is_physical=case.target_volume_is_physical, - volume_scope="full-field" if case.target_volume_is_physical else "IsFace-only", + volume_scope="full-field" + if case.target_volume_is_physical + else "IsFace-only", ) target_row.update( displacement_stats(target_displacement_raw, mask, "target_raw_displacement") diff --git a/exp/2026/06/10/unreachable-inverse-physics/src/20-toy-unreachable-inverse.py b/exp/2026/06/10/unreachable-inverse-physics/src/20-toy-unreachable-inverse.py index 29a1b8abf..ab9c9896c 100644 --- a/exp/2026/06/10/unreachable-inverse-physics/src/20-toy-unreachable-inverse.py +++ b/exp/2026/06/10/unreachable-inverse-physics/src/20-toy-unreachable-inverse.py @@ -197,12 +197,15 @@ def tetra_volumes(points: np.ndarray, tets: np.ndarray) -> np.ndarray: def rel_change(value: np.ndarray, reference: np.ndarray) -> np.ndarray: - return np.divide( - value, - reference, - out=np.full_like(value, np.nan, dtype=np.float64), - where=reference != 0.0, - ) - 1.0 + return ( + np.divide( + value, + reference, + out=np.full_like(value, np.nan, dtype=np.float64), + where=reference != 0.0, + ) + - 1.0 + ) def add_tetra_volume_change_fields( @@ -270,12 +273,7 @@ def add_material_and_boundary_fields(mesh: pv.UnstructuredGrid, cfg: Config) -> x, y, z = centers[:, 0], centers[:, 1], centers[:, 2] muscle = ( - (x >= 0.0) - & (x <= 0.5) - & (y >= 0.04) - & (y <= 0.06) - & (z >= 0.4) - & (z <= 0.6) + (x >= 0.0) & (x <= 0.5) & (y >= 0.04) & (y <= 0.06) & (z >= 0.4) & (z <= 0.6) ).astype(np.float64) smas = ((y >= 0.04) & (y <= 0.06)).astype(np.float64) aponeurosis = np.maximum(0.0, smas - muscle) @@ -407,7 +405,9 @@ def target_displacement(mesh: pv.UnstructuredGrid, target_y: float) -> np.ndarra return displacement -def make_target_mesh(mesh: pv.UnstructuredGrid, displacement: np.ndarray) -> pv.UnstructuredGrid: +def make_target_mesh( + mesh: pv.UnstructuredGrid, displacement: np.ndarray +) -> pv.UnstructuredGrid: result = mesh.copy(deep=True) result.point_data["Displacement"] = displacement result.point_data["TargetDisplacement"] = displacement @@ -508,7 +508,9 @@ def geometry_change( } -def top_roughness(mesh: pv.UnstructuredGrid, displacement: np.ndarray) -> dict[str, float]: +def top_roughness( + mesh: pv.UnstructuredGrid, displacement: np.ndarray +) -> dict[str, float]: target_mask = np.asarray(mesh.point_data[TARGET_SURFACE_MASK], dtype=bool) top_ids = np.flatnonzero(target_mask) top_y = displacement[top_ids, 1] @@ -659,7 +661,9 @@ def solve_case(case: ToyCase, cfg: Config) -> dict[str, Any]: # noqa: PLR0915 forward = build_forward(inverse_mesh, cfg) differentiable_forward = DifferentiableForward(forward) base_materials = forward.model.get_materials() - global_ids = np.asarray(inverse_mesh.point_data[GLOBAL_POINT_ID.vtk], dtype=np.int64) + global_ids = np.asarray( + inverse_mesh.point_data[GLOBAL_POINT_ID.vtk], dtype=np.int64 + ) target_mask = np.asarray(inverse_mesh.point_data[TARGET_SURFACE_MASK], dtype=bool) target_ids = np.flatnonzero(target_mask).astype(np.int64) active_ids = np.flatnonzero( @@ -742,7 +746,9 @@ def solve_case(case: ToyCase, cfg: Config) -> dict[str, Any]: # noqa: PLR0915 torch.linalg.vector_norm(active_clamped.detach()).cpu() / math.sqrt(active_clamped.numel()) ), - "activation_inv_max_abs": float(active_clamped.detach().abs().max().cpu()), + "activation_inv_max_abs": float( + active_clamped.detach().abs().max().cpu() + ), "grad_norm": float(torch.linalg.vector_norm(grad).cpu()), } if loss_value < best_loss: @@ -883,7 +889,9 @@ def selected_cases(cfg: Config) -> list[ToyCase]: raise ValueError(msg) spec = RESOLUTION_SPECS[resolution_name] for mode in cfg.modes: - target_y = cfg.target_magnitude if mode == "stretch" else -cfg.target_magnitude + target_y = ( + cfg.target_magnitude if mode == "stretch" else -cfg.target_magnitude + ) cases.append(ToyCase(resolution=spec, mode=mode, target_y=target_y)) return cases diff --git a/exp/2026/06/10/unreachable-inverse-physics/src/40-toy-forward-activation.py b/exp/2026/06/10/unreachable-inverse-physics/src/40-toy-forward-activation.py index 8222d207e..5ab9c12ee 100644 --- a/exp/2026/06/10/unreachable-inverse-physics/src/40-toy-forward-activation.py +++ b/exp/2026/06/10/unreachable-inverse-physics/src/40-toy-forward-activation.py @@ -173,7 +173,9 @@ def make_result_mesh( result.point_data["TargetPoint"] = result.points result.cell_data[ACTIVATION_INV.vtk] = activation_inv result.cell_data["ForwardActivationInv"] = activation_inv - result.cell_data["ForwardActivationInvNorm"] = np.linalg.norm(activation_inv, axis=1) + result.cell_data["ForwardActivationInvNorm"] = np.linalg.norm( + activation_inv, axis=1 + ) BASE.add_tetra_volume_change_fields(result, target, displacement) result.cell_data["VolumeForward"] = np.asarray(result.cell_data["VolumeInverse"]) result.cell_data["VolumeForwardRelChange"] = np.asarray( @@ -201,7 +203,9 @@ def displacement_stats(mesh: Any, displacement: np.ndarray) -> dict[str, float]: active_points[np.unique(tets[active_cells].reshape(-1))] = True stats = { "displacement/mean": float(values.mean()), - "displacement/rms": float(np.linalg.norm(displacement) / math.sqrt(mesh.n_points)), + "displacement/rms": float( + np.linalg.norm(displacement) / math.sqrt(mesh.n_points) + ), "displacement/max": float(values.max()), "top/displacement_y_mean": float(displacement[top, 1].mean()), "top/displacement_y_min": float(displacement[top, 1].min()), @@ -260,15 +264,29 @@ def solve_case(case: ForwardCase, cfg: Config) -> dict[str, Any]: } row.update(forward_solution_metrics(solution)) row.update(displacement_stats(mesh, displacement)) - row.update({f"forward/{key}": value for key, value in BASE.geometry_change(mesh, displacement, target_mask).items()}) + row.update( + { + f"forward/{key}": value + for key, value in BASE.geometry_change( + mesh, displacement, target_mask + ).items() + } + ) numeric_metrics = { - key: value for key, value in row.items() if isinstance(value, int | float | bool) + key: value + for key, value in row.items() + if isinstance(value, int | float | bool) } - melon.save(output_path, make_result_mesh(mesh, displacement, activation_inv, numeric_metrics)) + melon.save( + output_path, + make_result_mesh(mesh, displacement, activation_inv, numeric_metrics), + ) cherries.log_output(input_path) cherries.log_output(output_path) - cherries.log_metrics({f"{case.stem}/{key}": value for key, value in numeric_metrics.items()}) + cherries.log_metrics( + {f"{case.stem}/{key}": value for key, value in numeric_metrics.items()} + ) logger.info( "%s displacement rms %.6g max %.6g signed dV %.6g forward %s", case.stem, diff --git a/exp/2026/06/10/unreachable-inverse-physics/src/41-area-change-surfaces.py b/exp/2026/06/10/unreachable-inverse-physics/src/41-area-change-surfaces.py index 7937e6fae..12a61adf0 100644 --- a/exp/2026/06/10/unreachable-inverse-physics/src/41-area-change-surfaces.py +++ b/exp/2026/06/10/unreachable-inverse-physics/src/41-area-change-surfaces.py @@ -106,12 +106,15 @@ def quantiles(values: np.ndarray, prefix: str) -> dict[str, float]: def rel_change(new: np.ndarray, old: np.ndarray) -> np.ndarray: - return np.divide( - new, - old, - out=np.full_like(new, np.nan, dtype=np.float64), - where=old != 0.0, - ) - 1.0 + return ( + np.divide( + new, + old, + out=np.full_like(new, np.nan, dtype=np.float64), + where=old != 0.0, + ) + - 1.0 + ) def add_area_state( diff --git a/exp/2026/06/10/unreachable-inverse-physics/src/42-toy-volume-field-backfill.py b/exp/2026/06/10/unreachable-inverse-physics/src/42-toy-volume-field-backfill.py index 3aef964f7..194f0e956 100644 --- a/exp/2026/06/10/unreachable-inverse-physics/src/42-toy-volume-field-backfill.py +++ b/exp/2026/06/10/unreachable-inverse-physics/src/42-toy-volume-field-backfill.py @@ -45,7 +45,8 @@ def case_paths(data_dir: Path) -> list[Path]: return [ path for path in paths - if not path.name.endswith("-input.vtu") and not path.name.endswith("-target.vtu") + if not path.name.endswith("-input.vtu") + and not path.name.endswith("-target.vtu") ] @@ -88,7 +89,9 @@ def patch_pair(result_path: Path) -> dict[str, Any]: cherries.log_output(result_path) cherries.log_output(target_path) - inverse_rel = np.asarray(result.cell_data["VolumeInverseRelChange"], dtype=np.float64) + inverse_rel = np.asarray( + result.cell_data["VolumeInverseRelChange"], dtype=np.float64 + ) target_rel = np.asarray(result.cell_data["VolumeTargetRelChange"], dtype=np.float64) signed_inverse_rel = np.asarray( result.cell_data["SignedVolumeInverseRelChange"], dtype=np.float64 diff --git a/exp/2026/06/10/unreachable-inverse-physics/src/50-toy-tetwild-experiments.py b/exp/2026/06/10/unreachable-inverse-physics/src/50-toy-tetwild-experiments.py index a74ecfe8e..101f30a75 100644 --- a/exp/2026/06/10/unreachable-inverse-physics/src/50-toy-tetwild-experiments.py +++ b/exp/2026/06/10/unreachable-inverse-physics/src/50-toy-tetwild-experiments.py @@ -161,7 +161,9 @@ def sample_barycentric(n_samples: int) -> np.ndarray: return values / values.sum(axis=1, keepdims=True) -def inside_box(points: np.ndarray, bounds: tuple[float, float, float, float, float, float]) -> np.ndarray: +def inside_box( + points: np.ndarray, bounds: tuple[float, float, float, float, float, float] +) -> np.ndarray: xmin, xmax, ymin, ymax, zmin, zmax = bounds eps = 1.0e-12 return ( @@ -228,7 +230,9 @@ def add_fraction_fields(mesh: pv.UnstructuredGrid, cfg: Config) -> None: mesh.cell_data["Volume"] = BASE.tetra_volumes(points, tets) mesh.cell_data[ACTIVATION.vtk] = zero_activation.copy() mesh.cell_data[ACTIVATION_INV.vtk] = zero_activation.copy() - mesh.field_data["FractionSamplesPerTet"] = np.asarray([cfg.fraction_samples_per_tet]) + mesh.field_data["FractionSamplesPerTet"] = np.asarray( + [cfg.fraction_samples_per_tet] + ) eps = max(1.0e-5, 0.03 * min(parse_floats(cfg.lrs))) point_x, point_y, point_z = points[:, 0], points[:, 1], points[:, 2] @@ -278,7 +282,9 @@ def write_area_surface( surface.cell_data["TargetArea"] = target_area surface.cell_data["TargetAreaRelChange"] = BASE.rel_change(target_area, rest_area) surface.cell_data["SolutionArea"] = solution_area - surface.cell_data["SolutionAreaRelChange"] = BASE.rel_change(solution_area, rest_area) + surface.cell_data["SolutionAreaRelChange"] = BASE.rel_change( + solution_area, rest_area + ) output_dir.mkdir(parents=True, exist_ok=True) path = output_dir / f"{stem}-area-change.vtp" surface.save(path) @@ -286,7 +292,9 @@ def write_area_surface( return path -def target_rows(mesh: pv.UnstructuredGrid, spec: TetwildSpec, cfg: Config) -> list[dict[str, Any]]: +def target_rows( + mesh: pv.UnstructuredGrid, spec: TetwildSpec, cfg: Config +) -> list[dict[str, Any]]: rows: list[dict[str, Any]] = [] data_dir = cfg.output_summary.parent input_path = data_dir / f"50-toy-tetwild-{spec.name}-input.vtu" @@ -315,14 +323,23 @@ def target_rows(mesh: pv.UnstructuredGrid, spec: TetwildSpec, cfg: Config) -> li "lr": spec.lr, "n_points": int(mesh.n_points), "n_tets": int(mesh.n_cells), - "n_active_tets": int(np.asarray(mesh.cell_data["ActivationMask"], dtype=bool).sum()), + "n_active_tets": int( + np.asarray(mesh.cell_data["ActivationMask"], dtype=bool).sum() + ), "n_target_points": int(target_mask.sum()), "target_y": target_y, "input_path": str(input_path), "target_path": str(target_path), "area_surface_path": str(area_path), } - row.update({f"target/{key}": value for key, value in BASE.geometry_change(mesh, target, target_mask).items()}) + row.update( + { + f"target/{key}": value + for key, value in BASE.geometry_change( + mesh, target, target_mask + ).items() + } + ) rows.append(row) cherries.log_output(target_path) return rows @@ -381,7 +398,9 @@ def forward_solution_metrics(solution: Any) -> dict[str, Any]: } -def forward_rows(meshes: dict[float, pv.UnstructuredGrid], cfg: Config) -> list[dict[str, Any]]: +def forward_rows( + meshes: dict[float, pv.UnstructuredGrid], cfg: Config +) -> list[dict[str, Any]]: rows: list[dict[str, Any]] = [] for spec in specs(cfg): if spec.lr not in parse_floats(cfg.forward_lrs): @@ -421,22 +440,44 @@ def forward_rows(meshes: dict[float, pv.UnstructuredGrid], cfg: Config) -> list[ "lr": spec.lr, "n_points": int(mesh.n_points), "n_tets": int(mesh.n_cells), - "n_active_tets": int(np.asarray(mesh.cell_data["ActivationMask"], dtype=bool).sum()), + "n_active_tets": int( + np.asarray(mesh.cell_data["ActivationMask"], dtype=bool).sum() + ), "n_target_points": int(target_mask.sum()), "elapsed_s": time.perf_counter() - start, "output_path": str(output_path), "area_surface_path": str(area_path), } row.update(forward_solution_metrics(solution)) - row.update({f"forward/{key}": value for key, value in BASE.geometry_change(mesh, displacement, target_mask).items()}) - row.update({f"forward/{key}": value for key, value in BASE.top_roughness(mesh, displacement).items()}) + row.update( + { + f"forward/{key}": value + for key, value in BASE.geometry_change( + mesh, displacement, target_mask + ).items() + } + ) + row.update( + { + f"forward/{key}": value + for key, value in BASE.top_roughness(mesh, displacement).items() + } + ) rows.append(row) cherries.log_output(output_path) - cherries.log_metrics({f"{stem}/{key}": value for key, value in row.items() if isinstance(value, int | float | bool)}) + cherries.log_metrics( + { + f"{stem}/{key}": value + for key, value in row.items() + if isinstance(value, int | float | bool) + } + ) return rows -def inverse_rows(meshes: dict[float, pv.UnstructuredGrid], cfg: Config) -> list[dict[str, Any]]: +def inverse_rows( + meshes: dict[float, pv.UnstructuredGrid], cfg: Config +) -> list[dict[str, Any]]: rows: list[dict[str, Any]] = [] original_make_tet_box = BASE.make_tet_box original_add_material = BASE.add_material_and_boundary_fields @@ -445,7 +486,9 @@ def inverse_rows(meshes: dict[float, pv.UnstructuredGrid], cfg: Config) -> list[ if spec.lr not in parse_floats(cfg.inverse_lrs): continue for mode in parse_modes(cfg.modes): - target_y = cfg.target_magnitude if mode == "stretch" else -cfg.target_magnitude + target_y = ( + cfg.target_magnitude if mode == "stretch" else -cfg.target_magnitude + ) case = TetwildCase(resolution=spec, mode=mode, target_y=target_y) mesh = meshes[spec.lr].copy(deep=True) BASE.make_tet_box = lambda _resolution, mesh=mesh: mesh.copy(deep=True) @@ -460,9 +503,14 @@ def inverse_rows(meshes: dict[float, pv.UnstructuredGrid], cfg: Config) -> list[ area_path = write_area_surface( mesh=result, stem=case.stem, - target=np.asarray(result.point_data["TargetDisplacement"], dtype=np.float64), - solution=np.asarray(result.point_data["Displacement"], dtype=np.float64), - output_dir=cfg.output_summary.parent / "50-toy-tetwild-area-surfaces", + target=np.asarray( + result.point_data["TargetDisplacement"], dtype=np.float64 + ), + solution=np.asarray( + result.point_data["Displacement"], dtype=np.float64 + ), + output_dir=cfg.output_summary.parent + / "50-toy-tetwild-area-surfaces", ) row["area_surface_path"] = str(area_path) rows.append(row)