mechdsl-core 0.2.1__tar.gz
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.
- mechdsl_core-0.2.1/.gitignore +75 -0
- mechdsl_core-0.2.1/LICENSE +21 -0
- mechdsl_core-0.2.1/PKG-INFO +41 -0
- mechdsl_core-0.2.1/README.md +13 -0
- mechdsl_core-0.2.1/pyproject.toml +71 -0
- mechdsl_core-0.2.1/src/mechdsl/__init__.py +263 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/__init__.py +90 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/_experimental.py +71 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/anisotropic_emitter.py +233 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/artifact.py +319 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/boundary_codegen.py +277 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/common.py +1 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/einsum_optimizer.py +507 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/energy_emitter.py +316 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/family_registry.py +226 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/hex20_tables.py +314 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/hex8_reduced_tables.py +91 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/hex8_tables.py +214 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/hourglass.py +359 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/mfem_printer.py +819 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/mfem_template/CMakeLists.txt +51 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/moose_printer.py +603 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/moose_template/__init__.py +6 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/moose_template/input_template.i +112 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/spectral_emitter.py +284 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/taichi_printer.py +3597 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/templates/__init__.py +1 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/tet10_tables.py +267 -0
- mechdsl_core-0.2.1/src/mechdsl/codegen/tet4_tables.py +178 -0
- mechdsl_core-0.2.1/src/mechdsl/frontend/ARCHITECTURE.md +55 -0
- mechdsl_core-0.2.1/src/mechdsl/frontend/__init__.py +406 -0
- mechdsl_core-0.2.1/src/mechdsl/frontend/directives.py +748 -0
- mechdsl_core-0.2.1/src/mechdsl/frontend/math_parser.py +541 -0
- mechdsl_core-0.2.1/src/mechdsl/frontend/parser.py +294 -0
- mechdsl_core-0.2.1/src/mechdsl/frontend/two_point.py +12 -0
- mechdsl_core-0.2.1/src/mechdsl/integration/__init__.py +1100 -0
- mechdsl_core-0.2.1/src/mechdsl/ir/ARCHITECTURE.md +40 -0
- mechdsl_core-0.2.1/src/mechdsl/ir/__init__.py +39 -0
- mechdsl_core-0.2.1/src/mechdsl/ir/element_factory.py +192 -0
- mechdsl_core-0.2.1/src/mechdsl/ir/element_ir.py +822 -0
- mechdsl_core-0.2.1/src/mechdsl/ir/mechanics_ir.py +1438 -0
- mechdsl_core-0.2.1/src/mechdsl/lawgen/README.md +32 -0
- mechdsl_core-0.2.1/src/mechdsl/lawgen/REUSE.md +120 -0
- mechdsl_core-0.2.1/src/mechdsl/lawgen/__init__.py +40 -0
- mechdsl_core-0.2.1/src/mechdsl/lawgen/budgets.py +404 -0
- mechdsl_core-0.2.1/src/mechdsl/lawgen/carrier_emitter.py +447 -0
- mechdsl_core-0.2.1/src/mechdsl/lawgen/cli.py +588 -0
- mechdsl_core-0.2.1/src/mechdsl/lawgen/contracts.py +276 -0
- mechdsl_core-0.2.1/src/mechdsl/lawgen/diagnostics.py +263 -0
- mechdsl_core-0.2.1/src/mechdsl/lawgen/guard_transforms.py +234 -0
- mechdsl_core-0.2.1/src/mechdsl/lawgen/manifest.py +461 -0
- mechdsl_core-0.2.1/src/mechdsl/lawgen/sympy_to_taichi.py +738 -0
- mechdsl_core-0.2.1/src/mechdsl/lawgen/test_emitter.py +503 -0
- mechdsl_core-0.2.1/src/mechdsl/lib/__init__.py +25 -0
- mechdsl_core-0.2.1/src/mechdsl/lib/plasticity.py +214 -0
- mechdsl_core-0.2.1/src/mechdsl/lib/plasticity_kinematic.py +316 -0
- mechdsl_core-0.2.1/src/mechdsl/lib/plasticity_mixed.py +368 -0
- mechdsl_core-0.2.1/src/mechdsl/lib/tensor_ops.py +141 -0
- mechdsl_core-0.2.1/src/mechdsl/lowering/__init__.py +29 -0
- mechdsl_core-0.2.1/src/mechdsl/lowering/boundary.py +152 -0
- mechdsl_core-0.2.1/src/mechdsl/lowering/einsum_extract.py +255 -0
- mechdsl_core-0.2.1/src/mechdsl/lowering/fe_localise.py +411 -0
- mechdsl_core-0.2.1/src/mechdsl/solver/__init__.py +76 -0
- mechdsl_core-0.2.1/src/mechdsl/solver/_seam_runtime.py +67 -0
- mechdsl_core-0.2.1/src/mechdsl/solver/critical_timestep.py +300 -0
- mechdsl_core-0.2.1/src/mechdsl/solver/history_fields.py +116 -0
- mechdsl_core-0.2.1/src/mechdsl/solver/import_adapter.py +551 -0
- mechdsl_core-0.2.1/src/mechdsl/solver/integration.py +60 -0
- mechdsl_core-0.2.1/src/mechdsl/solver/jacobi_preconditioner.py +90 -0
- mechdsl_core-0.2.1/src/mechdsl/solver/load_stepping.py +143 -0
- mechdsl_core-0.2.1/src/mechdsl/solver/lumped_mass.py +139 -0
- mechdsl_core-0.2.1/src/mechdsl/solver/mesh_io.py +449 -0
- mechdsl_core-0.2.1/src/mechdsl/solver/newton.py +230 -0
- mechdsl_core-0.2.1/src/mechdsl/solver/seam_integrate.py +129 -0
- mechdsl_core-0.2.1/src/mechdsl/solver/seam_solve.py +173 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/__init__.py +11 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/anisotropic_energy.py +344 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/bridge.py +234 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/constitutive.py +97 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/convected.py +586 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/energy.py +492 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/invariants.py +186 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/kinematics.py +177 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/models/__init__.py +12 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/models/hgo.py +238 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/models/j2_power_law.py +441 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/models/johnson_cook.py +598 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/models/lemaitre.py +375 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/models/mooney_rivlin.py +214 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/models/neo_hookean.py +204 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/models/ogden.py +227 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/models/perzyna.py +443 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/models/svk.py +142 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/objective_rates.py +370 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/spectral_energy.py +291 -0
- mechdsl_core-0.2.1/src/mechdsl/symbolic/voigt.py +166 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/__init__.py +1 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/_assembly.py +278 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/_patch_test_kernels.py +185 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/ad_oracle.py +481 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/analytical.py +284 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/benchmarks/__init__.py +101 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/benchmarks/_core.py +143 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/benchmarks/_elastic_solver.py +226 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/benchmarks/_j2_solver.py +185 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/benchmarks/_meshes.py +398 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/benchmarks/_taylor_runtime.py +961 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/benchmarks/cantilever.py +164 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/benchmarks/cook_membrane.py +266 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/benchmarks/hgo_strip.py +448 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/benchmarks/necking_bar.py +402 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/benchmarks/notched_bar.py +589 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/benchmarks/plate_with_hole.py +587 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/benchmarks/taylor_impact.py +399 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/benchmarks/thick_cylinder.py +629 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/convergence.py +587 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/mms_matrix.py +319 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/patch_test.py +523 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/perf/__init__.py +47 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/perf/baseline.py +267 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/perf/regenerate_baseline.py +62 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/perf/registry.py +577 -0
- mechdsl_core-0.2.1/src/mechdsl/verify/perf/run_compare.py +119 -0
- mechdsl_core-0.2.1/tests/__init__.py +0 -0
- mechdsl_core-0.2.1/tests/_e2e_helpers.py +116 -0
- mechdsl_core-0.2.1/tests/_gen_cooks_ref.py +72 -0
- mechdsl_core-0.2.1/tests/conftest.py +21 -0
- mechdsl_core-0.2.1/tests/generate_golden.py +522 -0
- mechdsl_core-0.2.1/tests/golden/.gitkeep +0 -0
- mechdsl_core-0.2.1/tests/golden/boundary_neumann.ti.txt +26 -0
- mechdsl_core-0.2.1/tests/golden/generated_elastic.py.golden +683 -0
- mechdsl_core-0.2.1/tests/golden/generated_plastic.py.golden +912 -0
- mechdsl_core-0.2.1/tests/golden/generated_ul_svk.py.golden +570 -0
- mechdsl_core-0.2.1/tests/golden/perf/README.md +60 -0
- mechdsl_core-0.2.1/tests/golden/perf/baseline_smoke.json +59 -0
- mechdsl_core-0.2.1/tests/golden/template_family_emission_baseline.json +88 -0
- mechdsl_core-0.2.1/tests/lawgen/__init__.py +0 -0
- mechdsl_core-0.2.1/tests/lawgen/fixtures/linear_min.yaml +10 -0
- mechdsl_core-0.2.1/tests/lawgen/test_budgets.py +311 -0
- mechdsl_core-0.2.1/tests/lawgen/test_carrier_emitter.py +235 -0
- mechdsl_core-0.2.1/tests/lawgen/test_cli.py +359 -0
- mechdsl_core-0.2.1/tests/lawgen/test_contracts.py +293 -0
- mechdsl_core-0.2.1/tests/lawgen/test_diagnostics.py +289 -0
- mechdsl_core-0.2.1/tests/lawgen/test_guard_injection.py +401 -0
- mechdsl_core-0.2.1/tests/lawgen/test_lowering_table.py +404 -0
- mechdsl_core-0.2.1/tests/lawgen/test_manifest.py +382 -0
- mechdsl_core-0.2.1/tests/lawgen/test_sympy_to_taichi.py +201 -0
- mechdsl_core-0.2.1/tests/lawgen/test_test_emitter.py +259 -0
- mechdsl_core-0.2.1/tests/ref/.gitkeep +0 -0
- mechdsl_core-0.2.1/tests/ref/__init__.py +0 -0
- mechdsl_core-0.2.1/tests/ref/ref_hex8_elastic.py +489 -0
- mechdsl_core-0.2.1/tests/ref/ref_hex8_hgo.py +263 -0
- mechdsl_core-0.2.1/tests/ref/ref_hex8_plastic.py +488 -0
- mechdsl_core-0.2.1/tests/ref/ref_hex8_ul.py +450 -0
- mechdsl_core-0.2.1/tests/ref/ref_j2_kinematic.py +204 -0
- mechdsl_core-0.2.1/tests/ref/ref_j2_mixed.py +252 -0
- mechdsl_core-0.2.1/tests/test_ad_oracle.py +265 -0
- mechdsl_core-0.2.1/tests/test_analytical.py +650 -0
- mechdsl_core-0.2.1/tests/test_anisotropic_emission.py +125 -0
- mechdsl_core-0.2.1/tests/test_artifact_bundle.py +251 -0
- mechdsl_core-0.2.1/tests/test_artifacts.py +498 -0
- mechdsl_core-0.2.1/tests/test_benchmarks.py +1079 -0
- mechdsl_core-0.2.1/tests/test_benchmarks_cantilever_matrix.py +93 -0
- mechdsl_core-0.2.1/tests/test_benchmarks_cook_membrane_matrix.py +101 -0
- mechdsl_core-0.2.1/tests/test_benchmarks_necking_bar_matrix.py +196 -0
- mechdsl_core-0.2.1/tests/test_boundaries.py +1 -0
- mechdsl_core-0.2.1/tests/test_boundary_codegen.py +406 -0
- mechdsl_core-0.2.1/tests/test_boundary_neumann.py +103 -0
- mechdsl_core-0.2.1/tests/test_ci_config.py +153 -0
- mechdsl_core-0.2.1/tests/test_codegen.py +470 -0
- mechdsl_core-0.2.1/tests/test_compile_latex_docstring.py +62 -0
- mechdsl_core-0.2.1/tests/test_compile_pipeline.py +131 -0
- mechdsl_core-0.2.1/tests/test_constitutive_abc.py +271 -0
- mechdsl_core-0.2.1/tests/test_convected.py +159 -0
- mechdsl_core-0.2.1/tests/test_convected_curvilinear.py +557 -0
- mechdsl_core-0.2.1/tests/test_convected_patch.py +265 -0
- mechdsl_core-0.2.1/tests/test_convergence.py +533 -0
- mechdsl_core-0.2.1/tests/test_critical_timestep.py +219 -0
- mechdsl_core-0.2.1/tests/test_cross_backend.py +850 -0
- mechdsl_core-0.2.1/tests/test_documentation.py +346 -0
- mechdsl_core-0.2.1/tests/test_e2e.py +367 -0
- mechdsl_core-0.2.1/tests/test_e2e_plastic.py +736 -0
- mechdsl_core-0.2.1/tests/test_e2e_taichi.py +321 -0
- mechdsl_core-0.2.1/tests/test_einsum.py +433 -0
- mechdsl_core-0.2.1/tests/test_einsum_extract.py +108 -0
- mechdsl_core-0.2.1/tests/test_einsum_optimizer.py +310 -0
- mechdsl_core-0.2.1/tests/test_element_factory.py +190 -0
- mechdsl_core-0.2.1/tests/test_element_ir.py +308 -0
- mechdsl_core-0.2.1/tests/test_emission_verification.py +787 -0
- mechdsl_core-0.2.1/tests/test_emit_lame_conversion.py +152 -0
- mechdsl_core-0.2.1/tests/test_energy_codegen_svk.py +110 -0
- mechdsl_core-0.2.1/tests/test_energy_svk.py +103 -0
- mechdsl_core-0.2.1/tests/test_explicit_dynamics_acceptance.py +544 -0
- mechdsl_core-0.2.1/tests/test_explicit_integrator.py +208 -0
- mechdsl_core-0.2.1/tests/test_formulation_switching.py +181 -0
- mechdsl_core-0.2.1/tests/test_frontend.py +1 -0
- mechdsl_core-0.2.1/tests/test_frontend_build_context.py +320 -0
- mechdsl_core-0.2.1/tests/test_frontend_parser.py +713 -0
- mechdsl_core-0.2.1/tests/test_full_pipeline.py +317 -0
- mechdsl_core-0.2.1/tests/test_hex20_basis.py +247 -0
- mechdsl_core-0.2.1/tests/test_hex8_reduced.py +172 -0
- mechdsl_core-0.2.1/tests/test_hex8_tables.py +275 -0
- mechdsl_core-0.2.1/tests/test_hgo.py +195 -0
- mechdsl_core-0.2.1/tests/test_hgo_benchmark.py +225 -0
- mechdsl_core-0.2.1/tests/test_hgo_solver_e2e.py +205 -0
- mechdsl_core-0.2.1/tests/test_history_fields.py +276 -0
- mechdsl_core-0.2.1/tests/test_hourglass_control.py +217 -0
- mechdsl_core-0.2.1/tests/test_hourglass_suppression.py +123 -0
- mechdsl_core-0.2.1/tests/test_hyperelastic_uniaxial.py +198 -0
- mechdsl_core-0.2.1/tests/test_integration_surface.py +754 -0
- mechdsl_core-0.2.1/tests/test_invariants.py +84 -0
- mechdsl_core-0.2.1/tests/test_j2.py +420 -0
- mechdsl_core-0.2.1/tests/test_j2_radial_return_parity.py +149 -0
- mechdsl_core-0.2.1/tests/test_johnson_cook.py +588 -0
- mechdsl_core-0.2.1/tests/test_kinematics.py +235 -0
- mechdsl_core-0.2.1/tests/test_kinematics_ul.py +143 -0
- mechdsl_core-0.2.1/tests/test_lemaitre_acceptance.py +975 -0
- mechdsl_core-0.2.1/tests/test_lemaitre_codegen.py +226 -0
- mechdsl_core-0.2.1/tests/test_lemaitre_evolution.py +309 -0
- mechdsl_core-0.2.1/tests/test_load_stepping.py +286 -0
- mechdsl_core-0.2.1/tests/test_localise.py +354 -0
- mechdsl_core-0.2.1/tests/test_localise_model_validation.py +72 -0
- mechdsl_core-0.2.1/tests/test_mechanics_ir.py +321 -0
- mechdsl_core-0.2.1/tests/test_mechanics_ir_configuration.py +223 -0
- mechdsl_core-0.2.1/tests/test_mesh_io.py +721 -0
- mechdsl_core-0.2.1/tests/test_metric_assign_directives.py +116 -0
- mechdsl_core-0.2.1/tests/test_mfem_printer.py +332 -0
- mechdsl_core-0.2.1/tests/test_mms_convergence_matrix.py +93 -0
- mechdsl_core-0.2.1/tests/test_mooney_rivlin.py +205 -0
- mechdsl_core-0.2.1/tests/test_moose_printer.py +317 -0
- mechdsl_core-0.2.1/tests/test_neo_hookean.py +205 -0
- mechdsl_core-0.2.1/tests/test_newton.py +475 -0
- mechdsl_core-0.2.1/tests/test_notched_bar_benchmark.py +305 -0
- mechdsl_core-0.2.1/tests/test_nrpylatex_round_trip.py +162 -0
- mechdsl_core-0.2.1/tests/test_objective_rates.py +268 -0
- mechdsl_core-0.2.1/tests/test_ogden.py +191 -0
- mechdsl_core-0.2.1/tests/test_ogden_solver_e2e.py +203 -0
- mechdsl_core-0.2.1/tests/test_patch_test.py +403 -0
- mechdsl_core-0.2.1/tests/test_patch_test_all_elements.py +126 -0
- mechdsl_core-0.2.1/tests/test_perf_regression.py +396 -0
- mechdsl_core-0.2.1/tests/test_perzyna.py +444 -0
- mechdsl_core-0.2.1/tests/test_phase10_benchmark_registry.py +235 -0
- mechdsl_core-0.2.1/tests/test_phase10_elastic_solver.py +103 -0
- mechdsl_core-0.2.1/tests/test_phase10_j2_solver.py +127 -0
- mechdsl_core-0.2.1/tests/test_phase10_mesh_utils.py +92 -0
- mechdsl_core-0.2.1/tests/test_phase10_taylor_benchmark.py +180 -0
- mechdsl_core-0.2.1/tests/test_phase10_taylor_runtime.py +360 -0
- mechdsl_core-0.2.1/tests/test_phase10_taylor_state.py +421 -0
- mechdsl_core-0.2.1/tests/test_plastic_emission.py +560 -0
- mechdsl_core-0.2.1/tests/test_plate_with_hole.py +59 -0
- mechdsl_core-0.2.1/tests/test_ref_elastic.py +582 -0
- mechdsl_core-0.2.1/tests/test_ref_plastic.py +580 -0
- mechdsl_core-0.2.1/tests/test_review_followups.py +116 -0
- mechdsl_core-0.2.1/tests/test_smoke.py +29 -0
- mechdsl_core-0.2.1/tests/test_solver.py +293 -0
- mechdsl_core-0.2.1/tests/test_spectral_eigensolver.py +169 -0
- mechdsl_core-0.2.1/tests/test_svk.py +249 -0
- mechdsl_core-0.2.1/tests/test_symbolic.py +1 -0
- mechdsl_core-0.2.1/tests/test_symbolic_ir_interface.py +311 -0
- mechdsl_core-0.2.1/tests/test_taichi_printer.py +440 -0
- mechdsl_core-0.2.1/tests/test_taichi_printer_ul.py +431 -0
- mechdsl_core-0.2.1/tests/test_taylor_impact.py +316 -0
- mechdsl_core-0.2.1/tests/test_template_family_budget.py +301 -0
- mechdsl_core-0.2.1/tests/test_tensor_ops.py +278 -0
- mechdsl_core-0.2.1/tests/test_tet10_basis.py +264 -0
- mechdsl_core-0.2.1/tests/test_tet4_basis.py +192 -0
- mechdsl_core-0.2.1/tests/test_thick_cylinder.py +108 -0
- mechdsl_core-0.2.1/tests/test_ul_equivalence.py +286 -0
- mechdsl_core-0.2.1/tests/test_verification_gaps_p5t2.py +582 -0
- mechdsl_core-0.2.1/tests/test_verification_gaps_p5t3.py +122 -0
- mechdsl_core-0.2.1/tests/test_verify_assembly_cast.py +223 -0
- mechdsl_core-0.2.1/tests/test_viscoplastic_acceptance.py +235 -0
- mechdsl_core-0.2.1/tests/test_voigt.py +253 -0
- mechdsl_core-0.2.1/tests/tools/__init__.py +1 -0
- mechdsl_core-0.2.1/tests/tools/regen_p9_3_baseline.py +151 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.egg-info/
|
|
6
|
+
*.egg
|
|
7
|
+
dist/
|
|
8
|
+
build/
|
|
9
|
+
*.whl
|
|
10
|
+
.eggs/
|
|
11
|
+
|
|
12
|
+
# Virtual environments
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
env/
|
|
16
|
+
|
|
17
|
+
# IDE
|
|
18
|
+
.idea/
|
|
19
|
+
.vscode/
|
|
20
|
+
*.swp
|
|
21
|
+
*.swo
|
|
22
|
+
*~
|
|
23
|
+
|
|
24
|
+
# Testing
|
|
25
|
+
.pytest_cache/
|
|
26
|
+
.coverage
|
|
27
|
+
htmlcov/
|
|
28
|
+
.mypy_cache/
|
|
29
|
+
.ruff_cache/
|
|
30
|
+
|
|
31
|
+
# OS
|
|
32
|
+
.DS_Store
|
|
33
|
+
Thumbs.db
|
|
34
|
+
|
|
35
|
+
# Taichi
|
|
36
|
+
*.tcb
|
|
37
|
+
ti_cache/
|
|
38
|
+
|
|
39
|
+
# Artifacts
|
|
40
|
+
*.artifact.json
|
|
41
|
+
*.artifact.yaml
|
|
42
|
+
|
|
43
|
+
# Jupyter
|
|
44
|
+
.ipynb_checkpoints/
|
|
45
|
+
|
|
46
|
+
# Claude Code
|
|
47
|
+
.claude/settings.local.json
|
|
48
|
+
|
|
49
|
+
# Claude CoWork
|
|
50
|
+
/MechDsl/
|
|
51
|
+
*.npz
|
|
52
|
+
# Golden-file regression snapshots must be tracked
|
|
53
|
+
!packages/mechdsl-core/tests/golden/*.npz
|
|
54
|
+
.gitnexus
|
|
55
|
+
|
|
56
|
+
# Local working artifacts (orchestra runtime, plan-edit backups)
|
|
57
|
+
.orchestra/
|
|
58
|
+
**/.orchestra/
|
|
59
|
+
*.original.md
|
|
60
|
+
*.original.[0-9].md
|
|
61
|
+
.claude/worktrees/
|
|
62
|
+
.publisher-worktrees/
|
|
63
|
+
.sesskey
|
|
64
|
+
|
|
65
|
+
# Public-release staging tree (curated copy pushed to CEmM2/MechDSL)
|
|
66
|
+
/dev/MechDSL/
|
|
67
|
+
|
|
68
|
+
# MkDocs build output
|
|
69
|
+
/site/
|
|
70
|
+
|
|
71
|
+
# Generated wiki / code-intelligence index (logic-loom / akms tooling)
|
|
72
|
+
.repo_wiki/
|
|
73
|
+
|
|
74
|
+
# comment-sweep working tree
|
|
75
|
+
/.comment-review/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Shmuel Osovski
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mechdsl-core
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: MechDSL core — LaTeX tensor expressions to FEM solver code
|
|
5
|
+
Project-URL: Repository, https://github.com/CEmM2/MechDSL
|
|
6
|
+
Author: Shmuel Osovski
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: code-generation,computational-mechanics,dsl,fem,finite-elements,taichi
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
16
|
+
Requires-Python: <3.14,>=3.11
|
|
17
|
+
Requires-Dist: nrpylatex<2,>=1.4.0
|
|
18
|
+
Requires-Dist: numpy>=2.4.2
|
|
19
|
+
Requires-Dist: opt-einsum>=3.3
|
|
20
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
21
|
+
Requires-Dist: scipy>=1.17.0
|
|
22
|
+
Requires-Dist: sympy>=1.12
|
|
23
|
+
Provides-Extra: verify
|
|
24
|
+
Requires-Dist: algo2code<0.3,>=0.2.1; extra == 'verify'
|
|
25
|
+
Requires-Dist: taichi>=1.7; extra == 'verify'
|
|
26
|
+
Requires-Dist: ti-runtime<0.3,>=0.2.1; extra == 'verify'
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# mechdsl-core
|
|
30
|
+
|
|
31
|
+
Core compiler package for MechDSL — LaTeX tensor expressions to FEM solver code.
|
|
32
|
+
|
|
33
|
+
Handles constitutive equations, element-level physics (Einstein notation), kinematics,
|
|
34
|
+
and Taichi code generation through the Mechanics IR → Element IR → Einsum IR pipeline.
|
|
35
|
+
|
|
36
|
+
## Documentation
|
|
37
|
+
|
|
38
|
+
- **User docs:** <https://sosovski.group/MechDSL/mechdsl-core/> — introduction, getting
|
|
39
|
+
started, the LaTeX directive reference, the constitutive-model catalog, and examples.
|
|
40
|
+
- **Design specs:** `dev/design_docs/` (authoritative source of truth).
|
|
41
|
+
- See the [monorepo root](../../README.md) for the full project overview.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# mechdsl-core
|
|
2
|
+
|
|
3
|
+
Core compiler package for MechDSL — LaTeX tensor expressions to FEM solver code.
|
|
4
|
+
|
|
5
|
+
Handles constitutive equations, element-level physics (Einstein notation), kinematics,
|
|
6
|
+
and Taichi code generation through the Mechanics IR → Element IR → Einsum IR pipeline.
|
|
7
|
+
|
|
8
|
+
## Documentation
|
|
9
|
+
|
|
10
|
+
- **User docs:** <https://sosovski.group/MechDSL/mechdsl-core/> — introduction, getting
|
|
11
|
+
started, the LaTeX directive reference, the constitutive-model catalog, and examples.
|
|
12
|
+
- **Design specs:** `dev/design_docs/` (authoritative source of truth).
|
|
13
|
+
- See the [monorepo root](../../README.md) for the full project overview.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "mechdsl-core"
|
|
7
|
+
version = "0.2.1"
|
|
8
|
+
description = "MechDSL core — LaTeX tensor expressions to FEM solver code"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.11,<3.14"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Shmuel Osovski" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["fem", "finite-elements", "computational-mechanics", "dsl", "taichi", "code-generation"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Science/Research",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Topic :: Scientific/Engineering :: Physics",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"sympy>=1.12",
|
|
26
|
+
"numpy>=2.4.2",
|
|
27
|
+
"opt-einsum>=3.3",
|
|
28
|
+
"pyyaml>=6.0.3",
|
|
29
|
+
"scipy>=1.17.0",
|
|
30
|
+
"nrpylatex>=1.4.0,<2",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
# Taichi is the runtime backend — imported *only* on the verify() / run path
|
|
35
|
+
# (the emit, transpile, capabilities and model_catalog surfaces are proven
|
|
36
|
+
# Taichi-free; see tests/test_integration_surface.py::*taichi_free*). It lives
|
|
37
|
+
# in the `verify` extra so downstream consumers (compmech_reference_pack,
|
|
38
|
+
# akms_learn, the Logic-Loom sidecar) can install mechdsl-core for code
|
|
39
|
+
# emission without pulling Taichi's ~170 MB into their closure. Install
|
|
40
|
+
# `mechdsl-core[verify]` to run verification / solves. opt-einsum stays a base
|
|
41
|
+
# dep — it is a 0.4 MB pure-Python compile-time requirement of the emit path.
|
|
42
|
+
#
|
|
43
|
+
# The generated matrix-free SVK tangent @ti.kernel emits
|
|
44
|
+
# `from ti_runtime import ...` (Tier-1 tensor helpers + hex8 shape gradients +
|
|
45
|
+
# the apply_A injection seam) — the mechdsl-core -> ti-runtime production
|
|
46
|
+
# dependency edge. ti-runtime is Taichi-bearing, so it rides in the `verify`
|
|
47
|
+
# extra alongside taichi; the base install (emit / transpile / capabilities)
|
|
48
|
+
# stays Taichi-free. The generated matrix-free PCG solver is transpiled via
|
|
49
|
+
# `algo2code` in runtime mode and injected through the ti_runtime `set_solver`
|
|
50
|
+
# seam; algo2code is a stdlib-only compile-time tool and rides in the same
|
|
51
|
+
# extra. `verify` is the full install (~1 GB closure via Taichi) — everything
|
|
52
|
+
# needed to run and verify solves, not just emit code.
|
|
53
|
+
# NOTE: the AD oracle uses central finite differences (mechdsl.verify.ad_oracle)
|
|
54
|
+
# — torch was never imported anywhere and is deliberately NOT a dependency.
|
|
55
|
+
verify = ["taichi>=1.7", "ti-runtime>=0.2.1,<0.3", "algo2code>=0.2.1,<0.3"]
|
|
56
|
+
|
|
57
|
+
[project.scripts]
|
|
58
|
+
mechdsl-lawgen = "mechdsl.lawgen.cli:main"
|
|
59
|
+
|
|
60
|
+
[tool.uv.sources]
|
|
61
|
+
ti-runtime = { workspace = true }
|
|
62
|
+
algo2code = { workspace = true }
|
|
63
|
+
|
|
64
|
+
[project.urls]
|
|
65
|
+
Repository = "https://github.com/CEmM2/MechDSL"
|
|
66
|
+
|
|
67
|
+
[tool.hatch.metadata]
|
|
68
|
+
allow-direct-references = true
|
|
69
|
+
|
|
70
|
+
[tool.hatch.build.targets.wheel]
|
|
71
|
+
packages = ["src/mechdsl"]
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"""MechDSL core — LaTeX tensor expressions to FEM solver code (Taichi).
|
|
2
|
+
|
|
3
|
+
The canonical MVP-stable entry point is :func:`compile_latex`, which accepts
|
|
4
|
+
a LaTeX source string and produces an :class:`~mechdsl.codegen.artifact.ArtifactBundle`.
|
|
5
|
+
The lower-level :func:`compile` is preserved as a programmatic API that
|
|
6
|
+
takes a pre-built :class:`~mechdsl.ir.mechanics_ir.ProblemIR`.
|
|
7
|
+
|
|
8
|
+
See ``README.md`` Support tiers and
|
|
9
|
+
``dev/plans/recovery_plan_latex_contract.md`` Phase 2 (R1) for the recovery
|
|
10
|
+
context.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import TYPE_CHECKING
|
|
16
|
+
|
|
17
|
+
from mechdsl import integration as integration
|
|
18
|
+
from mechdsl.codegen import compile
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from os import PathLike
|
|
22
|
+
|
|
23
|
+
from mechdsl.codegen.artifact import ArtifactBundle
|
|
24
|
+
|
|
25
|
+
__version__ = "0.2.1"
|
|
26
|
+
|
|
27
|
+
# Allowed values for the `profile` argument of :func:`compile_latex`. Module-
|
|
28
|
+
# level so callers can introspect the supported set instead of guessing from
|
|
29
|
+
# the docstring. Add new profiles by extending this set explicitly — never
|
|
30
|
+
# silently relax the gate.
|
|
31
|
+
ALLOWED_PROFILES: frozenset[str] = frozenset({"mvp"})
|
|
32
|
+
|
|
33
|
+
__all__ = ["ALLOWED_PROFILES", "compile", "compile_latex", "integration"]
|
|
34
|
+
|
|
35
|
+
# Authored-invariant markers that select a non-default constitutive derivation
|
|
36
|
+
# path. Principal stretches (lbar1/2/3) belong to the spectral (Ogden) engine;
|
|
37
|
+
# the fiber pseudo-invariant (Ibar4) belongs to the anisotropic (HGO) engine.
|
|
38
|
+
_SPECTRAL_STRETCH = ("lbar1", "lbar2", "lbar3")
|
|
39
|
+
_FIBER_INVARIANT = "Ibar4"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _derive_constitutive_energy(energy_source: str):
|
|
43
|
+
"""Derive the constitutive model, routing by the authored invariants.
|
|
44
|
+
|
|
45
|
+
The free symbols of the parsed energy decide the path (robust to comments,
|
|
46
|
+
unlike a raw substring scan): a fiber pseudo-invariant ``Ibar4`` -> the
|
|
47
|
+
anisotropic (HGO) engine; principal stretches ``lbar1/2/3`` -> the spectral
|
|
48
|
+
(Ogden) engine; otherwise the named-invariant engine. Each engine
|
|
49
|
+
re-validates and rejects symbols outside its own contract.
|
|
50
|
+
"""
|
|
51
|
+
from mechdsl.symbolic.energy import parse_energy_scalar_sympy
|
|
52
|
+
|
|
53
|
+
psi, _ = parse_energy_scalar_sympy(energy_source)
|
|
54
|
+
names = {s.name for s in psi.free_symbols}
|
|
55
|
+
if _FIBER_INVARIANT in names:
|
|
56
|
+
from mechdsl.symbolic.anisotropic_energy import derive_from_anisotropic_energy
|
|
57
|
+
|
|
58
|
+
return derive_from_anisotropic_energy(energy_source)
|
|
59
|
+
if any(s in names for s in _SPECTRAL_STRETCH):
|
|
60
|
+
from mechdsl.symbolic.spectral_energy import derive_from_spectral_energy
|
|
61
|
+
|
|
62
|
+
return derive_from_spectral_energy(energy_source)
|
|
63
|
+
from mechdsl.symbolic.energy import derive_from_energy
|
|
64
|
+
|
|
65
|
+
return derive_from_energy(energy_source)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def compile_latex(
|
|
69
|
+
source: str,
|
|
70
|
+
profile: str = "mvp",
|
|
71
|
+
*,
|
|
72
|
+
energy_source: str | None = None,
|
|
73
|
+
energy_file: str | PathLike[str] | None = None,
|
|
74
|
+
) -> ArtifactBundle:
|
|
75
|
+
"""Compile a LaTeX-source mechanics problem to an artifact bundle.
|
|
76
|
+
|
|
77
|
+
This is the canonical MVP-stable entry point. The function:
|
|
78
|
+
|
|
79
|
+
1. Parses ``source`` through
|
|
80
|
+
:func:`mechdsl.frontend.parse_compile_context`, the math-aware
|
|
81
|
+
frontend entry point that preserves directive-only behaviour while
|
|
82
|
+
rejecting unsupported math-bearing sources before IR construction.
|
|
83
|
+
2. Adapts the resulting context dict to a :class:`ProblemIR` via
|
|
84
|
+
:meth:`ProblemIR.from_latex_semantics` (fgram P6-1). This is the
|
|
85
|
+
LaTeX-semantic constructor: its MVP-stable *core* (dim, formulation,
|
|
86
|
+
element type, material, boundaries) is identical to
|
|
87
|
+
:meth:`ProblemIR.from_context`, so the emitted Taichi code is
|
|
88
|
+
byte-for-byte unchanged. The constructor additionally attaches a
|
|
89
|
+
serializable :class:`~mechdsl.ir.mechanics_ir.LatexSemantics` record
|
|
90
|
+
to the IR (declared fields, directive-tagged constitutive
|
|
91
|
+
``(symbol, role)`` pairs, the weak-form label, and any ``$...$``
|
|
92
|
+
equation roles). That record rides into the artifact bundle's
|
|
93
|
+
``problem_ir_dict["latex_semantics"]`` so emitted code sections are
|
|
94
|
+
traceable back to their source equation roles for review and golden
|
|
95
|
+
diffing — the codegen contract itself stays the typed IR fields
|
|
96
|
+
(``material`` / ``residual_contract``), not the advisory record.
|
|
97
|
+
3. Forwards to :func:`compile` (the existing programmatic façade)
|
|
98
|
+
to run localisation, einsum planning, and Taichi emission.
|
|
99
|
+
|
|
100
|
+
**Backend stability:** Taichi is the only MVP-stable backend on the
|
|
101
|
+
canonical LaTeX compile path. All code produced by this function
|
|
102
|
+
targets the Taichi runtime. MFEM and MOOSE are experimental backends
|
|
103
|
+
preserved in the tree (``mechdsl.codegen.mfem_printer`` and
|
|
104
|
+
``mechdsl.codegen.moose_printer``) but they are not reachable through
|
|
105
|
+
this façade and are not part of the stable contract. Reaching those
|
|
106
|
+
surfaces requires calling the experimental printers directly; see
|
|
107
|
+
``README.md`` Support tiers and
|
|
108
|
+
``dev/plans/recovery_plan_latex_contract.md`` Phase 5 (R4).
|
|
109
|
+
|
|
110
|
+
Parameters
|
|
111
|
+
----------
|
|
112
|
+
source:
|
|
113
|
+
LaTeX source text containing ``% mechanics`` directives.
|
|
114
|
+
profile:
|
|
115
|
+
Compile profile selector. Only ``"mvp"`` is currently accepted;
|
|
116
|
+
other profiles (e.g. extended LaTeX math grammar via NRPyLaTeX,
|
|
117
|
+
non-canonical backends) are deferred to later recovery phases.
|
|
118
|
+
energy_source:
|
|
119
|
+
Optional self-contained nrpylatex strain-energy block (``% declare``
|
|
120
|
+
metric + ``EDD`` strain, then the scalar energy assignment). When
|
|
121
|
+
provided, it is run
|
|
122
|
+
through :func:`mechdsl.symbolic.energy.derive_from_energy` and the
|
|
123
|
+
resulting symbolic PK2 stress + material tangent are attached to the
|
|
124
|
+
:class:`ProblemIR` as ``derived_energy``. The generated solver then
|
|
125
|
+
emits its constitutive law and consistent tangent from the derived
|
|
126
|
+
energy (parameterised on the energy's own material-parameter names),
|
|
127
|
+
instead of the named-model ``(lam, mu)`` dispatch. The problem
|
|
128
|
+
``source``'s ``MaterialSpec`` params must supply a value for every
|
|
129
|
+
parameter the energy uses.
|
|
130
|
+
energy_file:
|
|
131
|
+
Path to a ``.tex`` file holding the same energy block as
|
|
132
|
+
``energy_source``. Mutually exclusive with ``energy_source``; the file
|
|
133
|
+
is read as UTF-8.
|
|
134
|
+
|
|
135
|
+
Boundary conditions
|
|
136
|
+
-------------------
|
|
137
|
+
LaTeX ``% mechanics boundary`` directives populate
|
|
138
|
+
:class:`mechdsl.ir.mechanics_ir.BoundaryCondition` slots on the
|
|
139
|
+
resulting :class:`ProblemIR`. Two boundary kinds are supported:
|
|
140
|
+
|
|
141
|
+
- **Dirichlet** — fixed displacement components, applied at solve
|
|
142
|
+
time by the runtime adapter.
|
|
143
|
+
- **Neumann** — surface tractions. When the directive carries a
|
|
144
|
+
numeric traction triple, post_recovery_plan P1-5 emits an
|
|
145
|
+
``f_ext`` initialisation kernel (see ``f_ext_kernel`` in
|
|
146
|
+
*Returns* below) and the bundle is self-contained for that BC.
|
|
147
|
+
Neumann BCs with a symbolic-string traction leave the kernel
|
|
148
|
+
slot empty.
|
|
149
|
+
|
|
150
|
+
Numeric ``f_ext`` provisioning is the **caller's responsibility**
|
|
151
|
+
when no kernel is emitted (Dirichlet-only problems or
|
|
152
|
+
symbolic-traction Neumann): the caller supplies the global
|
|
153
|
+
external-force vector to the solver. When ``f_ext_kernel`` is
|
|
154
|
+
present, the emitted kernel overrides any manual ``f_ext``
|
|
155
|
+
provisioning for the directive-driven contribution; the caller
|
|
156
|
+
is still responsible for compositing it with any additional body
|
|
157
|
+
forces. ``BoundaryCondition`` objects therefore document intent
|
|
158
|
+
at the IR level, while the artifact bundle decides whether the
|
|
159
|
+
contract is satisfied entirely by emitted code or jointly by
|
|
160
|
+
caller-provided ``f_ext``.
|
|
161
|
+
|
|
162
|
+
Returns
|
|
163
|
+
-------
|
|
164
|
+
ArtifactBundle
|
|
165
|
+
The same bundle :func:`compile` produces, ready for golden-file
|
|
166
|
+
comparison or Taichi emission. When the parsed problem contains
|
|
167
|
+
one or more Neumann BCs with numeric traction (post_recovery_plan
|
|
168
|
+
P1-5), the bundle's optional ``f_ext_kernel`` field carries the
|
|
169
|
+
emitted ``init_f_ext_from_neumann_<bc>`` kernel source. The kernel
|
|
170
|
+
signature is parametric in ``f_factor`` (= face_area /
|
|
171
|
+
n_face_nodes) so the runtime mesh adapter supplies the per-node
|
|
172
|
+
weighting at call time. Pure Dirichlet problems and Neumann BCs
|
|
173
|
+
with symbolic-string traction leave ``f_ext_kernel`` at ``None``;
|
|
174
|
+
existing residual / tangent fields and ``emitted_source`` shape
|
|
175
|
+
are unchanged.
|
|
176
|
+
|
|
177
|
+
Raises
|
|
178
|
+
------
|
|
179
|
+
ValueError
|
|
180
|
+
When ``profile`` is anything other than ``"mvp"``.
|
|
181
|
+
mechdsl.frontend.parser.ParseError
|
|
182
|
+
When the LaTeX source has a malformed ``% mechanics`` directive.
|
|
183
|
+
mechdsl.frontend.FrontendSemanticError
|
|
184
|
+
When a math-bearing LaTeX source cannot produce supported frontend
|
|
185
|
+
math semantics before IR construction.
|
|
186
|
+
mechdsl.symbolic.convected.UnsupportedError
|
|
187
|
+
When the parsed context falls outside the MVP-supported subset.
|
|
188
|
+
|
|
189
|
+
"""
|
|
190
|
+
if profile not in ALLOWED_PROFILES:
|
|
191
|
+
raise ValueError(
|
|
192
|
+
f"compile_latex profile={profile!r} is not supported. "
|
|
193
|
+
f"Allowed profiles: {sorted(ALLOWED_PROFILES)}. "
|
|
194
|
+
"Broader profile support is planned for later recovery-plan "
|
|
195
|
+
"phases (see dev/plans/recovery_plan_latex_contract.md)."
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
if energy_source is not None and energy_file is not None:
|
|
199
|
+
raise ValueError(
|
|
200
|
+
"compile_latex accepts at most one of energy_source / energy_file, not both."
|
|
201
|
+
)
|
|
202
|
+
if energy_file is not None:
|
|
203
|
+
from pathlib import Path
|
|
204
|
+
|
|
205
|
+
energy_source = Path(energy_file).read_text(encoding="utf-8")
|
|
206
|
+
|
|
207
|
+
from mechdsl.frontend import parse_compile_context
|
|
208
|
+
|
|
209
|
+
ctx = parse_compile_context(source)
|
|
210
|
+
|
|
211
|
+
import dataclasses
|
|
212
|
+
|
|
213
|
+
from mechdsl.codegen.taichi_printer import (
|
|
214
|
+
EmissionContext,
|
|
215
|
+
emit_neumann_f_ext_kernel_for_ir,
|
|
216
|
+
)
|
|
217
|
+
from mechdsl.ir.mechanics_ir import BCType, ProblemIR
|
|
218
|
+
|
|
219
|
+
# Build the IR through the LaTeX-semantic constructor so the emitted
|
|
220
|
+
# bundle carries the source-role metadata (latex_semantics) that links
|
|
221
|
+
# generated code sections back to source equation roles. The MVP-stable
|
|
222
|
+
# core is identical to from_context, so emitted Taichi is unchanged;
|
|
223
|
+
# only the additive latex_semantics record is new.
|
|
224
|
+
problem_ir = ProblemIR.from_latex_semantics(ctx)
|
|
225
|
+
# When a strain-energy block was supplied, derive its symbolic stress and
|
|
226
|
+
# attach it to the IR. The codegen layer then emits the constitutive law and
|
|
227
|
+
# consistent tangent from the derived energy (taichi_printer + the matching
|
|
228
|
+
# emitter), parameterised on the energy's own material-parameter names rather
|
|
229
|
+
# than the named-model (lam, mu) dispatch. The derivation path is selected
|
|
230
|
+
# from the authored invariants: principal stretches (Ogden) -> spectral,
|
|
231
|
+
# a fiber pseudo-invariant (HGO) -> anisotropic, else the named-invariant path.
|
|
232
|
+
if energy_source is not None:
|
|
233
|
+
problem_ir = dataclasses.replace(
|
|
234
|
+
problem_ir, derived_energy=_derive_constitutive_energy(energy_source)
|
|
235
|
+
)
|
|
236
|
+
# Enforce the MVP-stable contract at the canonical compile-path
|
|
237
|
+
# boundary so users hitting an experimental combination or a missing
|
|
238
|
+
# required-param see a clean IR-level rejection instead of a deep
|
|
239
|
+
# codegen / runtime failure.
|
|
240
|
+
problem_ir.assert_mvp_stable()
|
|
241
|
+
bundle = compile(problem_ir)
|
|
242
|
+
|
|
243
|
+
# Surface a Neumann ``f_ext`` initialisation kernel for every Neumann
|
|
244
|
+
# BC carrying numeric traction. Symbolic (string) traction stays
|
|
245
|
+
# handled by the legacy imported numeric injection path so existing
|
|
246
|
+
# callers keep working unchanged. Pure Dirichlet problems leave
|
|
247
|
+
# ``f_ext_kernel`` at ``None``.
|
|
248
|
+
neumann_bcs = [
|
|
249
|
+
bc
|
|
250
|
+
for bc in problem_ir.boundaries
|
|
251
|
+
if bc.bc_type == BCType.NEUMANN and isinstance(bc.traction, tuple)
|
|
252
|
+
]
|
|
253
|
+
if not neumann_bcs:
|
|
254
|
+
return bundle
|
|
255
|
+
em_ctx = EmissionContext()
|
|
256
|
+
for bc in neumann_bcs:
|
|
257
|
+
emit_neumann_f_ext_kernel_for_ir(
|
|
258
|
+
em_ctx,
|
|
259
|
+
bc_name=bc.name,
|
|
260
|
+
surface_tag=bc.effective_surface_tag,
|
|
261
|
+
traction=bc.traction, # type: ignore[arg-type]
|
|
262
|
+
)
|
|
263
|
+
return dataclasses.replace(bundle, f_ext_kernel=em_ctx.get_source())
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Einsum optimizer, Taichi code generation, boundary condition codegen.
|
|
2
|
+
|
|
3
|
+
Backend support tiers
|
|
4
|
+
---------------------
|
|
5
|
+
The MVP-stable canonical backend is :mod:`mechdsl.codegen.taichi_printer`.
|
|
6
|
+
:mod:`mechdsl.codegen.mfem_printer` and :mod:`mechdsl.codegen.moose_printer`
|
|
7
|
+
are preserved in-tree as **experimental** surfaces (see
|
|
8
|
+
``dev/plans/recovery_plan_latex_contract.md`` Phase 5 (R4)).
|
|
9
|
+
|
|
10
|
+
The ``__experimental__`` convention
|
|
11
|
+
-----------------------------------
|
|
12
|
+
Every experimental printer module exposes a module-level constant::
|
|
13
|
+
|
|
14
|
+
__experimental__: bool = True
|
|
15
|
+
|
|
16
|
+
so callers and tests can detect experimental status programmatically::
|
|
17
|
+
|
|
18
|
+
from mechdsl.codegen import mfem_printer
|
|
19
|
+
assert mfem_printer.__experimental__ is True
|
|
20
|
+
|
|
21
|
+
Stable backends do **not** set this flag. On the first call to its public
|
|
22
|
+
``emit`` function, each experimental printer additionally raises a single
|
|
23
|
+
:class:`mechdsl.codegen._experimental.ExperimentalBackendWarning` that can
|
|
24
|
+
be filtered with the standard :mod:`warnings` machinery.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
from typing import TYPE_CHECKING
|
|
30
|
+
|
|
31
|
+
from mechdsl.codegen._experimental import ExperimentalBackendWarning
|
|
32
|
+
from mechdsl.codegen.taichi_printer import TaichiCodegenFacade
|
|
33
|
+
|
|
34
|
+
if TYPE_CHECKING:
|
|
35
|
+
from mechdsl.codegen.artifact import ArtifactBundle
|
|
36
|
+
from mechdsl.ir.mechanics_ir import ProblemIR
|
|
37
|
+
|
|
38
|
+
__all__ = ["ExperimentalBackendWarning", "TaichiCodegenFacade", "compile"]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def compile(problem_ir: ProblemIR) -> ArtifactBundle:
|
|
42
|
+
"""Compile a ProblemIR into a self-contained Taichi solver.
|
|
43
|
+
|
|
44
|
+
Runs the full pipeline: localise → optimise → emit.
|
|
45
|
+
|
|
46
|
+
**Backend stability:** Taichi is the only MVP-stable backend on the
|
|
47
|
+
canonical LaTeX compile path. MFEM and MOOSE printers exist in the
|
|
48
|
+
tree as experimental surfaces (see ``mechdsl.codegen.mfem_printer``
|
|
49
|
+
and ``mechdsl.codegen.moose_printer``) but they are not part of the
|
|
50
|
+
stable contract and may not be supported in future recovery phases
|
|
51
|
+
without explicit roadmap work (Plan B §B8).
|
|
52
|
+
|
|
53
|
+
Parameters
|
|
54
|
+
----------
|
|
55
|
+
problem_ir : ProblemIR
|
|
56
|
+
The semantic problem specification.
|
|
57
|
+
|
|
58
|
+
Returns
|
|
59
|
+
-------
|
|
60
|
+
ArtifactBundle
|
|
61
|
+
Bundle with ``emitted_source`` populated. Contains all
|
|
62
|
+
intermediate products (IRs, contraction plans).
|
|
63
|
+
|
|
64
|
+
Raises
|
|
65
|
+
------
|
|
66
|
+
ValueError
|
|
67
|
+
Propagated when the IR contains an unsupported formulation,
|
|
68
|
+
element type, or material model for the MVP pipeline.
|
|
69
|
+
BudgetExceededError
|
|
70
|
+
Propagated when einsum optimisation exceeds the absolute JIT
|
|
71
|
+
budget ceiling.
|
|
72
|
+
"""
|
|
73
|
+
from mechdsl.codegen.artifact import ArtifactBundle as _AB
|
|
74
|
+
from mechdsl.codegen.taichi_printer import emit
|
|
75
|
+
from mechdsl.lowering.fe_localise import localise_and_optimize
|
|
76
|
+
|
|
77
|
+
loc_result, plans = localise_and_optimize(problem_ir)
|
|
78
|
+
bundle = _AB.from_pipeline(problem_ir, loc_result, plans)
|
|
79
|
+
source = emit(bundle)
|
|
80
|
+
|
|
81
|
+
return _AB(
|
|
82
|
+
problem_ir_dict=bundle.problem_ir_dict,
|
|
83
|
+
element_ir_summary=bundle.element_ir_summary,
|
|
84
|
+
contraction_plans=bundle.contraction_plans,
|
|
85
|
+
emitted_source=source,
|
|
86
|
+
metadata=bundle.metadata,
|
|
87
|
+
# Preserve the derived-energy Python-object channel through the
|
|
88
|
+
# bundle rebuild so a LaTeX-derived constitutive law reaches codegen.
|
|
89
|
+
derived_energy=bundle.derived_energy,
|
|
90
|
+
)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Experimental-backend infrastructure for mechdsl.codegen.
|
|
2
|
+
|
|
3
|
+
Defines the shared :class:`ExperimentalBackendWarning` that each non-stable
|
|
4
|
+
printer emits on first use, and documents the ``__experimental__`` flag
|
|
5
|
+
convention used across the codegen package.
|
|
6
|
+
|
|
7
|
+
Convention
|
|
8
|
+
----------
|
|
9
|
+
Every experimental backend module exposes a module-level constant::
|
|
10
|
+
|
|
11
|
+
__experimental__: bool = True
|
|
12
|
+
|
|
13
|
+
This allows tooling and tests to detect experimental status
|
|
14
|
+
programmatically (e.g. ``import mechdsl.codegen.mfem_printer as m;
|
|
15
|
+
assert m.__experimental__``) rather than parsing docstrings. Stable
|
|
16
|
+
backends (currently only :mod:`mechdsl.codegen.taichi_printer`) do **not**
|
|
17
|
+
set this flag.
|
|
18
|
+
|
|
19
|
+
At runtime, each experimental printer emits one
|
|
20
|
+
:class:`ExperimentalBackendWarning` per Python session on the first call to
|
|
21
|
+
its public ``emit`` function. The warning is filterable with the standard
|
|
22
|
+
:mod:`warnings` machinery::
|
|
23
|
+
|
|
24
|
+
import warnings
|
|
25
|
+
warnings.filterwarnings("ignore", category=ExperimentalBackendWarning)
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import warnings
|
|
31
|
+
|
|
32
|
+
__all__ = ["ExperimentalBackendWarning", "warn_experimental_backend_once"]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ExperimentalBackendWarning(UserWarning):
|
|
36
|
+
"""Warning raised on the first call to an experimental codegen backend.
|
|
37
|
+
|
|
38
|
+
Experimental backends (MFEM, MOOSE) are preserved in-tree but are not
|
|
39
|
+
part of the MVP stable contract. This warning signals that the caller
|
|
40
|
+
is using a surface outside the stable Taichi compile path.
|
|
41
|
+
|
|
42
|
+
Filter with::
|
|
43
|
+
|
|
44
|
+
import warnings
|
|
45
|
+
warnings.filterwarnings("ignore", category=ExperimentalBackendWarning)
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def warn_experimental_backend_once(state: dict, backend_name: str) -> None:
|
|
50
|
+
"""Emit an ExperimentalBackendWarning the first time this is called for the given state.
|
|
51
|
+
|
|
52
|
+
Idempotent: subsequent calls with the same state dict are no-ops.
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
state : dict
|
|
57
|
+
Module-level dict tracking warning state. Caller passes a single shared
|
|
58
|
+
dict (e.g. ``_warn_state``); this function flips ``state["warned"]`` to True.
|
|
59
|
+
backend_name : str
|
|
60
|
+
Human-readable backend name (e.g. "MFEM", "MOOSE") for the warning message.
|
|
61
|
+
"""
|
|
62
|
+
if state.get("warned"):
|
|
63
|
+
return
|
|
64
|
+
warnings.warn(
|
|
65
|
+
f"{backend_name} backend is experimental — its API may change without "
|
|
66
|
+
f"deprecation notice. Suppress with "
|
|
67
|
+
f"warnings.filterwarnings('ignore', category=ExperimentalBackendWarning).",
|
|
68
|
+
ExperimentalBackendWarning,
|
|
69
|
+
stacklevel=3,
|
|
70
|
+
)
|
|
71
|
+
state["warned"] = True
|