pyfastmm 1.0.0__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 (67) hide show
  1. pyfastmm-1.0.0/.github/workflows/publish.yml +107 -0
  2. pyfastmm-1.0.0/.github/workflows/test.yml +55 -0
  3. pyfastmm-1.0.0/.github/workflows/wheels.yml +171 -0
  4. pyfastmm-1.0.0/.gitignore +303 -0
  5. pyfastmm-1.0.0/.gitmodules +3 -0
  6. pyfastmm-1.0.0/.python-version +1 -0
  7. pyfastmm-1.0.0/CHANGELOG.md +7 -0
  8. pyfastmm-1.0.0/LICENSE +92 -0
  9. pyfastmm-1.0.0/Makefile +50 -0
  10. pyfastmm-1.0.0/PKG-INFO +117 -0
  11. pyfastmm-1.0.0/README.md +86 -0
  12. pyfastmm-1.0.0/devenv.lock +92 -0
  13. pyfastmm-1.0.0/devenv.nix +62 -0
  14. pyfastmm-1.0.0/devenv.yaml +20 -0
  15. pyfastmm-1.0.0/examples/two_sphere_cluster.py +25 -0
  16. pyfastmm-1.0.0/external/fastmm2/.gitignore +50 -0
  17. pyfastmm-1.0.0/external/fastmm2/LICENSE.txt +64 -0
  18. pyfastmm-1.0.0/external/fastmm2/README.md +144 -0
  19. pyfastmm-1.0.0/external/fastmm2/bpca1024.dat +1024 -0
  20. pyfastmm-1.0.0/external/fastmm2/build_multiT.py +53 -0
  21. pyfastmm-1.0.0/external/fastmm2/example.m +59 -0
  22. pyfastmm-1.0.0/external/fastmm2/example.py +77 -0
  23. pyfastmm-1.0.0/external/fastmm2/src/CMakeLists.txt +43 -0
  24. pyfastmm-1.0.0/external/fastmm2/src/Makefile +56 -0
  25. pyfastmm-1.0.0/external/fastmm2/src/T_matrix.f90 +80 -0
  26. pyfastmm-1.0.0/external/fastmm2/src/common.f90 +478 -0
  27. pyfastmm-1.0.0/external/fastmm2/src/gaussquad.f90 +196 -0
  28. pyfastmm-1.0.0/external/fastmm2/src/geometry.f90 +218 -0
  29. pyfastmm-1.0.0/external/fastmm2/src/integration_points.f90 +112 -0
  30. pyfastmm-1.0.0/external/fastmm2/src/interpolation.f90 +369 -0
  31. pyfastmm-1.0.0/external/fastmm2/src/io.f90 +1029 -0
  32. pyfastmm-1.0.0/external/fastmm2/src/main.f90 +491 -0
  33. pyfastmm-1.0.0/external/fastmm2/src/matvec.f90 +1144 -0
  34. pyfastmm-1.0.0/external/fastmm2/src/matvec_adaptive.f90 +1343 -0
  35. pyfastmm-1.0.0/external/fastmm2/src/matvec_new.f90 +1294 -0
  36. pyfastmm-1.0.0/external/fastmm2/src/matvec_old.f90 +731 -0
  37. pyfastmm-1.0.0/external/fastmm2/src/mie.f90 +1522 -0
  38. pyfastmm-1.0.0/external/fastmm2/src/octtree.f90 +383 -0
  39. pyfastmm-1.0.0/external/fastmm2/src/octtree_adaptive.f90 +423 -0
  40. pyfastmm-1.0.0/external/fastmm2/src/orientation_averaging.f90 +181 -0
  41. pyfastmm-1.0.0/external/fastmm2/src/possu.f90 +158 -0
  42. pyfastmm-1.0.0/external/fastmm2/src/sfunctions.f90 +885 -0
  43. pyfastmm-1.0.0/external/fastmm2/src/solver.f90 +1162 -0
  44. pyfastmm-1.0.0/external/fastmm2/src/translations.f90 +1824 -0
  45. pyfastmm-1.0.0/external/fastmm2/src/wigner.f90 +522 -0
  46. pyfastmm-1.0.0/flake.nix +98 -0
  47. pyfastmm-1.0.0/meson.build +107 -0
  48. pyfastmm-1.0.0/pyproject.toml +124 -0
  49. pyfastmm-1.0.0/scripts/streamlit_app.py +674 -0
  50. pyfastmm-1.0.0/src/pyfastmm/__init__.py +6 -0
  51. pyfastmm-1.0.0/src/pyfastmm/_build.py +50 -0
  52. pyfastmm-1.0.0/src/pyfastmm/_config.py +295 -0
  53. pyfastmm-1.0.0/src/pyfastmm/_fastmm.py +215 -0
  54. pyfastmm-1.0.0/src/pyfastmm/_fortran/fastmm2_f2py.f90 +269 -0
  55. pyfastmm-1.0.0/src/pyfastmm/_fortran/patches/gaussquad-f2py-ascii-fix.patch +80 -0
  56. pyfastmm-1.0.0/tests/conftest.py +4 -0
  57. pyfastmm-1.0.0/tests/data/fractal_N128_Df2.0.dat +149 -0
  58. pyfastmm-1.0.0/tests/data/fractal_sweep.toml +31 -0
  59. pyfastmm-1.0.0/tests/test_compatibility.py +153 -0
  60. pyfastmm-1.0.0/tests/test_config.py +114 -0
  61. pyfastmm-1.0.0/tests/test_f2py_smoke.py +75 -0
  62. pyfastmm-1.0.0/tests/test_solve.py +63 -0
  63. pyfastmm-1.0.0/tests/test_tmatrix.py +36 -0
  64. pyfastmm-1.0.0/tools/apply_patch.py +25 -0
  65. pyfastmm-1.0.0/tools/build_f2py_ext.py +70 -0
  66. pyfastmm-1.0.0/tools/wheel_smoke_test.py +37 -0
  67. pyfastmm-1.0.0/uv.lock +1695 -0
