freedyn2 0.1.0rc1__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 (290) hide show
  1. freedyn2-0.1.0rc1/.gitattributes +5 -0
  2. freedyn2-0.1.0rc1/.github/workflows/ci.yml +127 -0
  3. freedyn2-0.1.0rc1/.github/workflows/docs.yml +58 -0
  4. freedyn2-0.1.0rc1/.github/workflows/wheels.yml +340 -0
  5. freedyn2-0.1.0rc1/.gitignore +15 -0
  6. freedyn2-0.1.0rc1/CHANGELOG.md +36 -0
  7. freedyn2-0.1.0rc1/CITATION.cff +78 -0
  8. freedyn2-0.1.0rc1/CLAUDE.md +9 -0
  9. freedyn2-0.1.0rc1/CMakeLists.txt +198 -0
  10. freedyn2-0.1.0rc1/LICENSE +202 -0
  11. freedyn2-0.1.0rc1/NOTICE +24 -0
  12. freedyn2-0.1.0rc1/PKG-INFO +512 -0
  13. freedyn2-0.1.0rc1/README.md +483 -0
  14. freedyn2-0.1.0rc1/brand/README.md +74 -0
  15. freedyn2-0.1.0rc1/brand/logo/app-icon.svg +3 -0
  16. freedyn2-0.1.0rc1/brand/logo/avatar.svg +3 -0
  17. freedyn2-0.1.0rc1/brand/logo/favicon.svg +3 -0
  18. freedyn2-0.1.0rc1/brand/logo/lockup-claim-dark.svg +39 -0
  19. freedyn2-0.1.0rc1/brand/logo/lockup-claim-light.svg +39 -0
  20. freedyn2-0.1.0rc1/brand/logo/lockup-dark-transparent.svg +13 -0
  21. freedyn2-0.1.0rc1/brand/logo/lockup-dark.svg +13 -0
  22. freedyn2-0.1.0rc1/brand/logo/lockup-light-transparent.svg +13 -0
  23. freedyn2-0.1.0rc1/brand/logo/lockup-light.svg +13 -0
  24. freedyn2-0.1.0rc1/brand/logo/lockup-small-dark.svg +12 -0
  25. freedyn2-0.1.0rc1/brand/logo/lockup-small-light.svg +12 -0
  26. freedyn2-0.1.0rc1/brand/logo/mark-dark.svg +3 -0
  27. freedyn2-0.1.0rc1/brand/logo/mark-light.svg +3 -0
  28. freedyn2-0.1.0rc1/brand/make_logos.py +180 -0
  29. freedyn2-0.1.0rc1/brand/tokens.css +54 -0
  30. freedyn2-0.1.0rc1/brand/tokens.json +59 -0
  31. freedyn2-0.1.0rc1/cmake/copy_dlls.cmake +5 -0
  32. freedyn2-0.1.0rc1/docs/architecture.md +456 -0
  33. freedyn2-0.1.0rc1/docs/assistants.md +96 -0
  34. freedyn2-0.1.0rc1/docs/cli.md +165 -0
  35. freedyn2-0.1.0rc1/docs/download.md +47 -0
  36. freedyn2-0.1.0rc1/docs/examples.md +81 -0
  37. freedyn2-0.1.0rc1/docs/extensions.md +217 -0
  38. freedyn2-0.1.0rc1/docs/findings.md +66 -0
  39. freedyn2-0.1.0rc1/docs/from-adams.md +75 -0
  40. freedyn2-0.1.0rc1/docs/from-freedyn.md +161 -0
  41. freedyn2-0.1.0rc1/docs/getting-started.md +183 -0
  42. freedyn2-0.1.0rc1/docs/how-it-works.md +337 -0
  43. freedyn2-0.1.0rc1/docs/img/app-start.png +0 -0
  44. freedyn2-0.1.0rc1/docs/img/car-crg.png +0 -0
  45. freedyn2-0.1.0rc1/docs/img/fan.png +0 -0
  46. freedyn2-0.1.0rc1/docs/img/pendulum.png +0 -0
  47. freedyn2-0.1.0rc1/docs/img/root-locus.png +0 -0
  48. freedyn2-0.1.0rc1/docs/img/runs-delta.png +0 -0
  49. freedyn2-0.1.0rc1/docs/img/runs-reference.png +0 -0
  50. freedyn2-0.1.0rc1/docs/img/tune-pending.png +0 -0
  51. freedyn2-0.1.0rc1/docs/img/viewer.png +0 -0
  52. freedyn2-0.1.0rc1/docs/index.md +57 -0
  53. freedyn2-0.1.0rc1/docs/javascripts/mathjax.js +5 -0
  54. freedyn2-0.1.0rc1/docs/privacy.md +29 -0
  55. freedyn2-0.1.0rc1/docs/python-api.md +118 -0
  56. freedyn2-0.1.0rc1/docs/reference/bodies.md +52 -0
  57. freedyn2-0.1.0rc1/docs/reference/checks.md +44 -0
  58. freedyn2-0.1.0rc1/docs/reference/forces.md +124 -0
  59. freedyn2-0.1.0rc1/docs/reference/hardpoints.md +98 -0
  60. freedyn2-0.1.0rc1/docs/reference/joints.md +43 -0
  61. freedyn2-0.1.0rc1/docs/reference/measures.md +105 -0
  62. freedyn2-0.1.0rc1/docs/reference/model-file.md +120 -0
  63. freedyn2-0.1.0rc1/docs/reference/results.md +56 -0
  64. freedyn2-0.1.0rc1/docs/reference/sensors.md +62 -0
  65. freedyn2-0.1.0rc1/docs/reference/solver.md +53 -0
  66. freedyn2-0.1.0rc1/docs/reference/tires-roads.md +67 -0
  67. freedyn2-0.1.0rc1/docs/releasing.md +210 -0
  68. freedyn2-0.1.0rc1/docs/stylesheets/extra.css +2 -0
  69. freedyn2-0.1.0rc1/docs/theory.md +721 -0
  70. freedyn2-0.1.0rc1/docs/tutorial-crg.md +164 -0
  71. freedyn2-0.1.0rc1/docs/tutorial.md +163 -0
  72. freedyn2-0.1.0rc1/docs/viewer.md +177 -0
  73. freedyn2-0.1.0rc1/examples/bushing_mount.yaml +14 -0
  74. freedyn2-0.1.0rc1/examples/car_on_crg.yaml +98 -0
  75. freedyn2-0.1.0rc1/examples/compare/data/stiff.txt +10 -0
  76. freedyn2-0.1.0rc1/examples/compare/double_pendulum.fds +96 -0
  77. freedyn2-0.1.0rc1/examples/compare/driven_base.fds +161 -0
  78. freedyn2-0.1.0rc1/examples/compare/driven_rotor.fds +140 -0
  79. freedyn2-0.1.0rc1/examples/compare/dzhanibekov.fds +46 -0
  80. freedyn2-0.1.0rc1/examples/compare/fast_rotor.fds +50 -0
  81. freedyn2-0.1.0rc1/examples/compare/fast_rotor_modified.fds +50 -0
  82. freedyn2-0.1.0rc1/examples/compare/forced_oscillator.fds +124 -0
  83. freedyn2-0.1.0rc1/examples/compare/free_body.fds +50 -0
  84. freedyn2-0.1.0rc1/examples/compare/pendulum.fds +73 -0
  85. freedyn2-0.1.0rc1/examples/compare/rotated_gui_defaults.fds +46 -0
  86. freedyn2-0.1.0rc1/examples/compare/spline_spring.fds +130 -0
  87. freedyn2-0.1.0rc1/examples/compare/spring_chain.fds +221 -0
  88. freedyn2-0.1.0rc1/examples/compare/step_control.fds +46 -0
  89. freedyn2-0.1.0rc1/examples/compare/torsion_disks.fds +183 -0
  90. freedyn2-0.1.0rc1/examples/constant_loads.yaml +11 -0
  91. freedyn2-0.1.0rc1/examples/data/make_test_track.py +58 -0
  92. freedyn2-0.1.0rc1/examples/data/spline_slider_law.txt +9 -0
  93. freedyn2-0.1.0rc1/examples/data/test_track.crg +0 -0
  94. freedyn2-0.1.0rc1/examples/double_pendulum.yaml +35 -0
  95. freedyn2-0.1.0rc1/examples/double_wishbone.yaml +93 -0
  96. freedyn2-0.1.0rc1/examples/driven_rotor.yaml +20 -0
  97. freedyn2-0.1.0rc1/examples/dzhanibekov.yaml +10 -0
  98. freedyn2-0.1.0rc1/examples/extension/freedyn2_drag/__init__.py +68 -0
  99. freedyn2-0.1.0rc1/examples/extension/pyproject.toml +17 -0
  100. freedyn2-0.1.0rc1/examples/forced_oscillator.yaml +19 -0
  101. freedyn2-0.1.0rc1/examples/free_body.yaml +12 -0
  102. freedyn2-0.1.0rc1/examples/input_oscillator.yaml +30 -0
  103. freedyn2-0.1.0rc1/examples/oscillator.yaml +16 -0
  104. freedyn2-0.1.0rc1/examples/pendulum.yaml +17 -0
  105. freedyn2-0.1.0rc1/examples/quarter_car.yaml +69 -0
  106. freedyn2-0.1.0rc1/examples/scaling/car_1.fds +928 -0
  107. freedyn2-0.1.0rc1/examples/scaling/make_car.py +218 -0
  108. freedyn2-0.1.0rc1/examples/scaling/scaling.py +64 -0
  109. freedyn2-0.1.0rc1/examples/spline_slider.yaml +15 -0
  110. freedyn2-0.1.0rc1/examples/spring_pendulum.yaml +14 -0
  111. freedyn2-0.1.0rc1/examples/torsion_pendulum.yaml +11 -0
  112. freedyn2-0.1.0rc1/examples/two_bodies.yaml +11 -0
  113. freedyn2-0.1.0rc1/examples/winding_spring.yaml +15 -0
  114. freedyn2-0.1.0rc1/generator/fdgen/__init__.py +23 -0
  115. freedyn2-0.1.0rc1/generator/fdgen/__main__.py +39 -0
  116. freedyn2-0.1.0rc1/generator/fdgen/app/__init__.py +196 -0
  117. freedyn2-0.1.0rc1/generator/fdgen/app/freedyn2.ico +0 -0
  118. freedyn2-0.1.0rc1/generator/fdgen/app/freedyn2.png +0 -0
  119. freedyn2-0.1.0rc1/generator/fdgen/app/freedyn2.svg +18 -0
  120. freedyn2-0.1.0rc1/generator/fdgen/app/instance.py +72 -0
  121. freedyn2-0.1.0rc1/generator/fdgen/app/native.py +111 -0
  122. freedyn2-0.1.0rc1/generator/fdgen/app/recent.py +57 -0
  123. freedyn2-0.1.0rc1/generator/fdgen/app/server.py +388 -0
  124. freedyn2-0.1.0rc1/generator/fdgen/app/web/shell.js +51 -0
  125. freedyn2-0.1.0rc1/generator/fdgen/app/web/start.html +137 -0
  126. freedyn2-0.1.0rc1/generator/fdgen/app/web/start.js +165 -0
  127. freedyn2-0.1.0rc1/generator/fdgen/checks.py +312 -0
  128. freedyn2-0.1.0rc1/generator/fdgen/cli.py +283 -0
  129. freedyn2-0.1.0rc1/generator/fdgen/codegen.py +133 -0
  130. freedyn2-0.1.0rc1/generator/fdgen/convert.py +475 -0
  131. freedyn2-0.1.0rc1/generator/fdgen/crg.py +82 -0
  132. freedyn2-0.1.0rc1/generator/fdgen/custom_element.py +152 -0
  133. freedyn2-0.1.0rc1/generator/fdgen/doctor.py +119 -0
  134. freedyn2-0.1.0rc1/generator/fdgen/drivers.py +49 -0
  135. freedyn2-0.1.0rc1/generator/fdgen/errors.py +17 -0
  136. freedyn2-0.1.0rc1/generator/fdgen/expression_forces.py +68 -0
  137. freedyn2-0.1.0rc1/generator/fdgen/expressions.py +105 -0
  138. freedyn2-0.1.0rc1/generator/fdgen/extensions.py +109 -0
  139. freedyn2-0.1.0rc1/generator/fdgen/fds/__init__.py +150 -0
  140. freedyn2-0.1.0rc1/generator/fdgen/fds/blocks.py +55 -0
  141. freedyn2-0.1.0rc1/generator/fdgen/fds/bodies.py +77 -0
  142. freedyn2-0.1.0rc1/generator/fdgen/fds/loads.py +231 -0
  143. freedyn2-0.1.0rc1/generator/fdgen/fds/solver.py +54 -0
  144. freedyn2-0.1.0rc1/generator/fdgen/forces.py +274 -0
  145. freedyn2-0.1.0rc1/generator/fdgen/formulas.py +98 -0
  146. freedyn2-0.1.0rc1/generator/fdgen/geometry.py +41 -0
  147. freedyn2-0.1.0rc1/generator/fdgen/hardpoints.py +222 -0
  148. freedyn2-0.1.0rc1/generator/fdgen/joints.py +105 -0
  149. freedyn2-0.1.0rc1/generator/fdgen/kinematics.py +176 -0
  150. freedyn2-0.1.0rc1/generator/fdgen/lagrange.py +280 -0
  151. freedyn2-0.1.0rc1/generator/fdgen/linearize.py +297 -0
  152. freedyn2-0.1.0rc1/generator/fdgen/mcp_server.py +502 -0
  153. freedyn2-0.1.0rc1/generator/fdgen/mcp_setup.py +208 -0
  154. freedyn2-0.1.0rc1/generator/fdgen/measures.py +167 -0
  155. freedyn2-0.1.0rc1/generator/fdgen/model.py +406 -0
  156. freedyn2-0.1.0rc1/generator/fdgen/msvc.py +125 -0
  157. freedyn2-0.1.0rc1/generator/fdgen/outputs.py +32 -0
  158. freedyn2-0.1.0rc1/generator/fdgen/plugin.py +276 -0
  159. freedyn2-0.1.0rc1/generator/fdgen/resources.py +17 -0
  160. freedyn2-0.1.0rc1/generator/fdgen/rigid_body.py +219 -0
  161. freedyn2-0.1.0rc1/generator/fdgen/shapes.py +104 -0
  162. freedyn2-0.1.0rc1/generator/fdgen/splines.py +141 -0
  163. freedyn2-0.1.0rc1/generator/fdgen/sweep.py +105 -0
  164. freedyn2-0.1.0rc1/generator/fdgen/tire.py +194 -0
  165. freedyn2-0.1.0rc1/generator/fdgen/update.py +180 -0
  166. freedyn2-0.1.0rc1/generator/fdgen/userdirs.py +81 -0
  167. freedyn2-0.1.0rc1/generator/fdgen/view/__init__.py +1 -0
  168. freedyn2-0.1.0rc1/generator/fdgen/view/notes.py +118 -0
  169. freedyn2-0.1.0rc1/generator/fdgen/view/scene.py +268 -0
  170. freedyn2-0.1.0rc1/generator/fdgen/view/server.py +608 -0
  171. freedyn2-0.1.0rc1/generator/fdgen/view/web/channels.js +144 -0
  172. freedyn2-0.1.0rc1/generator/fdgen/view/web/index.html +312 -0
  173. freedyn2-0.1.0rc1/generator/fdgen/view/web/panels.js +510 -0
  174. freedyn2-0.1.0rc1/generator/fdgen/view/web/plot.js +809 -0
  175. freedyn2-0.1.0rc1/generator/fdgen/view/web/runs.js +79 -0
  176. freedyn2-0.1.0rc1/generator/fdgen/view/web/vendor/LICENSE-three.js +21 -0
  177. freedyn2-0.1.0rc1/generator/fdgen/view/web/vendor/OBJLoader.js +907 -0
  178. freedyn2-0.1.0rc1/generator/fdgen/view/web/vendor/OrbitControls.js +1523 -0
  179. freedyn2-0.1.0rc1/generator/fdgen/view/web/vendor/README.md +6 -0
  180. freedyn2-0.1.0rc1/generator/fdgen/view/web/vendor/STLLoader.js +411 -0
  181. freedyn2-0.1.0rc1/generator/fdgen/view/web/vendor/three.module.min.js +6 -0
  182. freedyn2-0.1.0rc1/generator/fdgen/view/web/viewer.js +1076 -0
  183. freedyn2-0.1.0rc1/generator/freedyn2/__init__.py +21 -0
  184. freedyn2-0.1.0rc1/generator/freedyn2/api.py +407 -0
  185. freedyn2-0.1.0rc1/installer/windows/THIRD-PARTY-NOTICES.txt +63 -0
  186. freedyn2-0.1.0rc1/installer/windows/build.py +460 -0
  187. freedyn2-0.1.0rc1/installer/windows/freedyn2-prompt.cmd +15 -0
  188. freedyn2-0.1.0rc1/installer/windows/freedyn2.iss +274 -0
  189. freedyn2-0.1.0rc1/installer/windows/signpath/installer.xml +14 -0
  190. freedyn2-0.1.0rc1/installer/windows/signpath/programs.xml +23 -0
  191. freedyn2-0.1.0rc1/installer/winget/FreeDynOrg.FreeDyn2.installer.yaml +36 -0
  192. freedyn2-0.1.0rc1/installer/winget/FreeDynOrg.FreeDyn2.locale.en-US.yaml +33 -0
  193. freedyn2-0.1.0rc1/installer/winget/FreeDynOrg.FreeDyn2.yaml +7 -0
  194. freedyn2-0.1.0rc1/installer/winget/render.py +42 -0
  195. freedyn2-0.1.0rc1/legacy/README.md +27 -0
  196. freedyn2-0.1.0rc1/legacy/benchmark.py +231 -0
  197. freedyn2-0.1.0rc1/legacy/build_legacy.py +233 -0
  198. freedyn2-0.1.0rc1/legacy/compare.py +258 -0
  199. freedyn2-0.1.0rc1/legacy/compat/Windows.h +36 -0
  200. freedyn2-0.1.0rc1/legacy/compat/concurrent_queue.h +26 -0
  201. freedyn2-0.1.0rc1/legacy/compat/io.h +2 -0
  202. freedyn2-0.1.0rc1/legacy/compat/legacy_compat.h +44 -0
  203. freedyn2-0.1.0rc1/legacy/compat/tbb/concurrent_vector.h +21 -0
  204. freedyn2-0.1.0rc1/legacy/compat/windows.h +36 -0
  205. freedyn2-0.1.0rc1/legacy/references/__init__.py +38 -0
  206. freedyn2-0.1.0rc1/legacy/references/common.py +42 -0
  207. freedyn2-0.1.0rc1/legacy/references/free_bodies.py +143 -0
  208. freedyn2-0.1.0rc1/legacy/references/free_body.py +55 -0
  209. freedyn2-0.1.0rc1/legacy/references/hinge_chain.py +93 -0
  210. freedyn2-0.1.0rc1/legacy/references/linear.py +55 -0
  211. freedyn2-0.1.0rc1/legacy/references/prescribed.py +126 -0
  212. freedyn2-0.1.0rc1/legacy/results.py +93 -0
  213. freedyn2-0.1.0rc1/mkdocs.yml +83 -0
  214. freedyn2-0.1.0rc1/pyproject.toml +69 -0
  215. freedyn2-0.1.0rc1/requirements-dev.txt +9 -0
  216. freedyn2-0.1.0rc1/requirements-docs.txt +2 -0
  217. freedyn2-0.1.0rc1/runtime/app/main.cpp +312 -0
  218. freedyn2-0.1.0rc1/runtime/app/road.cpp +84 -0
  219. freedyn2-0.1.0rc1/runtime/include/freedyn2/crg.hpp +56 -0
  220. freedyn2-0.1.0rc1/runtime/include/freedyn2/generated_function.hpp +45 -0
  221. freedyn2-0.1.0rc1/runtime/include/freedyn2/hht.hpp +108 -0
  222. freedyn2-0.1.0rc1/runtime/include/freedyn2/linear_solver.hpp +33 -0
  223. freedyn2-0.1.0rc1/runtime/include/freedyn2/model.hpp +84 -0
  224. freedyn2-0.1.0rc1/runtime/include/freedyn2/plugin.hpp +17 -0
  225. freedyn2-0.1.0rc1/runtime/include/freedyn2/scatter.hpp +49 -0
  226. freedyn2-0.1.0rc1/runtime/include/freedyn2/system.hpp +141 -0
  227. freedyn2-0.1.0rc1/runtime/src/crg.cpp +112 -0
  228. freedyn2-0.1.0rc1/runtime/src/generated_function.cpp +50 -0
  229. freedyn2-0.1.0rc1/runtime/src/hht.cpp +364 -0
  230. freedyn2-0.1.0rc1/runtime/src/linear_solver.cpp +132 -0
  231. freedyn2-0.1.0rc1/runtime/src/model.cpp +170 -0
  232. freedyn2-0.1.0rc1/runtime/src/plugin.cpp +70 -0
  233. freedyn2-0.1.0rc1/runtime/src/scatter.cpp +62 -0
  234. freedyn2-0.1.0rc1/runtime/src/system.cpp +355 -0
  235. freedyn2-0.1.0rc1/runtime/third_party/opencrg/LICENSE +204 -0
  236. freedyn2-0.1.0rc1/runtime/third_party/opencrg/NOTICE +57 -0
  237. freedyn2-0.1.0rc1/runtime/third_party/opencrg/README.md +6 -0
  238. freedyn2-0.1.0rc1/runtime/third_party/opencrg/inc/crgBaseLib.h +611 -0
  239. freedyn2-0.1.0rc1/runtime/third_party/opencrg/inc/crgBaseLibPrivate.h +731 -0
  240. freedyn2-0.1.0rc1/runtime/third_party/opencrg/src/crgContactPoint.c +636 -0
  241. freedyn2-0.1.0rc1/runtime/third_party/opencrg/src/crgEvalpk.c +160 -0
  242. freedyn2-0.1.0rc1/runtime/third_party/opencrg/src/crgEvaluv2xy.c +203 -0
  243. freedyn2-0.1.0rc1/runtime/third_party/opencrg/src/crgEvalxy2uv.c +473 -0
  244. freedyn2-0.1.0rc1/runtime/third_party/opencrg/src/crgEvalz.c +679 -0
  245. freedyn2-0.1.0rc1/runtime/third_party/opencrg/src/crgLoader.c +3410 -0
  246. freedyn2-0.1.0rc1/runtime/third_party/opencrg/src/crgMgr.c +1014 -0
  247. freedyn2-0.1.0rc1/runtime/third_party/opencrg/src/crgMsg.c +94 -0
  248. freedyn2-0.1.0rc1/runtime/third_party/opencrg/src/crgOptionMgmt.c +575 -0
  249. freedyn2-0.1.0rc1/runtime/third_party/opencrg/src/crgPortability.c +169 -0
  250. freedyn2-0.1.0rc1/runtime/third_party/opencrg/src/crgStatistics.c +354 -0
  251. freedyn2-0.1.0rc1/schema/model.schema.json +358 -0
  252. freedyn2-0.1.0rc1/tests/cpp/CMakeLists.txt +22 -0
  253. freedyn2-0.1.0rc1/tests/cpp/force_tests.cpp +260 -0
  254. freedyn2-0.1.0rc1/tests/cpp/joint_tests.cpp +170 -0
  255. freedyn2-0.1.0rc1/tests/cpp/main.cpp +28 -0
  256. freedyn2-0.1.0rc1/tests/cpp/rigid_body_tests.cpp +448 -0
  257. freedyn2-0.1.0rc1/tests/cpp/test_support.cpp +122 -0
  258. freedyn2-0.1.0rc1/tests/cpp/test_support.hpp +60 -0
  259. freedyn2-0.1.0rc1/tests/python/conftest.py +75 -0
  260. freedyn2-0.1.0rc1/tests/python/test_api.py +132 -0
  261. freedyn2-0.1.0rc1/tests/python/test_app.py +447 -0
  262. freedyn2-0.1.0rc1/tests/python/test_checks.py +146 -0
  263. freedyn2-0.1.0rc1/tests/python/test_cli.py +205 -0
  264. freedyn2-0.1.0rc1/tests/python/test_codegen.py +76 -0
  265. freedyn2-0.1.0rc1/tests/python/test_convert.py +146 -0
  266. freedyn2-0.1.0rc1/tests/python/test_crg.py +193 -0
  267. freedyn2-0.1.0rc1/tests/python/test_custom_elements.py +413 -0
  268. freedyn2-0.1.0rc1/tests/python/test_docs.py +47 -0
  269. freedyn2-0.1.0rc1/tests/python/test_extension_example.py +108 -0
  270. freedyn2-0.1.0rc1/tests/python/test_fds.py +137 -0
  271. freedyn2-0.1.0rc1/tests/python/test_forces.py +179 -0
  272. freedyn2-0.1.0rc1/tests/python/test_formulas.py +79 -0
  273. freedyn2-0.1.0rc1/tests/python/test_hardpoints.py +160 -0
  274. freedyn2-0.1.0rc1/tests/python/test_joints.py +130 -0
  275. freedyn2-0.1.0rc1/tests/python/test_legacy_compare.py +55 -0
  276. freedyn2-0.1.0rc1/tests/python/test_legacy_physics.py +59 -0
  277. freedyn2-0.1.0rc1/tests/python/test_lie_group.py +123 -0
  278. freedyn2-0.1.0rc1/tests/python/test_linearize.py +54 -0
  279. freedyn2-0.1.0rc1/tests/python/test_mcp.py +148 -0
  280. freedyn2-0.1.0rc1/tests/python/test_rigid_body.py +121 -0
  281. freedyn2-0.1.0rc1/tests/python/test_schema.py +64 -0
  282. freedyn2-0.1.0rc1/tests/python/test_sensors.py +114 -0
  283. freedyn2-0.1.0rc1/tests/python/test_setup_tools.py +360 -0
  284. freedyn2-0.1.0rc1/tests/python/test_sweep.py +62 -0
  285. freedyn2-0.1.0rc1/tests/python/test_tire.py +72 -0
  286. freedyn2-0.1.0rc1/tests/python/test_view.py +505 -0
  287. freedyn2-0.1.0rc1/tools/build_deps.py +73 -0
  288. freedyn2-0.1.0rc1/tools/docs_examples.py +42 -0
  289. freedyn2-0.1.0rc1/tools/docs_hooks.py +78 -0
  290. freedyn2-0.1.0rc1/tools/make_app_icon.py +105 -0
