parosol-py 0.1.3__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.
Files changed (165) hide show
  1. parosol_py-0.1.3/.github/workflows/build-wheels.yml +152 -0
  2. parosol_py-0.1.3/.github/workflows/publish-from-run.yml +65 -0
  3. parosol_py-0.1.3/.github/workflows/tests.yml +104 -0
  4. parosol_py-0.1.3/.gitignore +12 -0
  5. parosol_py-0.1.3/CMakeLists.txt +7 -0
  6. parosol_py-0.1.3/PKG-INFO +153 -0
  7. parosol_py-0.1.3/README.md +126 -0
  8. parosol_py-0.1.3/pyproject.toml +71 -0
  9. parosol_py-0.1.3/scripts/benchmark_torch_backend.py +136 -0
  10. parosol_py-0.1.3/scripts/install_prebuilt.py +102 -0
  11. parosol_py-0.1.3/scripts/local_check.py +154 -0
  12. parosol_py-0.1.3/src/parosol_native/CMakeLists.txt +35 -0
  13. parosol_py-0.1.3/src/parosol_native/LICENSE +15 -0
  14. parosol_py-0.1.3/src/parosol_native/src/AsciiImage.cpp +177 -0
  15. parosol_py-0.1.3/src/parosol_native/src/AsciiImage.h +90 -0
  16. parosol_py-0.1.3/src/parosol_native/src/AsciiImageMirrored.cpp +178 -0
  17. parosol_py-0.1.3/src/parosol_native/src/AsciiImageMirrored.h +73 -0
  18. parosol_py-0.1.3/src/parosol_native/src/BaseGrid.h +96 -0
  19. parosol_py-0.1.3/src/parosol_native/src/BoundaryCondition.h +95 -0
  20. parosol_py-0.1.3/src/parosol_native/src/CPULayout.h +144 -0
  21. parosol_py-0.1.3/src/parosol_native/src/Chebyshev.cpp +98 -0
  22. parosol_py-0.1.3/src/parosol_native/src/Chebyshev.h +88 -0
  23. parosol_py-0.1.3/src/parosol_native/src/Config.h +82 -0
  24. parosol_py-0.1.3/src/parosol_native/src/Doxyfile +1512 -0
  25. parosol_py-0.1.3/src/parosol_native/src/GReader.cpp +498 -0
  26. parosol_py-0.1.3/src/parosol_native/src/GReader.hpp +1595 -0
  27. parosol_py-0.1.3/src/parosol_native/src/GWriter.cpp +460 -0
  28. parosol_py-0.1.3/src/parosol_native/src/GWriter.hpp +1158 -0
  29. parosol_py-0.1.3/src/parosol_native/src/GenericMatrix.h +394 -0
  30. parosol_py-0.1.3/src/parosol_native/src/HDF5Image.cpp +232 -0
  31. parosol_py-0.1.3/src/parosol_native/src/HDF5Image.h +74 -0
  32. parosol_py-0.1.3/src/parosol_native/src/HDF5ParfePrinter.h +206 -0
  33. parosol_py-0.1.3/src/parosol_native/src/HDF5Printer.h +231 -0
  34. parosol_py-0.1.3/src/parosol_native/src/ImageReader.h +73 -0
  35. parosol_py-0.1.3/src/parosol_native/src/Jacobi.h +56 -0
  36. parosol_py-0.1.3/src/parosol_native/src/JacobiSmoother.cpp +36 -0
  37. parosol_py-0.1.3/src/parosol_native/src/JacobiSmoother.h +92 -0
  38. parosol_py-0.1.3/src/parosol_native/src/KeyGenerator.h +111 -0
  39. parosol_py-0.1.3/src/parosol_native/src/MlCycle.h +238 -0
  40. parosol_py-0.1.3/src/parosol_native/src/MlLevelCG.h +53 -0
  41. parosol_py-0.1.3/src/parosol_native/src/MlLevelCheb.h +58 -0
  42. parosol_py-0.1.3/src/parosol_native/src/MlOctreeGrid.h +462 -0
  43. parosol_py-0.1.3/src/parosol_native/src/OctreeGrid.h +1670 -0
  44. parosol_py-0.1.3/src/parosol_native/src/OctreeNode.h +62 -0
  45. parosol_py-0.1.3/src/parosol_native/src/OptLocalMatrix.h +188 -0
  46. parosol_py-0.1.3/src/parosol_native/src/PCGSolver.cpp +172 -0
  47. parosol_py-0.1.3/src/parosol_native/src/PCGSolver.h +79 -0
  48. parosol_py-0.1.3/src/parosol_native/src/Postprocessing.h +182 -0
  49. parosol_py-0.1.3/src/parosol_native/src/Problem.h +262 -0
  50. parosol_py-0.1.3/src/parosol_native/src/Solver.h +55 -0
  51. parosol_py-0.1.3/src/parosol_native/src/StiffnessMatrix.h +86 -0
  52. parosol_py-0.1.3/src/parosol_native/src/Testtools.h +196 -0
  53. parosol_py-0.1.3/src/parosol_native/src/Timing.h +145 -0
  54. parosol_py-0.1.3/src/parosol_native/src/Toolbox.cpp +59 -0
  55. parosol_py-0.1.3/src/parosol_native/src/Toolbox.h +28 -0
  56. parosol_py-0.1.3/src/parosol_native/src/VTKPrinter.h +334 -0
  57. parosol_py-0.1.3/src/parosol_native/src/est_ev.cpp +87 -0
  58. parosol_py-0.1.3/src/parosol_native/src/est_ev.h +40 -0
  59. parosol_py-0.1.3/src/parosol_native/src/fem.cpp +723 -0
  60. parosol_py-0.1.3/src/parosol_native/src/fem.h +113 -0
  61. parosol_py-0.1.3/src/parosol_native/src/main.cpp +300 -0
  62. parosol_py-0.1.3/src/parosol_native/src/tri_eig.h +76 -0
  63. parosol_py-0.1.3/src/parosol_py/__init__.py +52 -0
  64. parosol_py-0.1.3/src/parosol_py/_version.py +1 -0
  65. parosol_py-0.1.3/src/parosol_py/api.py +354 -0
  66. parosol_py-0.1.3/src/parosol_py/batch.py +410 -0
  67. parosol_py-0.1.3/src/parosol_py/boundary_conditions.py +67 -0
  68. parosol_py-0.1.3/src/parosol_py/bundle.py +346 -0
  69. parosol_py-0.1.3/src/parosol_py/cli.py +646 -0
  70. parosol_py-0.1.3/src/parosol_py/config.py +1348 -0
  71. parosol_py-0.1.3/src/parosol_py/config_templates/default.yaml +239 -0
  72. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/batch.yaml +10 -0
  73. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/bending_z.yaml +13 -0
  74. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/coarse_preview.yaml +8 -0
  75. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/constrained_axial_z.yaml +14 -0
  76. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/debug.yaml +9 -0
  77. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/debug_sets.yaml +6 -0
  78. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/density_power.yaml +14 -0
  79. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/direct_mechanics_manifest.yaml +15 -0
  80. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/load_history_3.yaml +29 -0
  81. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/load_history_6.yaml +49 -0
  82. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/progressive_loading_manifest.yaml +14 -0
  83. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/proximal_femur.yaml +71 -0
  84. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/proximal_femur_sideways_fall.yaml +81 -0
  85. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/shear_zx.yaml +12 -0
  86. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/shear_zy.yaml +12 -0
  87. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/smart_bone_compression_z.yaml +17 -0
  88. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/standard_fields.yaml +8 -0
  89. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/standard_mechanics_fields.yaml +9 -0
  90. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/torsion_z.yaml +12 -0
  91. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/vertebra.yaml +93 -0
  92. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/xtremecti.yaml +29 -0
  93. parosol_py-0.1.3/src/parosol_py/config_templates/profiles/xtremectii.yaml +29 -0
  94. parosol_py-0.1.3/src/parosol_py/config_templates.py +36 -0
  95. parosol_py-0.1.3/src/parosol_py/core.py +139 -0
  96. parosol_py-0.1.3/src/parosol_py/diagnostics.py +792 -0
  97. parosol_py-0.1.3/src/parosol_py/field_export.py +195 -0
  98. parosol_py-0.1.3/src/parosol_py/hdf5_io.py +143 -0
  99. parosol_py-0.1.3/src/parosol_py/images.py +149 -0
  100. parosol_py-0.1.3/src/parosol_py/licenses/parosol_native_LICENSE.txt +15 -0
  101. parosol_py-0.1.3/src/parosol_py/load_cases.py +407 -0
  102. parosol_py-0.1.3/src/parosol_py/load_history.py +287 -0
  103. parosol_py-0.1.3/src/parosol_py/materials.py +366 -0
  104. parosol_py-0.1.3/src/parosol_py/modeling/__init__.py +4 -0
  105. parosol_py-0.1.3/src/parosol_py/modeling/alignment.py +508 -0
  106. parosol_py-0.1.3/src/parosol_py/modeling/builder.py +47 -0
  107. parosol_py-0.1.3/src/parosol_py/modeling/common.py +754 -0
  108. parosol_py-0.1.3/src/parosol_py/modeling/femur.py +360 -0
  109. parosol_py-0.1.3/src/parosol_py/modeling/io.py +61 -0
  110. parosol_py-0.1.3/src/parosol_py/modeling/spine.py +308 -0
  111. parosol_py-0.1.3/src/parosol_py/modeling/types.py +23 -0
  112. parosol_py-0.1.3/src/parosol_py/nodesets.py +413 -0
  113. parosol_py-0.1.3/src/parosol_py/paths.py +24 -0
  114. parosol_py-0.1.3/src/parosol_py/profiles.py +51 -0
  115. parosol_py-0.1.3/src/parosol_py/reference_validation.py +102 -0
  116. parosol_py-0.1.3/src/parosol_py/reports.py +462 -0
  117. parosol_py-0.1.3/src/parosol_py/results.py +67 -0
  118. parosol_py-0.1.3/src/parosol_py/runner.py +168 -0
  119. parosol_py-0.1.3/src/parosol_py/set_export.py +117 -0
  120. parosol_py-0.1.3/src/parosol_py/surfaces.py +168 -0
  121. parosol_py-0.1.3/src/parosol_py/validation.py +49 -0
  122. parosol_py-0.1.3/src/parosol_py/visualization.py +849 -0
  123. parosol_py-0.1.3/src/parosol_py/workflow_template.py +188 -0
  124. parosol_py-0.1.3/src/parosol_torch/__init__.py +28 -0
  125. parosol_py-0.1.3/src/parosol_torch/backend.py +102 -0
  126. parosol_py-0.1.3/src/parosol_torch/contract.py +82 -0
  127. parosol_py-0.1.3/src/parosol_torch/elasticity.py +406 -0
  128. parosol_py-0.1.3/src/parosol_torch/prototype.py +28 -0
  129. parosol_py-0.1.3/src/parosol_torch/registry.py +51 -0
  130. parosol_py-0.1.3/tests/fixtures/reference/SAMPLE_HOM_LS.AIM +1 -0
  131. parosol_py-0.1.3/tests/fixtures/reference/SAMPLE_HOM_LS_analysis.txt +43 -0
  132. parosol_py-0.1.3/tests/fixtures/reference/SAMPLE_HOM_LS_pistoia.txt +14 -0
  133. parosol_py-0.1.3/tests/fixtures/trab1240/material_table.yaml +7 -0
  134. parosol_py-0.1.3/tests/fixtures/trab1240/reference.json +40 -0
  135. parosol_py-0.1.3/tests/fixtures/trab1240/reference_sed.npz +0 -0
  136. parosol_py-0.1.3/tests/fixtures/trab1240/trab1240_labels.npz +0 -0
  137. parosol_py-0.1.3/tests/test_api.py +405 -0
  138. parosol_py-0.1.3/tests/test_batch.py +515 -0
  139. parosol_py-0.1.3/tests/test_boundary_conditions.py +48 -0
  140. parosol_py-0.1.3/tests/test_bundle.py +105 -0
  141. parosol_py-0.1.3/tests/test_config_cli.py +2272 -0
  142. parosol_py-0.1.3/tests/test_config_templates.py +92 -0
  143. parosol_py-0.1.3/tests/test_core.py +51 -0
  144. parosol_py-0.1.3/tests/test_diagnostics.py +299 -0
  145. parosol_py-0.1.3/tests/test_field_export.py +58 -0
  146. parosol_py-0.1.3/tests/test_hdf5_io.py +167 -0
  147. parosol_py-0.1.3/tests/test_images.py +49 -0
  148. parosol_py-0.1.3/tests/test_load_cases.py +225 -0
  149. parosol_py-0.1.3/tests/test_load_history.py +72 -0
  150. parosol_py-0.1.3/tests/test_materials.py +187 -0
  151. parosol_py-0.1.3/tests/test_modeling.py +603 -0
  152. parosol_py-0.1.3/tests/test_nodesets.py +54 -0
  153. parosol_py-0.1.3/tests/test_packaging.py +88 -0
  154. parosol_py-0.1.3/tests/test_parosol_torch.py +163 -0
  155. parosol_py-0.1.3/tests/test_profiles.py +11 -0
  156. parosol_py-0.1.3/tests/test_reference_validation.py +49 -0
  157. parosol_py-0.1.3/tests/test_reports.py +121 -0
  158. parosol_py-0.1.3/tests/test_results.py +41 -0
  159. parosol_py-0.1.3/tests/test_runner.py +96 -0
  160. parosol_py-0.1.3/tests/test_set_export.py +44 -0
  161. parosol_py-0.1.3/tests/test_solver_smoke.py +31 -0
  162. parosol_py-0.1.3/tests/test_surfaces.py +42 -0
  163. parosol_py-0.1.3/tests/test_trab1240_reference.py +176 -0
  164. parosol_py-0.1.3/tests/test_validation.py +28 -0
  165. parosol_py-0.1.3/tests/test_visualization.py +98 -0