@@ -0,0 +1,107 @@
1
+ name: Continuous Delivery
2
+
3
+ # Tag-first release. semantic-release decides the version and creates the
4
+ # tag + GitHub Release; the same commit's wheels then build (via the
5
+ # reusable wheels.yml) and publish to PyPI. Mirrors pyMSTM's publish.yml
6
+ # (github.com/arunoruto/pyMSTM) -- see that project for the fuller
7
+ # rationale behind this design.
8
+ #
9
+ # NOTE: the filename `publish.yml` is load-bearing -- the PyPI trusted
10
+ # publisher for `pyfastmm` is configured against this exact workflow
11
+ # file. The job that calls pypa/gh-action-pypi-publish must stay in here.
12
+
13
+ on:
14
+ workflow_dispatch:
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ jobs:
20
+ test:
21
+ uses: ./.github/workflows/test.yml
22
+
23
+ release:
24
+ name: Version, tag, and create the GitHub Release
25
+ runs-on: ubuntu-latest
26
+ needs: test
27
+ concurrency:
28
+ group: ${{ github.workflow }}-release-${{ github.ref_name }}
29
+ cancel-in-progress: false
30
+ permissions:
31
+ contents: write
32
+ outputs:
33
+ released: ${{ steps.release.outputs.released }}
34
+ tag: ${{ steps.release.outputs.tag }}
35
+ steps:
36
+ - name: Setup | Checkout Repository on Release Branch
37
+ uses: actions/checkout@v4
38
+ with:
39
+ ref: ${{ github.ref_name }}
40
+ fetch-depth: 0
41
+ # No submodules: this job only versions/tags/releases, it never
42
+ # builds the extension. Wheels build in wheels.yml (with
43
+ # submodules), from the tag this job creates.
44
+
45
+ - name: Setup | Force release branch to be at workflow sha
46
+ run: git reset --hard ${{ github.sha }}
47
+
48
+ - name: Action | Semantic Version Release
49
+ # Computes the next version from Conventional Commits, bumps
50
+ # pyproject.toml + __init__.py (per [tool.semantic_release]),
51
+ # commits, tags, pushes, and creates the GitHub Release.
52
+ id: release
53
+ uses: python-semantic-release/python-semantic-release@v10.6.1
54
+ with:
55
+ github_token: ${{ secrets.GITHUB_TOKEN }}
56
+ git_committer_name: "github-actions"
57
+ git_committer_email: "actions@users.noreply.github.com"
58
+
59
+ wheels:
60
+ # Build the wheels + sdist for the tag release just created. Reuses
61
+ # the exact same build that's available on demand via wheels.yml.
62
+ needs: release
63
+ if: needs.release.outputs.released == 'true'
64
+ # GitHub validates a called reusable workflow's permission needs
65
+ # *statically*, across all its jobs, regardless of which actually run
66
+ # at runtime -- wheels.yml's check_comment job (skipped here, this is
67
+ # a workflow_call, not issue_comment) still declares issues:write/
68
+ # pull-requests:read, which this workflow's top-level permissions:
69
+ # contents: read alone doesn't cover. Without this override the whole
70
+ # run fails at dispatch time with "startup_failure", before any job
71
+ # even starts -- confirmed via a real failed dispatch.
72
+ permissions:
73
+ contents: read
74
+ issues: write
75
+ pull-requests: read
76
+ uses: ./.github/workflows/wheels.yml
77
+ with:
78
+ ref: ${{ needs.release.outputs.tag }}
79
+
80
+ publish:
81
+ name: Publish to PyPI and attach artifacts to the GitHub Release
82
+ runs-on: ubuntu-latest
83
+ needs:
84
+ - release
85
+ - wheels
86
+ if: needs.release.outputs.released == 'true'
87
+ environment:
88
+ name: pypi
89
+ url: https://pypi.org/p/pyfastmm
90
+ permissions:
91
+ id-token: write # PyPI trusted publishing (OIDC)
92
+ contents: write # attach assets to the GitHub Release
93
+ steps:
94
+ - name: Download | All build artifacts (wheels + sdist)
95
+ uses: actions/download-artifact@v4
96
+ with:
97
+ pattern: cibw-*
98
+ path: dist
99
+ merge-multiple: true
100
+
101
+ - name: Publish | PyPI (trusted publishing, no token)
102
+ uses: pypa/gh-action-pypi-publish@release/v1
103
+
104
+ - name: Publish | Attach wheels + sdist to the GitHub Release
105
+ env:
106
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
107
+ run: gh release upload ${{ needs.release.outputs.tag }} dist/* --repo ${{ github.repository }} --clobber
@@ -0,0 +1,55 @@
1
+ name: Testing
2
+ on:
3
+ workflow_call:
4
+ workflow_dispatch:
5
+ pull_request:
6
+ push:
7
+ branches: [main]
8
+ jobs:
9
+ unittest:
10
+ name: PyTest
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ with:
15
+ submodules: recursive
16
+ - name: Install build dependencies
17
+ # gfortran/lapack/blas: needed for `uv sync` to build the f2py
18
+ # extension (meson-python drives numpy.f2py -c against
19
+ # external/fastmm2/, see meson.build). cmake/libhdf5-dev: only
20
+ # for the standalone CLI reference binary (make cli), which
21
+ # keeps building the *unmodified* upstream sources including
22
+ # io.f90/HDF5, unlike the Python extension itself.
23
+ run: |
24
+ sudo apt-get update
25
+ sudo apt-get install -y gfortran liblapack-dev libblas-dev cmake libhdf5-dev
26
+ - name: Install uv
27
+ id: setup-python
28
+ uses: astral-sh/setup-uv@v4
29
+ with:
30
+ enable-cache: true
31
+ - name: Install dependencies (builds the f2py extension)
32
+ run: uv sync --extra dev
33
+ - name: Cache | FaSTMM2 CLI reference binary
34
+ id: cache-cli
35
+ uses: actions/cache@v4
36
+ with:
37
+ path: build/cli/FaSTMM2
38
+ # external/fastmm2 is a git submodule pinned to a fixed commit
39
+ # in .gitmodules -- it essentially never changes between runs,
40
+ # so hashing its checked-out content (plus the Makefile that
41
+ # drives the CMake build) is a reliable "did the CLI's own
42
+ # inputs change" key, letting most runs skip rebuilding it
43
+ # entirely (mirrors pyMSTM's identical CLI-caching setup).
44
+ key: ${{ runner.os }}-fastmm2-cli-${{ hashFiles('external/fastmm2/src/**', 'Makefile') }}
45
+ - name: Build the standalone FaSTMM2 CLI reference binary
46
+ # test_compatibility.py skips itself if this isn't present -- but
47
+ # we want that cross-check to actually run in CI, not silently
48
+ # skip. Skipped entirely on a cache hit above -- `make`'s own
49
+ # mtime-based staleness check isn't reliable here since a fresh
50
+ # checkout + cache restore don't produce trustworthy relative
51
+ # timestamps between sources and the cached binary.
52
+ if: steps.cache-cli.outputs.cache-hit != 'true'
53
+ run: make cli
54
+ - name: Test with pytest
55
+ run: uv run pytest tests/ -v
@@ -0,0 +1,171 @@
1
+ name: Wheels
2
+
3
+ # Single source of truth for *how* pyfastmm's wheels + sdist are built.
4
+ # Mirrors pyMSTM's wheels.yml (github.com/arunoruto/pyMSTM) -- see that
5
+ # project for the fuller rationale behind this design.
6
+ #
7
+ # Deliberately not triggered automatically at all (no PR push, no push to
8
+ # main) -- cibuildwheel across cp311-cp314 is slow enough, and this
9
+ # project small/quiet enough, that it isn't worth building on every
10
+ # commit or every merge. Runs on demand instead:
11
+ # - workflow_dispatch: Actions tab, or `gh workflow run wheels.yml --ref
12
+ # <branch>` -- run manually whenever you actually want to validate a
13
+ # build (e.g. right before merging a PR you're unsure about).
14
+ # - Commenting `/build-wheels` on a PR.
15
+ # - Called by publish.yml (workflow_call) with the freshly-created tag
16
+ # at actual release time.
17
+ #
18
+ # Tradeoff worth knowing: publish.yml's `release` job tags before this
19
+ # workflow ever builds anything (tag-first), so if a release's build
20
+ # fails here, the tag/GitHub Release already exist -- a phantom release
21
+ # with no wheels, needing manual cleanup (`gh release delete <tag>
22
+ # --cleanup-tag`). There's no automatic pre-release validation to catch
23
+ # this ahead of time; the mitigation is manual -- run workflow_dispatch
24
+ # or `/build-wheels` on a PR you're unsure about before merging/releasing.
25
+ #
26
+ # All cibuildwheel configuration lives in pyproject.toml's
27
+ # [tool.cibuildwheel] -- deliberately not here as CIBW_* env vars, so this
28
+ # stays a bare `uses:` and the exact same build is reproducible locally
29
+ # with the `cibuildwheel` CLI.
30
+
31
+ on:
32
+ workflow_call:
33
+ inputs:
34
+ ref:
35
+ description: "Git ref (tag) to build. Empty builds the triggering commit."
36
+ type: string
37
+ required: false
38
+ default: ""
39
+ workflow_dispatch:
40
+ inputs:
41
+ ref:
42
+ description: "Ref to build (defaults to whatever branch this is run against)."
43
+ type: string
44
+ required: false
45
+ default: ""
46
+ issue_comment:
47
+ types: [created]
48
+
49
+ permissions:
50
+ contents: read
51
+
52
+ jobs:
53
+ # Only relevant for the issue_comment trigger: gates /build-wheels on
54
+ # the commenter actually having write access (issue_comment fires for
55
+ # *any* comment from *anyone* on a public repo -- without this, anyone
56
+ # could burn CI minutes triggering the wheel matrix on an arbitrary PR),
57
+ # and resolves the PR's head SHA (issue_comment's payload doesn't
58
+ # include PR ref info directly, only the issue/PR number).
59
+ check_comment:
60
+ if: >
61
+ github.event_name == 'issue_comment' &&
62
+ github.event.issue.pull_request != null &&
63
+ contains(github.event.comment.body, '/build-wheels')
64
+ runs-on: ubuntu-latest
65
+ permissions:
66
+ contents: read
67
+ pull-requests: read # to resolve the PR's head SHA
68
+ issues: write # to react to the triggering comment (PR comments are "issues" API-wise)
69
+ outputs:
70
+ authorized: ${{ steps.check.outputs.authorized }}
71
+ sha: ${{ steps.pr.outputs.sha }}
72
+ steps:
73
+ - name: Check commenter has write access
74
+ id: check
75
+ uses: actions/github-script@v7
76
+ with:
77
+ script: |
78
+ const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
79
+ owner: context.repo.owner,
80
+ repo: context.repo.repo,
81
+ username: context.payload.comment.user.login,
82
+ });
83
+ const authorized = ["admin", "write"].includes(data.permission);
84
+ core.setOutput("authorized", authorized);
85
+ await github.rest.reactions.createForIssueComment({
86
+ owner: context.repo.owner,
87
+ repo: context.repo.repo,
88
+ comment_id: context.payload.comment.id,
89
+ content: authorized ? "rocket" : "-1",
90
+ });
91
+ if (!authorized) {
92
+ core.setFailed(`@${context.payload.comment.user.login} does not have write access -- not triggering the wheel build.`);
93
+ }
94
+
95
+ - name: Resolve PR head SHA
96
+ id: pr
97
+ if: steps.check.outputs.authorized == 'true'
98
+ uses: actions/github-script@v7
99
+ with:
100
+ script: |
101
+ const { data } = await github.rest.pulls.get({
102
+ owner: context.repo.owner,
103
+ repo: context.repo.repo,
104
+ pull_number: context.issue.number,
105
+ });
106
+ core.setOutput("sha", data.head.sha);
107
+
108
+ build_wheels:
109
+ name: Wheels on ${{ matrix.os }}
110
+ needs: [check_comment]
111
+ # always(): check_comment is skipped entirely for every trigger except
112
+ # issue_comment, and a skipped need must not block this job -- but a
113
+ # *failed* (unauthorized) check_comment must.
114
+ if: >
115
+ always() &&
116
+ needs.check_comment.result != 'failure' &&
117
+ (github.event_name != 'issue_comment' || needs.check_comment.outputs.authorized == 'true')
118
+ runs-on: ${{ matrix.os }}
119
+ strategy:
120
+ fail-fast: false
121
+ matrix:
122
+ # A matrix of one for now -- kept a matrix so macOS/Windows are a
123
+ # one-line add later (their cibuildwheel settings are already
124
+ # staged in pyproject.toml's [tool.cibuildwheel.macos]).
125
+ os: [ubuntu-latest]
126
+ steps:
127
+ - uses: actions/checkout@v4
128
+ with:
129
+ # check_comment's resolved SHA on a /build-wheels comment;
130
+ # inputs.ref on workflow_call/workflow_dispatch (empty checks
131
+ # out whatever ref the dispatch/call itself targeted).
132
+ ref: ${{ needs.check_comment.outputs.sha || inputs.ref }}
133
+ submodules: recursive
134
+
135
+ - uses: pypa/cibuildwheel@v4.1.0
136
+
137
+ - uses: actions/upload-artifact@v4
138
+ with:
139
+ name: cibw-wheels-${{ matrix.os }}
140
+ path: ./wheelhouse/*.whl
141
+
142
+ build_sdist:
143
+ name: sdist
144
+ needs: [check_comment]
145
+ if: >
146
+ always() &&
147
+ needs.check_comment.result != 'failure' &&
148
+ (github.event_name != 'issue_comment' || needs.check_comment.outputs.authorized == 'true')
149
+ runs-on: ubuntu-latest
150
+ steps:
151
+ - uses: actions/checkout@v4
152
+ with:
153
+ ref: ${{ needs.check_comment.outputs.sha || inputs.ref }}
154
+ submodules: recursive
155
+
156
+ - name: Install gfortran
157
+ # meson-python's sdist build runs `meson setup`, which requires a
158
+ # Fortran compiler to be found -- even though producing the sdist
159
+ # (a source tarball) compiles nothing itself. LAPACK/BLAS aren't
160
+ # needed here: meson.build never declares them as meson
161
+ # dependencies, only tools/build_f2py_ext.py links them directly
162
+ # at actual compile time.
163
+ run: sudo apt-get update && sudo apt-get install -y gfortran
164
+
165
+ - name: Build sdist
166
+ run: pipx run build --sdist
167
+
168
+ - uses: actions/upload-artifact@v4
169
+ with:
170
+ name: cibw-sdist
171
+ path: ./dist/*.tar.gz
@@ -0,0 +1,303 @@
1
+ build/
2
+
3
+ ## Devenv
4
+ .devenv*
5
+ devenv.local.nix
6
+ devenv.local.yaml
7
+
8
+ # direnv
9
+ .direnv
10
+
11
+ # pre-commit
12
+ .pre-commit-config.yaml
13
+
14
+ ## Python
15
+ # Byte-compiled / optimized / DLL files
16
+ __pycache__/
17
+ *.py[codz]
18
+ *$py.class
19
+
20
+ # C extensions
21
+ *.so
22
+
23
+ # Distribution / packaging
24
+ .Python
25
+ build/
26
+ develop-eggs/
27
+ dist/
28
+ downloads/
29
+ eggs/
30
+ .eggs/
31
+ lib/
32
+ lib64/
33
+ parts/
34
+ sdist/
35
+ var/
36
+ wheels/
37
+ share/python-wheels/
38
+ *.egg-info/
39
+ .installed.cfg
40
+ *.egg
41
+ MANIFEST
42
+
43
+ # PyInstaller
44
+ # Usually these files are written by a python script from a template
45
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
46
+ *.manifest
47
+ *.spec
48
+
49
+ # Installer logs
50
+ pip-log.txt
51
+ pip-delete-this-directory.txt
52
+
53
+ # Unit test / coverage reports
54
+ htmlcov/
55
+ .tox/
56
+ .nox/
57
+ .coverage
58
+ .coverage.*
59
+ .cache
60
+ nosetests.xml
61
+ coverage.xml
62
+ *.cover
63
+ *.py.cover
64
+ *.lcov
65
+ .hypothesis/
66
+ .pytest_cache/
67
+ cover/
68
+
69
+ # Translations
70
+ *.mo
71
+ *.pot
72
+
73
+ # Django stuff:
74
+ *.log
75
+ local_settings.py
76
+ db.sqlite3
77
+ db.sqlite3-journal
78
+
79
+ # Flask stuff:
80
+ instance/
81
+ .webassets-cache
82
+
83
+ # Scrapy stuff:
84
+ .scrapy
85
+
86
+ # Sphinx documentation
87
+ docs/_build/
88
+
89
+ # PyBuilder
90
+ .pybuilder/
91
+ target/
92
+
93
+ # Jupyter Notebook
94
+ .ipynb_checkpoints
95
+
96
+ # IPython
97
+ profile_default/
98
+ ipython_config.py
99
+
100
+ # pyenv
101
+ # For a library or package, you might want to ignore these files since the code is
102
+ # intended to run in multiple environments; otherwise, check them in:
103
+ # .python-version
104
+
105
+ # pipenv
106
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
107
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
108
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
109
+ # install all needed dependencies.
110
+ # Pipfile.lock
111
+
112
+ # UV
113
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
114
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
115
+ # commonly ignored for libraries.
116
+ # uv.lock
117
+
118
+ # poetry
119
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
120
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
121
+ # commonly ignored for libraries.
122
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
123
+ # poetry.lock
124
+ # poetry.toml
125
+
126
+ # pdm
127
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
128
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
129
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
130
+ # pdm.lock
131
+ # pdm.toml
132
+ .pdm-python
133
+ .pdm-build/
134
+
135
+ # pixi
136
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
137
+ # pixi.lock
138
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
139
+ # in the .venv directory. It is recommended not to include this directory in version control.
140
+ .pixi/*
141
+ !.pixi/config.toml
142
+
143
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
144
+ __pypackages__/
145
+
146
+ # Celery stuff
147
+ celerybeat-schedule*
148
+ celerybeat.pid
149
+
150
+ # Redis
151
+ *.rdb
152
+ *.aof
153
+ *.pid
154
+
155
+ # RabbitMQ
156
+ mnesia/
157
+ rabbitmq/
158
+ rabbitmq-data/
159
+
160
+ # ActiveMQ
161
+ activemq-data/
162
+
163
+ # SageMath parsed files
164
+ *.sage.py
165
+
166
+ # Environments
167
+ .env
168
+ .envrc
169
+ .venv
170
+ env/
171
+ venv/
172
+ ENV/
173
+ env.bak/
174
+ venv.bak/
175
+
176
+ # Spyder project settings
177
+ .spyderproject
178
+ .spyproject
179
+
180
+ # Rope project settings
181
+ .ropeproject
182
+
183
+ # mkdocs documentation
184
+ /site
185
+
186
+ # mypy
187
+ .mypy_cache/
188
+ .dmypy.json
189
+ dmypy.json
190
+
191
+ # Pyre type checker
192
+ .pyre/
193
+
194
+ # pytype static type analyzer
195
+ .pytype/
196
+
197
+ # Cython debug symbols
198
+ cython_debug/
199
+
200
+ # PyCharm
201
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
202
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
203
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
204
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
205
+ # .idea/
206
+
207
+ # Abstra
208
+ # Abstra is an AI-powered process automation framework.
209
+ # Ignore directories containing user credentials, local state, and settings.
210
+ # Learn more at https://abstra.io/docs
211
+ .abstra/
212
+
213
+ # Visual Studio Code
214
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
215
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
216
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
217
+ # you could uncomment the following to ignore the entire vscode folder
218
+ # .vscode/
219
+ # Temporary file for partial code execution
220
+ tempCodeRunnerFile.py
221
+
222
+ # Ruff stuff:
223
+ .ruff_cache/
224
+
225
+ # PyPI configuration file
226
+ .pypirc
227
+
228
+ # Marimo
229
+ marimo/_static/
230
+ marimo/_lsp/
231
+ __marimo__/
232
+
233
+ # Streamlit
234
+ .streamlit/secrets.toml
235
+
236
+ ## C++
237
+ # Prerequisites
238
+ *.d
239
+
240
+ # Compiled Object files
241
+ *.slo
242
+ *.lo
243
+ *.o
244
+ *.obj
245
+
246
+ # Precompiled Headers
247
+ *.gch
248
+ *.pch
249
+
250
+ # Linker files
251
+ *.ilk
252
+
253
+ # Debugger Files
254
+ *.pdb
255
+
256
+ # Compiled Dynamic libraries
257
+ *.so
258
+ *.dylib
259
+ *.dll
260
+ *.so.*
261
+
262
+ # Fortran module files
263
+ *.mod
264
+ *.smod
265
+
266
+ # Compiled Static libraries
267
+ *.lai
268
+ *.la
269
+ *.a
270
+ *.lib
271
+
272
+ # Executables
273
+ *.exe
274
+ *.out
275
+ *.app
276
+
277
+ # Build directories
278
+ build/
279
+ Build/
280
+ build-*/
281
+
282
+ # CMake generated files
283
+ CMakeFiles/
284
+ CMakeCache.txt
285
+ cmake_install.cmake
286
+ install_manifest.txt
287
+ compile_commands.json
288
+
289
+ # Temporary files
290
+ *.tmp
291
+ *.log
292
+ *.bak
293
+ *.swp
294
+
295
+ # vcpkg
296
+ vcpkg_installed/
297
+
298
+ # debug information files
299
+ *.dwo
300
+
301
+ # test output & cache
302
+ Testing/
303
+ .cache/
@@ -0,0 +1,3 @@
1
+ [submodule "external/fastmm2"]
2
+ path = external/fastmm2
3
+ url = https://bitbucket.org/planetarysystemresearch/fastmm2/
@@ -0,0 +1 @@
1
+ 3.14
@@ -0,0 +1,7 @@
1
+ # CHANGELOG
2
+
3
+ <!-- version list -->
4
+
5
+ ## v1.0.0 (2026-07-14)
6
+
7
+ - Initial Release