@@ -0,0 +1,5 @@
1
+ # Windows batch files need CRLF line endings; the installer's texts are shown on Windows
2
+ *.cmd text eol=crlf
3
+ *.bat text eol=crlf
4
+ installer/windows/*.txt text eol=crlf
5
+ installer/windows/*.iss text eol=crlf
@@ -0,0 +1,127 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main] # work branches run once, through their pull request
6
+ pull_request:
7
+
8
+ # a new push to a pull request cancels its runs still in progress
9
+ concurrency:
10
+ group: ci-${{ github.ref }}
11
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
12
+
13
+ jobs:
14
+ build-and-test:
15
+ runs-on: ubuntu-24.04
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.12"
21
+ - name: Install dependencies
22
+ run: |
23
+ sudo apt-get update
24
+ sudo apt-get install -y libeigen3-dev libsuitesparse-dev
25
+ python -m pip install --upgrade pip
26
+ python -m pip install -r requirements-dev.txt
27
+ - name: Lint
28
+ run: python -m pyflakes generator legacy tests/python examples/extension tools installer
29
+ - name: Configure and build
30
+ run: |
31
+ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DPython3_EXECUTABLE="$(which python)"
32
+ cmake --build build -j
33
+ - name: C++ tests
34
+ run: ctest --test-dir build --output-on-failure -V
35
+ - name: Python tests (with the runtime built)
36
+ run: python -m pytest -v
37
+ - name: freedyn2 run (.fds and .yaml, model plugin)
38
+ env:
39
+ PYTHONPATH: generator
40
+ run: |
41
+ python -m fdgen.cli run examples/compare/pendulum.fds -o pendulum.csv
42
+ python -m fdgen.cli run examples/compare/spline_spring.fds -o spline_spring.csv
43
+ python -m fdgen.cli run examples/driven_rotor.yaml -o driven_rotor.csv -- --linear-solver klu
44
+
45
+ # Windows: MSVC; Eigen and KLU (SuiteSparse with only KLU and its parts, no BLAS, as DLLs:
46
+ # LGPL, linked dynamically) from tools/build_deps.py as for the wheels, cached; model plugins
47
+ # compiled with MSVC (CC=cl) as a user with Visual Studio Build Tools would.
48
+ windows:
49
+ runs-on: windows-latest
50
+ env:
51
+ CC: cl
52
+ PYTHONPATH: generator
53
+ steps:
54
+ - uses: actions/checkout@v4
55
+ - uses: actions/setup-python@v5
56
+ with:
57
+ python-version: "3.12"
58
+ - uses: ilammy/msvc-dev-cmd@v1
59
+ - uses: actions/cache@v4
60
+ with:
61
+ path: deps
62
+ key: deps-${{ runner.os }}-msvc-${{ hashFiles('tools/build_deps.py') }}
63
+ - name: Install dependencies
64
+ run: |
65
+ python -m pip install --upgrade pip
66
+ python -m pip install -r requirements-dev.txt
67
+ python tools/build_deps.py deps
68
+ - name: Configure and build
69
+ run: |
70
+ cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$PWD\deps" `
71
+ -DPython3_EXECUTABLE="$((Get-Command python).Source)"
72
+ cmake --build build
73
+ - name: C++ tests
74
+ run: ctest --test-dir build --output-on-failure
75
+ - name: Python tests
76
+ run: python -m pytest -v
77
+ - name: freedyn2 run (.fds and .yaml, model plugin)
78
+ run: |
79
+ python -m fdgen.cli run examples/compare/pendulum.fds -o pendulum.csv
80
+ python -m fdgen.cli run examples/driven_rotor.yaml -o driven_rotor.csv -- --linear-solver klu
81
+
82
+ # FreeDyn 2 against the legacy kernel (freedyn-org/me, private). Needs a repository
83
+ # secret FREEDYN_ME_TOKEN with read access to freedyn-org/me; skipped without it.
84
+ legacy-compare:
85
+ runs-on: ubuntu-24.04
86
+ env:
87
+ HAS_TOKEN: ${{ secrets.FREEDYN_ME_TOKEN != '' }}
88
+ steps:
89
+ - name: Notice
90
+ if: env.HAS_TOKEN != 'true'
91
+ run: echo "::notice::FREEDYN_ME_TOKEN is not set, legacy comparison skipped"
92
+ - uses: actions/checkout@v4
93
+ if: env.HAS_TOKEN == 'true'
94
+ - uses: actions/checkout@v4
95
+ if: env.HAS_TOKEN == 'true'
96
+ with:
97
+ repository: freedyn-org/me
98
+ token: ${{ secrets.FREEDYN_ME_TOKEN }}
99
+ path: me
100
+ - uses: actions/setup-python@v5
101
+ if: env.HAS_TOKEN == 'true'
102
+ with:
103
+ python-version: "3.12"
104
+ - name: Install dependencies
105
+ if: env.HAS_TOKEN == 'true'
106
+ run: |
107
+ sudo apt-get update
108
+ sudo apt-get install -y libeigen3-dev libsuitesparse-dev
109
+ python -m pip install --upgrade pip
110
+ python -m pip install -r requirements-dev.txt mkl-devel
111
+ - name: Build FreeDyn 2
112
+ if: env.HAS_TOKEN == 'true'
113
+ run: |
114
+ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DPython3_EXECUTABLE="$(which python)"
115
+ cmake --build build -j
116
+ - name: Build legacy FreeDyn
117
+ if: env.HAS_TOKEN == 'true'
118
+ run: MKL_ROOT="$(python -c 'import sys; print(sys.prefix)')" python legacy/build_legacy.py me -o build/legacy
119
+ - name: Compare
120
+ if: env.HAS_TOKEN == 'true'
121
+ run: |
122
+ python -m pytest -v tests/python/test_legacy_compare.py tests/python/test_legacy_physics.py
123
+ python legacy/compare.py examples/compare/*.fds --level exact --markdown exact.md
124
+ python legacy/compare.py examples/compare/*.fds --level physics --markdown physics.md
125
+ PYTHONPATH=generator python -m fdgen.cli compare examples/compare/*.fds --legacy build/legacy/build/FreeDyn --markdown demo.md
126
+ { echo "### freedyn2 compare (both programs on the same .fds, converged reference)"; cat demo.md; echo
127
+ echo "### Exact (legacy profile)"; cat exact.md; echo; echo "### Physics (v2 profile vs reference)"; cat physics.md; } >> "$GITHUB_STEP_SUMMARY"
@@ -0,0 +1,58 @@
1
+ name: Docs
2
+
3
+ # The user documentation (mkdocs.yml, docs/) with the live examples (tools/docs_examples.py:
4
+ # viewers exported with the runtime). Built on every pull request that touches it; published
5
+ # to GitHub Pages from main once Pages is enabled (Settings → Pages → Source: GitHub Actions,
6
+ # and the repository variable PAGES_ENABLED = true).
7
+
8
+ on:
9
+ push:
10
+ branches: [main]
11
+ pull_request:
12
+ paths: [docs/**, mkdocs.yml, tools/docs_*.py, examples/**, schema/**, generator/fdgen/view/**, .github/workflows/docs.yml]
13
+ workflow_dispatch:
14
+
15
+ concurrency:
16
+ group: docs-${{ github.ref }}
17
+ cancel-in-progress: true
18
+
19
+ jobs:
20
+ build:
21
+ runs-on: ubuntu-24.04
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ - uses: actions/setup-python@v5
25
+ with:
26
+ python-version: "3.12"
27
+ - name: Install dependencies
28
+ run: |
29
+ sudo apt-get update
30
+ sudo apt-get install -y libeigen3-dev libsuitesparse-dev
31
+ python -m pip install --upgrade pip
32
+ python -m pip install -r requirements-dev.txt -r requirements-docs.txt
33
+ - name: Build the runtime
34
+ run: |
35
+ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DFD_BUILD_EXAMPLES=OFF -DBUILD_TESTING=OFF -DPython3_EXECUTABLE="$(which python)"
36
+ cmake --build build -j --target freedyn2_run freedyn2_road
37
+ - name: Live examples
38
+ run: python tools/docs_examples.py
39
+ - name: Build the site
40
+ run: mkdocs build --strict
41
+ - uses: actions/upload-pages-artifact@v3
42
+ if: github.ref == 'refs/heads/main' && vars.PAGES_ENABLED == 'true'
43
+ with:
44
+ path: site
45
+
46
+ deploy:
47
+ needs: build
48
+ if: github.ref == 'refs/heads/main' && vars.PAGES_ENABLED == 'true'
49
+ runs-on: ubuntu-24.04
50
+ permissions:
51
+ pages: write
52
+ id-token: write
53
+ environment:
54
+ name: github-pages
55
+ url: ${{ steps.deployment.outputs.page_url }}
56
+ steps:
57
+ - id: deployment
58
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,340 @@
1
+ name: Wheels
2
+
3
+ # Wheels for Windows and Linux (pip install / uv tool install freedyn2): the Python package with
4
+ # the compiled runtime and its KLU libraries (pyproject.toml: scikit-build-core, cibuildwheel), and
5
+ # the Windows installer built from the Windows wheel (installer/windows).
6
+ # Runs for pull requests that change the packaging, by hand, and for version tags. A version tag
7
+ # (v0.1.0, ...) must equal the version in pyproject.toml; it publishes to PyPI (trusted publishing:
8
+ # the PyPI project must have this repository and workflow registered as a trusted publisher,
9
+ # environment "pypi"), creates the GitHub Release with the wheels, the sdist and the installer,
10
+ # and updates the winget package (secret WINGET_TOKEN). Maintainers: docs/releasing.md.
11
+ #
12
+ # Code signing (optional, on version tags only): SignPath (SignPath Foundation for open-source
13
+ # projects), enabled by the secret SIGNPATH_API_TOKEN and the variables SIGNPATH_ORGANIZATION_ID,
14
+ # SIGNPATH_PROJECT_SLUG, SIGNPATH_SIGNING_POLICY_SLUG, SIGNPATH_CONFIG_PROGRAMS,
15
+ # SIGNPATH_CONFIG_INSTALLER (artifact configurations: installer/windows/signpath). Without the token
16
+ # the installer is built unsigned. Another signer replaces the two steps "Sign the programs" and
17
+ # "Sign the installer": they read build/installer/to-sign and dist-installer and write the signed
18
+ # files back to the same places.
19
+ on:
20
+ pull_request:
21
+ paths: [pyproject.toml, CMakeLists.txt, tools/**, installer/**, .github/workflows/wheels.yml]
22
+ workflow_dispatch:
23
+ push:
24
+ tags: ["v*"]
25
+
26
+ concurrency:
27
+ group: wheels-${{ github.ref }}
28
+ cancel-in-progress: true
29
+
30
+ jobs:
31
+ version:
32
+ runs-on: ubuntu-24.04
33
+ outputs:
34
+ version: ${{ steps.v.outputs.version }}
35
+ prerelease: ${{ steps.v.outputs.prerelease }}
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+ - name: Version of pyproject.toml (equal to the tag for a release)
39
+ id: v
40
+ run: |
41
+ v=$(python3 -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')
42
+ echo "version=$v" >> "$GITHUB_OUTPUT"
43
+ if [[ "$v" =~ [a-zA-Z] ]]; then echo "prerelease=true" >> "$GITHUB_OUTPUT"; else echo "prerelease=false" >> "$GITHUB_OUTPUT"; fi
44
+ if [[ "$GITHUB_REF" == refs/tags/v* && "${GITHUB_REF_NAME#v}" != "$v" ]]; then
45
+ echo "::error::tag $GITHUB_REF_NAME does not match the version $v in pyproject.toml (expected tag v$v)"
46
+ exit 1
47
+ fi
48
+ echo "version $v"
49
+
50
+ wheels:
51
+ needs: [version]
52
+ strategy:
53
+ matrix:
54
+ os: [ubuntu-24.04, windows-latest]
55
+ runs-on: ${{ matrix.os }}
56
+ steps:
57
+ - uses: actions/checkout@v4
58
+ - uses: actions/cache@v4 # the dependencies of the Windows build (on Linux they are built in the container)
59
+ if: runner.os == 'Windows'
60
+ with:
61
+ path: C:/fd-deps
62
+ key: wheel-deps-${{ runner.os }}-${{ hashFiles('tools/build_deps.py') }}
63
+ - uses: pypa/cibuildwheel@v2.23.3
64
+ env:
65
+ CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28
66
+ - uses: actions/upload-artifact@v4
67
+ with:
68
+ name: wheels-${{ matrix.os }}
69
+ path: wheelhouse/*.whl
70
+
71
+ sdist:
72
+ needs: [version]
73
+ runs-on: ubuntu-24.04
74
+ steps:
75
+ - uses: actions/checkout@v4
76
+ - run: pipx run build --sdist
77
+ - uses: actions/upload-artifact@v4
78
+ with:
79
+ name: sdist
80
+ path: dist/*.tar.gz
81
+
82
+ # The Windows installer (Inno Setup) from the Windows wheel, then installed, used and uninstalled.
83
+ installer:
84
+ needs: [wheels]
85
+ runs-on: windows-latest
86
+ env:
87
+ SIGNER: ${{ (secrets.SIGNPATH_API_TOKEN != '' && startsWith(github.ref, 'refs/tags/v')) && 'signpath' || 'none' }}
88
+ steps:
89
+ - uses: actions/checkout@v4
90
+ - uses: actions/setup-python@v5
91
+ with:
92
+ python-version: "3.12"
93
+ - uses: actions/download-artifact@v4
94
+ with:
95
+ name: wheels-windows-latest
96
+ path: wheelhouse
97
+ - name: Inno Setup
98
+ run: |
99
+ $iscc = "${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe"
100
+ if (-not (Test-Path $iscc)) {
101
+ choco install innosetup -y --no-progress
102
+ if ($LASTEXITCODE) { exit 1 }
103
+ }
104
+ if (-not (Test-Path $iscc)) { Write-Error "ISCC.exe not found after installing Inno Setup"; exit 1 }
105
+ "ISCC=$iscc" >> $env:GITHUB_ENV
106
+ - uses: actions/cache@v4
107
+ with:
108
+ path: build/installer/downloads
109
+ key: installer-python-${{ hashFiles('installer/windows/build.py') }}
110
+ - name: Stage (Python, packages, launchers)
111
+ run: python installer/windows/build.py stage --wheel-dir wheelhouse --work build/installer
112
+
113
+ # --- signing of the programs inside the installer (SIGNER) -----------------------------
114
+ - name: Collect the programs to sign
115
+ if: env.SIGNER != 'none'
116
+ run: |
117
+ # our own programs only (python.exe and the packages' binaries carry their makers' signatures)
118
+ $stage = "build/installer/stage/core"
119
+ $files = @(Get-ChildItem "$stage/bin/*.exe") + @(Get-ChildItem "$stage/python/Scripts/freedyn2*.exe") +
120
+ @(Get-ChildItem "$stage/python/Lib/site-packages/fdgen/bin/*.exe")
121
+ foreach ($f in $files) {
122
+ $rel = [IO.Path]::GetRelativePath((Resolve-Path $stage), $f.FullName)
123
+ $dest = Join-Path "build/installer/to-sign" $rel
124
+ New-Item -ItemType Directory -Force (Split-Path $dest) | Out-Null
125
+ Copy-Item $f.FullName $dest
126
+ }
127
+ Get-ChildItem -Recurse -File build/installer/to-sign | ForEach-Object FullName
128
+ - name: Upload the programs to sign
129
+ if: env.SIGNER == 'signpath'
130
+ id: upload-programs
131
+ uses: actions/upload-artifact@v4
132
+ with:
133
+ name: programs-unsigned
134
+ path: build/installer/to-sign
135
+ - name: Sign the programs
136
+ if: env.SIGNER == 'signpath'
137
+ uses: signpath/github-action-submit-signing-request@f6d04783b4569d051e0c80105fe66e82819d0092 # v3.0
138
+ with:
139
+ api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
140
+ organization-id: ${{ vars.SIGNPATH_ORGANIZATION_ID }}
141
+ project-slug: ${{ vars.SIGNPATH_PROJECT_SLUG }}
142
+ signing-policy-slug: ${{ vars.SIGNPATH_SIGNING_POLICY_SLUG }}
143
+ artifact-configuration-slug: ${{ vars.SIGNPATH_CONFIG_PROGRAMS }}
144
+ github-artifact-id: ${{ steps.upload-programs.outputs.artifact-id }}
145
+ wait-for-completion: true
146
+ wait-for-completion-timeout-in-seconds: 7200 # release signing waits for a manual approval
147
+ output-artifact-directory: build/installer/to-sign
148
+ - name: Put the signed programs into the stage
149
+ if: env.SIGNER != 'none'
150
+ run: |
151
+ Copy-Item -Recurse -Force build/installer/to-sign/* build/installer/stage/core/
152
+ Get-ChildItem -Recurse -File build/installer/to-sign | ForEach-Object {
153
+ $s = Get-AuthenticodeSignature $_.FullName
154
+ "$($s.Status) $($_.Name)"
155
+ if ($s.Status -ne 'Valid') { Write-Error "$($_.Name) is not signed"; exit 1 }
156
+ }
157
+
158
+ - name: Installer
159
+ run: python installer/windows/build.py compile --work build/installer --out dist-installer --iscc "$env:ISCC"
160
+
161
+ - name: Upload the installer to sign
162
+ if: env.SIGNER == 'signpath'
163
+ id: upload-installer
164
+ uses: actions/upload-artifact@v4
165
+ with:
166
+ name: installer-unsigned
167
+ path: dist-installer/*.exe
168
+ - name: Sign the installer
169
+ if: env.SIGNER == 'signpath'
170
+ uses: signpath/github-action-submit-signing-request@f6d04783b4569d051e0c80105fe66e82819d0092 # v3.0
171
+ with:
172
+ api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
173
+ organization-id: ${{ vars.SIGNPATH_ORGANIZATION_ID }}
174
+ project-slug: ${{ vars.SIGNPATH_PROJECT_SLUG }}
175
+ signing-policy-slug: ${{ vars.SIGNPATH_SIGNING_POLICY_SLUG }}
176
+ artifact-configuration-slug: ${{ vars.SIGNPATH_CONFIG_INSTALLER }}
177
+ github-artifact-id: ${{ steps.upload-installer.outputs.artifact-id }}
178
+ wait-for-completion: true
179
+ wait-for-completion-timeout-in-seconds: 7200
180
+ output-artifact-directory: dist-installer
181
+ - name: Check the signature of the installer
182
+ if: env.SIGNER != 'none'
183
+ run: |
184
+ $s = Get-AuthenticodeSignature (Get-ChildItem dist-installer/FreeDyn2-*-setup.exe)
185
+ "$($s.Status) $($s.SignerCertificate.Subject)"
186
+ if ($s.Status -ne 'Valid') { exit 1 }
187
+
188
+ # --- smoke test: install silently (per user, into a path with a space), use, uninstall ----
189
+ - name: Smoke test
190
+ run: |
191
+ $ErrorActionPreference = 'Stop'
192
+ function Check([string]$what) { if ($LASTEXITCODE) { Write-Error "$what failed (exit code $LASTEXITCODE)" } }
193
+ $setup = (Get-ChildItem dist-installer/FreeDyn2-*-setup.exe | Select-Object -First 1).FullName
194
+ $dir = Join-Path $env:RUNNER_TEMP 'FreeDyn2 smoke'
195
+ $log = Join-Path $env:RUNNER_TEMP 'install.log'
196
+ $p = Start-Process $setup -Wait -PassThru -ArgumentList '/VERYSILENT', '/SUPPRESSMSGBOXES', '/NORESTART', '/CURRENTUSER',
197
+ "/DIR=`"$dir`"", '/COMPONENTS=core,compiler,examples', '/TASKS=path', "/LOG=`"$log`""
198
+ if ($p.ExitCode -ne 0) { Get-Content $log -Tail 50; Write-Error "setup exit code $($p.ExitCode)" }
199
+ $bin = Join-Path $dir 'bin'
200
+ foreach ($f in 'bin\freedyn2.exe', 'bin\freedyn2-gui.exe', 'bin\freedyn2-prompt.cmd', 'python\python.exe',
201
+ 'python\Lib\site-packages\ziglang', 'examples\driven_rotor.yaml', 'licenses\python-packages.txt',
202
+ 'THIRD-PARTY-NOTICES.txt', 'unins000.exe') {
203
+ if (-not (Test-Path (Join-Path $dir $f))) { Write-Error "not installed: $f" }
204
+ }
205
+ $userPath = (Get-ItemProperty HKCU:\Environment).Path -split ';'
206
+ if ($userPath -notcontains $bin) { Write-Error "bin not on the user PATH: $userPath" }
207
+
208
+ # an isolated user: settings in FREEDYN2_HOME, no CC; the compiler is Zig (component compiler)
209
+ $env:FREEDYN2_HOME = Join-Path $env:RUNNER_TEMP 'fd2home'
210
+ Remove-Item Env:CC -ErrorAction SilentlyContinue
211
+ $work = Join-Path $env:RUNNER_TEMP 'fd2work'
212
+ New-Item -ItemType Directory -Force $work | Out-Null
213
+ Set-Location $work
214
+ $fd = Join-Path $bin 'freedyn2.exe'
215
+ & $fd --version; Check 'freedyn2 --version'
216
+ & $fd config compiler zig; Check 'freedyn2 config compiler zig'
217
+ & $fd doctor; Check 'freedyn2 doctor'
218
+ & $fd run (Join-Path $dir 'examples\compare\pendulum.fds') -o pendulum.csv; Check 'freedyn2 run pendulum.fds'
219
+ & $fd run (Join-Path $dir 'examples\driven_rotor.yaml') -o driven_rotor.csv; Check 'freedyn2 run driven_rotor.yaml (Zig)'
220
+ foreach ($csv in 'pendulum.csv', 'driven_rotor.csv') { if (-not (Test-Path $csv)) { Write-Error "no $csv" } }
221
+ & $fd setup-mcp --client claude-desktop --dry-run; Check 'freedyn2 setup-mcp --dry-run'
222
+ # the launcher in python\Scripts works as well (relocated like bin)
223
+ & (Join-Path $dir 'python\Scripts\freedyn2.exe') --version; Check 'python\Scripts\freedyn2.exe --version'
224
+
225
+ Set-Location $env:RUNNER_TEMP
226
+ $p = Start-Process (Join-Path $dir 'unins000.exe') -Wait -PassThru -ArgumentList '/VERYSILENT', '/SUPPRESSMSGBOXES', '/NORESTART'
227
+ if ($p.ExitCode -ne 0) { Write-Error "uninstall exit code $($p.ExitCode)" }
228
+ # the uninstaller continues from a copy in %TEMP%: wait for it
229
+ for ($i = 0; $i -lt 180 -and (Test-Path $dir); $i++) { Start-Sleep -Seconds 1 }
230
+ if (Test-Path $dir) { Get-ChildItem -Recurse $dir | Select-Object -First 30 | ForEach-Object FullName; Write-Error "left after uninstall: $dir" }
231
+ $userPath = (Get-ItemProperty HKCU:\Environment).Path -split ';'
232
+ if ($userPath -contains $bin) { Write-Error "bin still on the user PATH" }
233
+ "installed, used and uninstalled"
234
+ - uses: actions/upload-artifact@v4
235
+ with:
236
+ name: installer-windows
237
+ path: dist-installer/FreeDyn2-*-setup.exe
238
+ if-no-files-found: error
239
+
240
+ publish:
241
+ if: startsWith(github.ref, 'refs/tags/v')
242
+ needs: [wheels, sdist, installer]
243
+ runs-on: ubuntu-24.04
244
+ environment: pypi
245
+ permissions:
246
+ id-token: write
247
+ steps:
248
+ - uses: actions/download-artifact@v4
249
+ with:
250
+ pattern: wheels-*
251
+ path: dist
252
+ merge-multiple: true
253
+ - uses: actions/download-artifact@v4
254
+ with:
255
+ name: sdist
256
+ path: dist
257
+ - uses: pypa/gh-action-pypi-publish@release/v1
258
+
259
+ # GitHub Release vX.Y.Z: wheels, sdist, the installer (also as FreeDyn2-setup.exe for the stable
260
+ # link .../releases/latest/download/FreeDyn2-setup.exe), SHA256SUMS; notes from CHANGELOG.md
261
+ # and generated. The app's update notice reads the latest release.
262
+ release:
263
+ if: startsWith(github.ref, 'refs/tags/v')
264
+ needs: [version, wheels, sdist, installer]
265
+ runs-on: ubuntu-24.04
266
+ permissions:
267
+ contents: write
268
+ steps:
269
+ - uses: actions/checkout@v4
270
+ - uses: actions/download-artifact@v4 # not the unsigned intermediates of the signing
271
+ with:
272
+ pattern: wheels-*
273
+ path: dist
274
+ merge-multiple: true
275
+ - uses: actions/download-artifact@v4
276
+ with:
277
+ name: sdist
278
+ path: dist
279
+ - uses: actions/download-artifact@v4
280
+ with:
281
+ name: installer-windows
282
+ path: dist
283
+ - name: Assets and notes
284
+ env:
285
+ VERSION: ${{ needs.version.outputs.version }}
286
+ run: |
287
+ cd dist
288
+ cp "FreeDyn2-$VERSION-setup.exe" FreeDyn2-setup.exe
289
+ sha256sum -- *.whl *.tar.gz *.exe > SHA256SUMS
290
+ cat SHA256SUMS
291
+ cd ..
292
+ # the section "## [VERSION]" of CHANGELOG.md (empty if there is none)
293
+ python3 - "$VERSION" > notes.md <<'EOF'
294
+ import re, sys
295
+ text = open("CHANGELOG.md", encoding="utf-8").read()
296
+ m = re.search(rf"^## \[{re.escape(sys.argv[1])}\][^\n]*\n(.*?)(?=^## |\Z)", text, re.M | re.S)
297
+ print(m.group(1).strip() if m else "")
298
+ EOF
299
+ cat notes.md
300
+ - uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
301
+ with:
302
+ name: FreeDyn 2 version ${{ needs.version.outputs.version }}
303
+ body_path: notes.md
304
+ generate_release_notes: true
305
+ prerelease: ${{ needs.version.outputs.prerelease == 'true' }}
306
+ make_latest: ${{ needs.version.outputs.prerelease == 'true' && 'false' || 'true' }}
307
+ fail_on_unmatched_files: true
308
+ files: |
309
+ dist/*.whl
310
+ dist/*.tar.gz
311
+ dist/FreeDyn2-*-setup.exe
312
+ dist/FreeDyn2-setup.exe
313
+ dist/SHA256SUMS
314
+
315
+ # winget (microsoft/winget-pkgs): a pull request with the new version, after the first version was
316
+ # submitted by hand (installer/winget). Needs the secret WINGET_TOKEN (a classic GitHub token
317
+ # with public_repo of an account with a fork of winget-pkgs); skipped without it and for pre-releases.
318
+ winget:
319
+ if: startsWith(github.ref, 'refs/tags/v')
320
+ needs: [version, release]
321
+ runs-on: windows-latest
322
+ env:
323
+ HAS_TOKEN: ${{ secrets.WINGET_TOKEN != '' }}
324
+ PRERELEASE: ${{ needs.version.outputs.prerelease }}
325
+ steps:
326
+ - name: Notice
327
+ if: env.HAS_TOKEN != 'true' || env.PRERELEASE == 'true'
328
+ run: echo "::notice::winget update skipped (no WINGET_TOKEN, or a pre-release)"
329
+ - name: wingetcreate update
330
+ if: env.HAS_TOKEN == 'true' && env.PRERELEASE != 'true'
331
+ env:
332
+ WINGET_TOKEN: ${{ secrets.WINGET_TOKEN }}
333
+ VERSION: ${{ needs.version.outputs.version }}
334
+ run: |
335
+ $url = "https://github.com/$env:GITHUB_REPOSITORY/releases/download/v$env:VERSION/FreeDyn2-$env:VERSION-setup.exe"
336
+ Invoke-WebRequest https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
337
+ # the same installer for both scopes of the manifest (user, machine)
338
+ .\wingetcreate.exe update FreeDynOrg.FreeDyn2 --version $env:VERSION `
339
+ --urls "$url|x64|user" "$url|x64|machine" --submit --token $env:WINGET_TOKEN
340
+ if ($LASTEXITCODE) { exit 1 }
@@ -0,0 +1,15 @@
1
+ build/
2
+ __pycache__/
3
+ *.egg-info/
4
+ .pytest_cache/
5
+ *.csv
6
+
7
+ # tire data sets (.tir) stay outside the repository (FREEDYN2_TIR)
8
+ *.tir
9
+
10
+ # documentation: generated live examples, the built site
11
+ docs/live/
12
+ site/
13
+
14
+ # worktrees of parallel agent sessions
15
+ .claude/worktrees/
@@ -0,0 +1,36 @@
1
+ # Changelog
2
+
3
+ All notable changes of FreeDyn 2. Versions follow [semantic versioning](https://semver.org);
4
+ the section of a version becomes the text of its GitHub Release (docs/releasing.md).
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [0.1.0rc1] - 2026-11-06
9
+
10
+ Release candidate: a test of the release process (PyPI, GitHub Release, Windows installer).
11
+ Not signed yet. Install it explicitly: `pip install --pre freedyn2` or the installer from this
12
+ release.
13
+
14
+ ### Added
15
+
16
+ - Wheels for Windows (x64) and Linux (x86_64): `pip install freedyn2`, `uv tool install freedyn2`;
17
+ extras `gui` (app window, pywebview) and `compiler` (Zig, a C compiler for model plugins).
18
+ - Windows installer `FreeDyn2-setup.exe`: per user without administrator rights, its own Python,
19
+ the app, the command line, optionally Zig, the .fds association and the Claude Desktop setup.
20
+ - The app `freedyn2-gui` / `freedyn2 gui`: start page (open, recent models, examples), a window
21
+ per model, one instance, an update notice for new releases.
22
+ - `freedyn2 convert`: legacy .fds models as YAML model files.
23
+ - The Python API: `import freedyn2` (load, run, check, sweep, convert).
24
+ - `freedyn2 setup-mcp`, `freedyn2 doctor`, `freedyn2 config`, `freedyn2 update-check`.
25
+ - Compiler selection: Zig, MSVC without a developer prompt (vswhere), gcc, clang.
26
+
27
+ ## [0.1.0] - unreleased
28
+
29
+ First release.
30
+
31
+ ### Added
32
+
33
+ - Wheels for Windows (x64) and Linux (x86_64) on PyPI: `pip install freedyn2`, `uv tool install freedyn2`.
34
+ - Windows installer `FreeDyn2-setup.exe` (per user, no administrator rights): its own Python, the
35
+ app, the viewer, the MCP server and optionally a C compiler (Zig) for model plugins.
36
+ - ...
@@ -0,0 +1,78 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use FreeDyn 2, please cite it with these metadata."
3
+ title: "FreeDyn 2: multibody dynamics with generated models"
4
+ type: software
5
+ authors:
6
+ - family-names: Oberpeilsteiner
7
+ given-names: Stefan
8
+ - name: "The FreeDyn 2 contributors"
9
+ repository-code: "https://github.com/freedyn-org/freedyn2"
10
+ url: "https://freedyn-org.github.io/freedyn2/"
11
+ license: Apache-2.0
12
+ keywords:
13
+ - multibody dynamics
14
+ - HHT
15
+ - Lie group time integration
16
+ - CasADi
17
+ - code generation
18
+ references:
19
+ - type: conference-paper
20
+ title: "FreeDyn: a free, flexible and state of the art multibody simulation package for education, research and industrial applications"
21
+ authors:
22
+ - family-names: Witteveen
23
+ given-names: Wolfgang
24
+ - family-names: Lauss
25
+ given-names: Thomas
26
+ - family-names: Oberpeilsteiner
27
+ given-names: Stefan
28
+ collection-title: "Nonlinear Structures & Systems, Volume 1"
29
+ publisher:
30
+ name: Springer
31
+ year: 2021
32
+ doi: "10.1007/978-3-030-47626-7_8"
33
+ - type: conference-paper
34
+ title: "FreeDyn: a multibody simulation research code"
35
+ authors:
36
+ - family-names: Nachbagauer
37
+ given-names: Karin
38
+ - family-names: Sherif
39
+ given-names: Karim
40
+ - family-names: Witteveen
41
+ given-names: Wolfgang
42
+ conference:
43
+ name: "11th World Congress on Computational Mechanics (WCCM XI), 5th European Conference on Computational Mechanics (ECCM V)"
44
+ city: Barcelona
45
+ year: 2014
46
+ - type: conference-paper
47
+ title: "FreeDyn: a software for advanced multibody simulation: applications in the field of vehicle dynamics"
48
+ authors:
49
+ - family-names: Oberpeilsteiner
50
+ given-names: Stefan
51
+ - family-names: Lauss
52
+ given-names: Thomas
53
+ - family-names: Eichmeir
54
+ given-names: Philipp
55
+ - family-names: Steiner
56
+ given-names: Wolfgang
57
+ conference:
58
+ name: "ECCOMAS Thematic Conference on Multibody Dynamics 2019"
59
+ city: Duisburg
60
+ year: 2019
61
+ - type: article
62
+ title: "A modified HHT method for the numerical simulation of rigid body rotations with Euler parameters"
63
+ authors:
64
+ - family-names: Sherif
65
+ given-names: Karim
66
+ - family-names: Nachbagauer
67
+ given-names: Karin
68
+ - family-names: Steiner
69
+ given-names: Wolfgang
70
+ - family-names: Lauss
71
+ given-names: Thomas
72
+ journal: "Multibody System Dynamics"
73
+ volume: 46
74
+ issue: 2
75
+ start: 181
76
+ end: 202
77
+ year: 2019
78
+ doi: "10.1007/s11044-019-09672-6"
@@ -0,0 +1,9 @@
1
+ # Notes for Claude
2
+
3
+ ## Brand
4
+
5
+ Anything visual or public-facing (viewer UI, docs theme, README, slides, release notes, social
6
+ images) follows [`brand/README.md`](brand/README.md): name always `freedyn2` in lower case, claim
7
+ "ai-first multibody dynamics.", colors and fonts from [`brand/tokens.json`](brand/tokens.json)
8
+ (CSS: [`brand/tokens.css`](brand/tokens.css)), logos from [`brand/logo/`](brand/logo/). Do not
9
+ invent new colors or logo variants; extend the tokens instead.