@@ -0,0 +1,152 @@
1
+ name: Build Wheels
2
+
3
+ "on":
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ build_wheels:
11
+ runs-on: ${{ matrix.os }}
12
+ permissions:
13
+ contents: read
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ include:
18
+ - os: ubuntu-latest
19
+ artifact: manylinux-x86_64
20
+ cibw_arch: x86_64
21
+ - os: windows-latest
22
+ artifact: windows-amd64
23
+ cibw_arch: AMD64
24
+ - os: macos-latest
25
+ artifact: macos-arm64
26
+ cibw_arch: arm64
27
+ - os: macos-15-intel
28
+ artifact: macos-x86_64
29
+ cibw_arch: x86_64
30
+
31
+ steps:
32
+ - name: Checkout code
33
+ uses: actions/checkout@v4
34
+ with:
35
+ submodules: recursive
36
+
37
+ - name: Set up Python
38
+ uses: actions/setup-python@v5
39
+ with:
40
+ python-version: "3.12"
41
+
42
+ - name: Cache vcpkg artifacts (Windows)
43
+ if: matrix.os == 'windows-latest'
44
+ uses: actions/cache@v4
45
+ with:
46
+ path: |
47
+ C:\vcpkg\downloads
48
+ C:\vcpkg\buildtrees
49
+ C:\vcpkg\packages
50
+ C:\vcpkg\installed
51
+ C:\vcpkg\bincache
52
+ key: ${{ runner.os }}-vcpkg-parosol-v1-${{ hashFiles('pyproject.toml', '.github/workflows/build-wheels.yml') }}
53
+ restore-keys: |
54
+ ${{ runner.os }}-vcpkg-parosol-v1-
55
+
56
+ - name: Install cibuildwheel
57
+ run: |
58
+ python -m pip install --upgrade pip cibuildwheel
59
+
60
+ - name: Build wheels (cibuildwheel)
61
+ env:
62
+ CIBW_ARCHS: ${{ matrix.cibw_arch }}
63
+ run: python -m cibuildwheel --output-dir dist
64
+
65
+ - name: Upload wheel artifacts
66
+ uses: actions/upload-artifact@v4
67
+ with:
68
+ name: wheels-${{ matrix.artifact }}
69
+ path: ./dist/*.whl
70
+
71
+ build_sdist:
72
+ runs-on: ubuntu-latest
73
+ permissions:
74
+ contents: read
75
+ steps:
76
+ - name: Checkout code
77
+ uses: actions/checkout@v4
78
+ with:
79
+ submodules: recursive
80
+
81
+ - name: Set up Python
82
+ uses: actions/setup-python@v5
83
+ with:
84
+ python-version: "3.12"
85
+
86
+ - name: Build sdist
87
+ run: |
88
+ python -m pip install --upgrade pip build
89
+ python -m build --sdist --outdir dist
90
+
91
+ - name: Upload sdist artifact
92
+ uses: actions/upload-artifact@v4
93
+ with:
94
+ name: sdist
95
+ path: ./dist/*.tar.gz
96
+
97
+ publish:
98
+ needs: [build_wheels, build_sdist]
99
+ runs-on: ubuntu-latest
100
+ if: startsWith(github.ref, 'refs/tags/v')
101
+ permissions:
102
+ id-token: write
103
+ contents: write
104
+ environment:
105
+ name: pypi
106
+ url: https://pypi.org/p/parosol-py
107
+ steps:
108
+ - name: Download wheel artifacts
109
+ uses: actions/download-artifact@v4
110
+ with:
111
+ pattern: wheels-*
112
+ path: dist
113
+ merge-multiple: true
114
+
115
+ - name: Download sdist artifact
116
+ uses: actions/download-artifact@v4
117
+ with:
118
+ name: sdist
119
+ path: dist
120
+
121
+ - name: Set up Python for debug tooling
122
+ uses: actions/setup-python@v5
123
+ with:
124
+ python-version: "3.12"
125
+
126
+ - name: Debug artifact inventory
127
+ run: |
128
+ echo "Current dist/ contents:"
129
+ ls -lah dist
130
+ echo
131
+ echo "Wheel files:"
132
+ ls -1 dist/*.whl || true
133
+ echo
134
+ echo "Source distributions:"
135
+ ls -1 dist/*.tar.gz || true
136
+
137
+ - name: Twine check
138
+ run: |
139
+ python -m pip install --upgrade pip twine
140
+ python -m twine check dist/*
141
+
142
+ - name: Upload wheels to GitHub Release
143
+ uses: softprops/action-gh-release@v2
144
+ with:
145
+ files: |
146
+ dist/*.whl
147
+ dist/*.tar.gz
148
+
149
+ - name: Publish to PyPI
150
+ uses: pypa/gh-action-pypi-publish@release/v1
151
+ with:
152
+ verbose: true
@@ -0,0 +1,65 @@
1
+ name: Publish From Existing Run
2
+
3
+ "on":
4
+ workflow_dispatch:
5
+ inputs:
6
+ source_run_id:
7
+ description: "GitHub Actions run ID that already contains wheels + sdist artifacts"
8
+ required: true
9
+ type: string
10
+
11
+ jobs:
12
+ publish:
13
+ runs-on: ubuntu-latest
14
+ permissions:
15
+ id-token: write
16
+ contents: read
17
+ actions: read
18
+ environment:
19
+ name: pypi
20
+ url: https://pypi.org/p/parosol-py
21
+ steps:
22
+ - name: Download wheel artifacts from source run
23
+ uses: actions/download-artifact@v4
24
+ with:
25
+ github-token: ${{ secrets.GITHUB_TOKEN }}
26
+ repository: ${{ github.repository }}
27
+ run-id: ${{ inputs.source_run_id }}
28
+ pattern: wheels-*
29
+ path: dist
30
+ merge-multiple: true
31
+
32
+ - name: Download sdist artifact from source run
33
+ uses: actions/download-artifact@v4
34
+ with:
35
+ github-token: ${{ secrets.GITHUB_TOKEN }}
36
+ repository: ${{ github.repository }}
37
+ run-id: ${{ inputs.source_run_id }}
38
+ name: sdist
39
+ path: dist
40
+
41
+ - name: Set up Python for debug tooling
42
+ uses: actions/setup-python@v5
43
+ with:
44
+ python-version: "3.12"
45
+
46
+ - name: Debug artifact inventory
47
+ run: |
48
+ echo "Current dist/ contents:"
49
+ ls -lah dist
50
+ echo
51
+ echo "Wheel files:"
52
+ ls -1 dist/*.whl || true
53
+ echo
54
+ echo "Source distributions:"
55
+ ls -1 dist/*.tar.gz || true
56
+
57
+ - name: Twine check
58
+ run: |
59
+ python -m pip install --upgrade pip twine
60
+ python -m twine check dist/*
61
+
62
+ - name: Publish to PyPI
63
+ uses: pypa/gh-action-pypi-publish@release/v1
64
+ with:
65
+ verbose: true
@@ -0,0 +1,104 @@
1
+ name: Tests
2
+
3
+ "on":
4
+ pull_request:
5
+ branches: ["main", "master"]
6
+ push:
7
+ branches: ["main", "master"]
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-latest
13
+ permissions:
14
+ contents: read
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ python-version: ["3.11", "3.12", "3.13"]
19
+
20
+ steps:
21
+ - name: Checkout code
22
+ uses: actions/checkout@v4
23
+ with:
24
+ submodules: recursive
25
+
26
+ - name: Setup Miniconda
27
+ uses: conda-incubator/setup-miniconda@v3
28
+ with:
29
+ activate-environment: testenv
30
+ python-version: ${{ matrix.python-version }}
31
+ channels: conda-forge
32
+ auto-activate-base: false
33
+
34
+ - name: Install native and Python dependencies
35
+ shell: bash -l {0}
36
+ run: |
37
+ conda install -y \
38
+ cmake \
39
+ compilers \
40
+ eigen \
41
+ hdf5 \
42
+ make \
43
+ ninja \
44
+ numpy \
45
+ openmpi \
46
+ pip \
47
+ pytest \
48
+ pytest-cov \
49
+ scikit-build-core \
50
+ simpleitk
51
+ python -m pip install --upgrade pip
52
+ python -m pip install -e . --no-build-isolation
53
+
54
+ - name: Run tests
55
+ shell: bash -l {0}
56
+ run: pytest -q
57
+
58
+ coverage:
59
+ runs-on: ubuntu-latest
60
+ permissions:
61
+ contents: read
62
+ steps:
63
+ - name: Checkout code
64
+ uses: actions/checkout@v4
65
+ with:
66
+ submodules: recursive
67
+
68
+ - name: Setup Miniconda
69
+ uses: conda-incubator/setup-miniconda@v3
70
+ with:
71
+ activate-environment: covenv
72
+ python-version: "3.12"
73
+ channels: conda-forge
74
+ auto-activate-base: false
75
+
76
+ - name: Install native and Python dependencies
77
+ shell: bash -l {0}
78
+ run: |
79
+ conda install -y \
80
+ cmake \
81
+ compilers \
82
+ eigen \
83
+ hdf5 \
84
+ make \
85
+ ninja \
86
+ numpy \
87
+ openmpi \
88
+ pip \
89
+ pytest \
90
+ pytest-cov \
91
+ scikit-build-core \
92
+ simpleitk
93
+ python -m pip install --upgrade pip
94
+ python -m pip install -e . --no-build-isolation
95
+
96
+ - name: Run tests with coverage
97
+ shell: bash -l {0}
98
+ run: pytest -q --cov=parosol_py --cov-report=term-missing --cov-report=xml:coverage.xml
99
+
100
+ - name: Upload coverage artifact
101
+ uses: actions/upload-artifact@v4
102
+ with:
103
+ name: coverage-xml
104
+ path: coverage.xml
@@ -0,0 +1,12 @@
1
+ .worktrees/
2
+ docs/superpowers/
3
+ .DS_Store
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ __pycache__/
7
+ framework-main/
8
+ build/
9
+ dist/
10
+ dist-local-*/
11
+ wheelhouse-*/
12
+ *.egg-info/
@@ -0,0 +1,7 @@
1
+ cmake_minimum_required(VERSION 3.18)
2
+ project(parosol_py LANGUAGES CXX)
3
+
4
+ add_subdirectory(src/parosol_native)
5
+
6
+ install(TARGETS parosol
7
+ RUNTIME DESTINATION parosol_py/bin)
@@ -0,0 +1,153 @@
1
+ Metadata-Version: 2.2
2
+ Name: parosol-py
3
+ Version: 0.1.3
4
+ Summary: Python package and API wrapper for the ParOSol micro-FE solver
5
+ Keywords: finite-element-analysis,bone,hr-pqct,parosol
6
+ Author: Matthias Walle
7
+ Maintainer: Matthias Walle
8
+ License: GPL-2.0-or-later
9
+ Project-URL: Repository, https://github.com/wallematthias/parosol-py
10
+ Project-URL: Native-ParOSol-License, https://github.com/wallematthias/parosol-py/blob/main/src/parosol_native/LICENSE
11
+ Requires-Python: <3.14,>=3.11
12
+ Requires-Dist: numpy>=1.24
13
+ Requires-Dist: h5py>=3.10
14
+ Requires-Dist: SimpleITK>=2.3
15
+ Requires-Dist: aimio-py>=0.1.1
16
+ Requires-Dist: PyYAML>=6
17
+ Requires-Dist: matplotlib>=3.8
18
+ Provides-Extra: dev
19
+ Requires-Dist: pytest>=8; extra == "dev"
20
+ Requires-Dist: pytest-cov>=5; extra == "dev"
21
+ Requires-Dist: build>=1; extra == "dev"
22
+ Requires-Dist: cibuildwheel>=2.19; extra == "dev"
23
+ Requires-Dist: twine>=5; extra == "dev"
24
+ Provides-Extra: torch
25
+ Requires-Dist: torch>=2.3; extra == "torch"
26
+ Description-Content-Type: text/markdown
27
+
28
+ # parosol-py
29
+
30
+ `parosol-py` is the Python package and runtime wrapper for the ParOSol
31
+ micro-FE solver. It provides Python helpers for creating solver inputs, running
32
+ the bundled native executable, reading outputs, and mapping label or density
33
+ images to material stiffness.
34
+
35
+ The bundled native ParOSol solver was written by Cyril Flaig and is distributed
36
+ under the GNU General Public License, version 2 or later. The Python package is
37
+ therefore distributed as `GPL-2.0-or-later`.
38
+
39
+ ## Install
40
+
41
+ Prebuilt wheels include the native ParOSol executable:
42
+
43
+ ```bash
44
+ python -m pip install parosol-py
45
+ ```
46
+
47
+ For local development:
48
+
49
+ ```bash
50
+ python -m pip install -e .[dev]
51
+ ```
52
+
53
+ Source installs require CMake, an MPI C++ compiler/runtime, HDF5 C++ libraries,
54
+ and Eigen headers. Release wheels are built for Python 3.11, 3.12, and 3.13.
55
+ macOS wheels currently target macOS 15 or newer because the bundled native
56
+ solver depends on Homebrew HDF5/OpenMPI libraries built for that target.
57
+
58
+ ## Local Check
59
+
60
+ Before relying on GitHub Actions, run the local verification gate from an
61
+ environment that has the native build tools:
62
+
63
+ ```bash
64
+ python scripts/local_check.py
65
+ ```
66
+
67
+ Add `--smoke-install` to install the built wheel into a temporary virtual
68
+ environment and import it.
69
+
70
+ ## Python API
71
+
72
+ ```python
73
+ import numpy as np
74
+
75
+ from parosol_py import solve
76
+
77
+ material = np.ones((10, 10, 10), dtype=np.float32) * 1000.0
78
+
79
+ result = solve(
80
+ material=material,
81
+ spacing=(0.061, 0.061, 0.061),
82
+ material_unit="MPa",
83
+ test="axial",
84
+ test_axis="z",
85
+ strain=-0.01,
86
+ outputs=("sed",),
87
+ export_dir="outputs/example",
88
+ )
89
+
90
+ print(result.summary)
91
+ print(result.exported)
92
+ ```
93
+
94
+ Use `dry_run=True` to write the ParOSol HDF5 input and command without launching
95
+ the solver:
96
+
97
+ ```python
98
+ result = solve(
99
+ material=material,
100
+ spacing=(0.061, 0.061, 0.061),
101
+ material_unit="MPa",
102
+ test="axial",
103
+ test_axis="z",
104
+ strain=-0.01,
105
+ dry_run=True,
106
+ export_dir="outputs/dry_run",
107
+ )
108
+ ```
109
+
110
+ ## Material Mapping
111
+
112
+ Label images can be mapped through an explicit material table:
113
+
114
+ ```python
115
+ import numpy as np
116
+
117
+ from parosol_py import LinearIsotropicMaterials, labels_to_material_map
118
+
119
+ labels = np.array([[[100, 127]]], dtype=np.uint16)
120
+ table = LinearIsotropicMaterials(
121
+ youngs_modulus_mpa={100: 8748.0, 127: 8748.0},
122
+ poisson_ratio={100: 0.3, 127: 0.3},
123
+ )
124
+
125
+ mapped = labels_to_material_map(labels, table)
126
+ ```
127
+
128
+ Continuous density images can be converted with one of the supported equations:
129
+
130
+ ```python
131
+ from parosol_py import density_to_material_map
132
+
133
+ mapped = density_to_material_map(
134
+ density_image,
135
+ equation="power",
136
+ coefficient=10000.0,
137
+ exponent=1.7,
138
+ reference_density=1000.0,
139
+ poisson_ratio=0.3,
140
+ )
141
+ ```
142
+
143
+ The Mulder grayscale BMD law is available as `mulder2007`:
144
+
145
+ ```python
146
+ mapped = density_to_material_map(
147
+ density_image,
148
+ equation="mulder2007",
149
+ active_mask=outer_contour,
150
+ floor_e_mpa=2.0,
151
+ poisson_ratio=0.3,
152
+ )
153
+ ```
@@ -0,0 +1,126 @@
1
+ # parosol-py
2
+
3
+ `parosol-py` is the Python package and runtime wrapper for the ParOSol
4
+ micro-FE solver. It provides Python helpers for creating solver inputs, running
5
+ the bundled native executable, reading outputs, and mapping label or density
6
+ images to material stiffness.
7
+
8
+ The bundled native ParOSol solver was written by Cyril Flaig and is distributed
9
+ under the GNU General Public License, version 2 or later. The Python package is
10
+ therefore distributed as `GPL-2.0-or-later`.
11
+
12
+ ## Install
13
+
14
+ Prebuilt wheels include the native ParOSol executable:
15
+
16
+ ```bash
17
+ python -m pip install parosol-py
18
+ ```
19
+
20
+ For local development:
21
+
22
+ ```bash
23
+ python -m pip install -e .[dev]
24
+ ```
25
+
26
+ Source installs require CMake, an MPI C++ compiler/runtime, HDF5 C++ libraries,
27
+ and Eigen headers. Release wheels are built for Python 3.11, 3.12, and 3.13.
28
+ macOS wheels currently target macOS 15 or newer because the bundled native
29
+ solver depends on Homebrew HDF5/OpenMPI libraries built for that target.
30
+
31
+ ## Local Check
32
+
33
+ Before relying on GitHub Actions, run the local verification gate from an
34
+ environment that has the native build tools:
35
+
36
+ ```bash
37
+ python scripts/local_check.py
38
+ ```
39
+
40
+ Add `--smoke-install` to install the built wheel into a temporary virtual
41
+ environment and import it.
42
+
43
+ ## Python API
44
+
45
+ ```python
46
+ import numpy as np
47
+
48
+ from parosol_py import solve
49
+
50
+ material = np.ones((10, 10, 10), dtype=np.float32) * 1000.0
51
+
52
+ result = solve(
53
+ material=material,
54
+ spacing=(0.061, 0.061, 0.061),
55
+ material_unit="MPa",
56
+ test="axial",
57
+ test_axis="z",
58
+ strain=-0.01,
59
+ outputs=("sed",),
60
+ export_dir="outputs/example",
61
+ )
62
+
63
+ print(result.summary)
64
+ print(result.exported)
65
+ ```
66
+
67
+ Use `dry_run=True` to write the ParOSol HDF5 input and command without launching
68
+ the solver:
69
+
70
+ ```python
71
+ result = solve(
72
+ material=material,
73
+ spacing=(0.061, 0.061, 0.061),
74
+ material_unit="MPa",
75
+ test="axial",
76
+ test_axis="z",
77
+ strain=-0.01,
78
+ dry_run=True,
79
+ export_dir="outputs/dry_run",
80
+ )
81
+ ```
82
+
83
+ ## Material Mapping
84
+
85
+ Label images can be mapped through an explicit material table:
86
+
87
+ ```python
88
+ import numpy as np
89
+
90
+ from parosol_py import LinearIsotropicMaterials, labels_to_material_map
91
+
92
+ labels = np.array([[[100, 127]]], dtype=np.uint16)
93
+ table = LinearIsotropicMaterials(
94
+ youngs_modulus_mpa={100: 8748.0, 127: 8748.0},
95
+ poisson_ratio={100: 0.3, 127: 0.3},
96
+ )
97
+
98
+ mapped = labels_to_material_map(labels, table)
99
+ ```
100
+
101
+ Continuous density images can be converted with one of the supported equations:
102
+
103
+ ```python
104
+ from parosol_py import density_to_material_map
105
+
106
+ mapped = density_to_material_map(
107
+ density_image,
108
+ equation="power",
109
+ coefficient=10000.0,
110
+ exponent=1.7,
111
+ reference_density=1000.0,
112
+ poisson_ratio=0.3,
113
+ )
114
+ ```
115
+
116
+ The Mulder grayscale BMD law is available as `mulder2007`:
117
+
118
+ ```python
119
+ mapped = density_to_material_map(
120
+ density_image,
121
+ equation="mulder2007",
122
+ active_mask=outer_contour,
123
+ floor_e_mpa=2.0,
124
+ poisson_ratio=0.3,
125
+ )
126
+ ```
@@ -0,0 +1,71 @@
1
+ [build-system]
2
+ requires = ["scikit-build-core>=0.10"]
3
+ build-backend = "scikit_build_core.build"
4
+
5
+ [project]
6
+ name = "parosol-py"
7
+ version = "0.1.3"
8
+ description = "Python package and API wrapper for the ParOSol micro-FE solver"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11,<3.14"
11
+ license = { text = "GPL-2.0-or-later" }
12
+ authors = [{ name = "Matthias Walle" }]
13
+ maintainers = [{ name = "Matthias Walle" }]
14
+ keywords = ["finite-element-analysis", "bone", "hr-pqct", "parosol"]
15
+ dependencies = [
16
+ "numpy>=1.24",
17
+ "h5py>=3.10",
18
+ "SimpleITK>=2.3",
19
+ "aimio-py>=0.1.1",
20
+ "PyYAML>=6",
21
+ "matplotlib>=3.8",
22
+ ]
23
+
24
+ [project.scripts]
25
+ parosol = "parosol_py.cli:main"
26
+
27
+ [project.urls]
28
+ Repository = "https://github.com/wallematthias/parosol-py"
29
+ Native-ParOSol-License = "https://github.com/wallematthias/parosol-py/blob/main/src/parosol_native/LICENSE"
30
+
31
+ [project.optional-dependencies]
32
+ dev = [
33
+ "pytest>=8",
34
+ "pytest-cov>=5",
35
+ "build>=1",
36
+ "cibuildwheel>=2.19",
37
+ "twine>=5",
38
+ ]
39
+ torch = [
40
+ "torch>=2.3",
41
+ ]
42
+
43
+ [tool.scikit-build]
44
+ cmake.version = ">=3.18"
45
+ wheel.packages = ["src/parosol_py", "src/parosol_torch"]
46
+
47
+ [tool.cibuildwheel]
48
+ build = "cp311-* cp312-* cp313-*"
49
+ skip = "*-musllinux_* *-manylinux_i686 *-win32"
50
+ test-command = "python -c \"from parosol_py.runner import packaged_executable; p=packaged_executable(); print(p); assert p.exists()\""
51
+ build-verbosity = 1
52
+
53
+ [tool.cibuildwheel.linux]
54
+ archs = ["x86_64"]
55
+ before-all = "if command -v yum >/dev/null 2>&1; then yum install -y eigen3-devel hdf5-devel openmpi-devel; elif command -v dnf >/dev/null 2>&1; then dnf install -y eigen3-devel hdf5-devel openmpi-devel; elif command -v apt-get >/dev/null 2>&1; then apt-get update && apt-get install -y libeigen3-dev libhdf5-dev libopenmpi-dev openmpi-bin; else echo 'No supported package manager found for native dependencies' && exit 1; fi"
56
+ environment = { PATH="/usr/lib64/openmpi/bin:/usr/lib/openmpi/bin:$PATH", LD_LIBRARY_PATH="/usr/lib64/openmpi/lib:/usr/lib/openmpi/lib:$LD_LIBRARY_PATH" }
57
+
58
+ [tool.cibuildwheel.macos]
59
+ before-all = "brew install eigen hdf5 open-mpi"
60
+ environment = { CMAKE_PREFIX_PATH="$(brew --prefix eigen):$(brew --prefix hdf5):$(brew --prefix open-mpi)", MACOSX_DEPLOYMENT_TARGET="15.0" }
61
+ repair-wheel-command = "python -m pip install delocate && delocate-wheel --require-archs {delocate_archs} -w {dest_dir} {wheel}"
62
+
63
+ [tool.cibuildwheel.windows]
64
+ archs = ["AMD64"]
65
+ before-all = "powershell -NoProfile -ExecutionPolicy Bypass -Command \"$ErrorActionPreference = 'Stop'; winget install --id Microsoft.msmpi --exact --silent --accept-package-agreements --accept-source-agreements; if (-not (Test-Path 'C:\\Program Files\\Microsoft MPI\\Bin\\mpiexec.exe')) { throw 'MS-MPI redistributable install did not produce mpiexec.exe' }; if (-not (Test-Path 'C:\\vcpkg')) { git clone --depth 1 https://github.com/microsoft/vcpkg C:\\vcpkg }; & C:\\vcpkg\\bootstrap-vcpkg.bat; & C:\\vcpkg\\vcpkg.exe install eigen3:x64-windows hdf5[cpp]:x64-windows msmpi:x64-windows --disable-metrics\""
66
+ environment = { CMAKE_TOOLCHAIN_FILE="C:/vcpkg/scripts/buildsystems/vcpkg.cmake", VCPKG_TARGET_TRIPLET="x64-windows" }
67
+ repair-wheel-command = "python -m pip install delvewheel && delvewheel repair -w {dest_dir} {wheel}"
68
+
69
+ [tool.pytest.ini_options]
70
+ testpaths = ["tests"]
71
+ addopts = "-ra"