From 75ff4e33de80df03386ecb049809e77f3062d64d Mon Sep 17 00:00:00 2001 From: hholb Date: Wed, 18 Mar 2026 11:44:23 -0600 Subject: [PATCH 1/4] create new zensical site --- .github/workflows/docs.yml | 28 ++++ .gitignore | 3 + docs/index.md | 166 ++++++++++++++++++++ docs/markdown.md | 98 ++++++++++++ pyproject.toml | 1 + uv.lock | 64 +++++++- zensical.toml | 305 +++++++++++++++++++++++++++++++++++++ 7 files changed, 664 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/docs.yml create mode 100644 docs/index.md create mode 100644 docs/markdown.md create mode 100644 zensical.toml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..0262eb8 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,28 @@ +name: Documentation +on: + push: + branches: + - main +permissions: + contents: read + pages: write + id-token: write +jobs: + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - uses: actions/configure-pages@v5 + - uses: actions/checkout@v5 + - uses: actions/setup-python@v5 + with: + python-version: 3.x + - run: pip install zensical + - run: zensical build --clean + - uses: actions/upload-pages-artifact@v4 + with: + path: site + - uses: actions/deploy-pages@v4 + id: deployment diff --git a/.gitignore b/.gitignore index ee6c946..0d3c304 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,6 @@ Thumbs.db # Sockets (shouldn't be committed but just in case) /tmp/ipi_* + +# zensical +site/ diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..3b76a8a --- /dev/null +++ b/docs/index.md @@ -0,0 +1,166 @@ +--- +icon: lucide/rocket +--- + +# Get started + +For full documentation visit [zensical.org](https://zensical.org/docs/). + +## Commands + +* [`zensical new`][new] - Create a new project +* [`zensical serve`][serve] - Start local web server +* [`zensical build`][build] - Build your site + + [new]: https://zensical.org/docs/usage/new/ + [serve]: https://zensical.org/docs/usage/preview/ + [build]: https://zensical.org/docs/usage/build/ + +## Examples + +### Admonitions + +> Go to [documentation](https://zensical.org/docs/authoring/admonitions/) + +!!! note + + This is a **note** admonition. Use it to provide helpful information. + +!!! warning + + This is a **warning** admonition. Be careful! + +### Details + +> Go to [documentation](https://zensical.org/docs/authoring/admonitions/#collapsible-blocks) + +??? info "Click to expand for more info" + + This content is hidden until you click to expand it. + Great for FAQs or long explanations. + +## Code Blocks + +> Go to [documentation](https://zensical.org/docs/authoring/code-blocks/) + +``` python hl_lines="2" title="Code blocks" +def greet(name): + print(f"Hello, {name}!") # (1)! + +greet("Python") +``` + +1. > Go to [documentation](https://zensical.org/docs/authoring/code-blocks/#code-annotations) + + Code annotations allow to attach notes to lines of code. + +Code can also be highlighted inline: `#!python print("Hello, Python!")`. + +## Content tabs + +> Go to [documentation](https://zensical.org/docs/authoring/content-tabs/) + +=== "Python" + + ``` python + print("Hello from Python!") + ``` + +=== "Rust" + + ``` rs + println!("Hello from Rust!"); + ``` + +## Diagrams + +> Go to [documentation](https://zensical.org/docs/authoring/diagrams/) + +``` mermaid +graph LR + A[Start] --> B{Error?}; + B -->|Yes| C[Hmm...]; + C --> D[Debug]; + D --> B; + B ---->|No| E[Yay!]; +``` + +## Footnotes + +> Go to [documentation](https://zensical.org/docs/authoring/footnotes/) + +Here's a sentence with a footnote.[^1] + +Hover it, to see a tooltip. + +[^1]: This is the footnote. + + +## Formatting + +> Go to [documentation](https://zensical.org/docs/authoring/formatting/) + +- ==This was marked (highlight)== +- ^^This was inserted (underline)^^ +- ~~This was deleted (strikethrough)~~ +- H~2~O +- A^T^A +- ++ctrl+alt+del++ + +## Icons, Emojis + +> Go to [documentation](https://zensical.org/docs/authoring/icons-emojis/) + +* :sparkles: `:sparkles:` +* :rocket: `:rocket:` +* :tada: `:tada:` +* :memo: `:memo:` +* :eyes: `:eyes:` + +## Maths + +> Go to [documentation](https://zensical.org/docs/authoring/math/) + +$$ +\cos x=\sum_{k=0}^{\infty}\frac{(-1)^k}{(2k)!}x^{2k} +$$ + +!!! warning "Needs configuration" + Note that MathJax is included via a `script` tag on this page and is not + configured in the generated default configuration to avoid including it + in a pages that do not need it. See the documentation for details on how + to configure it on all your pages if they are more Maths-heavy than these + simple starter pages. + + + + +## Task Lists + +> Go to [documentation](https://zensical.org/docs/authoring/lists/#using-task-lists) + +* [x] Install Zensical +* [x] Configure `zensical.toml` +* [x] Write amazing documentation +* [ ] Deploy anywhere + +## Tooltips + +> Go to [documentation](https://zensical.org/docs/authoring/tooltips/) + +[Hover me][example] + + [example]: https://example.com "I'm a tooltip!" diff --git a/docs/markdown.md b/docs/markdown.md new file mode 100644 index 0000000..7ea6d1e --- /dev/null +++ b/docs/markdown.md @@ -0,0 +1,98 @@ +--- +icon: simple/markdown +--- + +# Markdown in 5min + +## Headers +``` +# H1 Header +## H2 Header +### H3 Header +#### H4 Header +##### H5 Header +###### H6 Header +``` + +## Text formatting +``` +**bold text** +*italic text* +***bold and italic*** +~~strikethrough~~ +`inline code` +``` + +## Links and images +``` +[Link text](https://example.com) +[Link with title](https://example.com "Hover title") +![Alt text](image.jpg) +![Image with title](image.jpg "Image title") +``` + +## Lists +``` +Unordered: +- Item 1 +- Item 2 + - Nested item + +Ordered: +1. First item +2. Second item +3. Third item +``` + +## Blockquotes +``` +> This is a blockquote +> Multiple lines +>> Nested quote +``` + +## Code blocks +```` +```javascript +function hello() { + console.log("Hello, world!"); +} +``` +```` + +## Tables +``` +| Header 1 | Header 2 | Header 3 | +|----------|----------|----------| +| Row 1 | Data | Data | +| Row 2 | Data | Data | +``` + +## Horizontal rule +``` +--- +or +*** +or +___ +``` + +## Task lists +``` +- [x] Completed task +- [ ] Incomplete task +- [ ] Another task +``` + +## Escaping characters +``` +Use backslash to escape: \* \_ \# \` +``` + +## Line breaks +``` +End a line with two spaces +to create a line break. + +Or use a blank line for a new paragraph. +``` \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 6db6e0b..8c4c298 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ dependencies = [ dev = [ "pytest>=7.0", "ruff>=0.1", + "zensical>=0.0.27", ] modal = [ "modal>=0.56", diff --git a/uv.lock b/uv.lock index 691214c..91a2b2f 100644 --- a/uv.lock +++ b/uv.lock @@ -445,6 +445,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, ] +[[package]] +name = "deepmerge" +version = "2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a8/3a/b0ba594708f1ad0bc735884b3ad854d3ca3bdc1d741e56e40bbda6263499/deepmerge-2.0.tar.gz", hash = "sha256:5c3d86081fbebd04dd5de03626a0607b809a98fb6ccba5770b62466fe940ff20", size = 19890, upload-time = "2024-08-30T05:31:50.308Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/82/e5d2c1c67d19841e9edc74954c827444ae826978499bde3dfc1d007c8c11/deepmerge-2.0-py3-none-any.whl", hash = "sha256:6de9ce507115cff0bed95ff0ce9ecc31088ef50cbdf09bc90a09349a318b3d00", size = 13475, upload-time = "2024-08-30T05:31:48.659Z" }, +] + [[package]] name = "e3nn" version = "0.4.4" @@ -1016,6 +1025,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/53/7d7b1de354a43e11cb19b370f81833f078f931aff4555b24e869013eea1a/mace_torch-0.3.14-py3-none-any.whl", hash = "sha256:9a7a00a79b3fa3448a13961e2a4af616ff10466fa193aeb4579dc83be9da1b00", size = 237087, upload-time = "2025-08-06T17:30:11.377Z" }, ] +[[package]] +name = "markdown" +version = "3.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/f4/69fa6ed85ae003c2378ffa8f6d2e3234662abd02c10d216c0ba96081a238/markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950", size = 368805, upload-time = "2026-02-09T14:57:26.942Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" }, +] + [[package]] name = "markdown-it-py" version = "4.0.0" @@ -2148,6 +2166,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] +[[package]] +name = "pymdown-extensions" +version = "10.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ba/63/06673d1eb6d8f83c0ea1f677d770e12565fb516928b4109c9e2055656a9e/pymdown_extensions-10.21.tar.gz", hash = "sha256:39f4a020f40773f6b2ff31d2cd2546c2c04d0a6498c31d9c688d2be07e1767d5", size = 853363, upload-time = "2026-02-15T20:44:06.748Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/2c/5b079febdc65e1c3fb2729bf958d18b45be7113828528e8a0b5850dd819a/pymdown_extensions-10.21-py3-none-any.whl", hash = "sha256:91b879f9f864d49794c2d9534372b10150e6141096c3908a455e45ca72ad9d3f", size = 268877, upload-time = "2026-02-15T20:44:05.464Z" }, +] + [[package]] name = "pyparsing" version = "3.3.1" @@ -2281,7 +2312,7 @@ wheels = [ [[package]] name = "rootstock" -version = "0.6.1" +version = "0.7.0" source = { editable = "." } dependencies = [ { name = "ase" }, @@ -2295,6 +2326,7 @@ dependencies = [ dev = [ { name = "pytest" }, { name = "ruff" }, + { name = "zensical" }, ] mace = [ { name = "mace-torch" }, @@ -2315,6 +2347,7 @@ requires-dist = [ { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.1" }, { name = "tomli", marker = "python_full_version < '3.11'", specifier = ">=2.0" }, { name = "torch", marker = "extra == 'mace'", specifier = ">=2.0" }, + { name = "zensical", marker = "extra == 'dev'", specifier = ">=0.0.27" }, ] provides-extras = ["dev", "modal", "mace"] @@ -3004,3 +3037,32 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/48/b7/503c98092fb3b344a179579f55814b613c1fbb1c23b3ec14a7b008a66a6e/yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1", size = 85171, upload-time = "2025-10-06T14:12:16.935Z" }, { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, ] + +[[package]] +name = "zensical" +version = "0.0.27" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "deepmerge" }, + { name = "markdown" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "pyyaml" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8f/83/969152d927b522a0fed1f20b1730575d86b920ce51530b669d9fad4537de/zensical-0.0.27.tar.gz", hash = "sha256:6d8d74aba4a9f9505e6ba1c43d4c828ba4ff7bb1ff9b005e5174c5b92cf23419", size = 3841776, upload-time = "2026-03-13T17:56:14.494Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/fe/0335f1a521eb6c0ab96028bf67148390eb1d5c742c23e6a4b0f8381508bd/zensical-0.0.27-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:d51ebf4b038f3eea99fd337119b99d92ad92bbe674372d5262e6dbbabbe4e9b5", size = 12262017, upload-time = "2026-03-13T17:55:36.403Z" }, + { url = "https://files.pythonhosted.org/packages/02/cb/ac24334fc7959b49496c97cb9d2bed82a8db8b84eafaf68189048e7fe69a/zensical-0.0.27-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:a627cd4599cf2c5a5a5205f0510667227d1fe4579b6f7445adba2d84bab9fbc8", size = 12147361, upload-time = "2026-03-13T17:55:39.736Z" }, + { url = "https://files.pythonhosted.org/packages/a2/0f/31c981f61006fdaf0460d15bde1248a045178d67307bad61a4588414855d/zensical-0.0.27-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99cbc493022f8749504ef10c71772d360b705b4e2fd1511421393157d07bdccf", size = 12505771, upload-time = "2026-03-13T17:55:42.993Z" }, + { url = "https://files.pythonhosted.org/packages/30/1e/f6842c94ec89e5e9184f407dbbab2a497b444b28d4fb5b8df631894be896/zensical-0.0.27-cp310-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ecc20a85e8a23ad9ab809b2f268111321be7b2e214021b3b00f138936a87a434", size = 12455689, upload-time = "2026-03-13T17:55:46.055Z" }, + { url = "https://files.pythonhosted.org/packages/4c/ad/866c3336381cca7528e792469958fbe2e65b9206a2657bef3dd8ed4ac88b/zensical-0.0.27-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da11e0f0861dbd7d3b5e6fe1e3a53b361b2181c53f3abe9fb4cdf2ed0cea47bf", size = 12791263, upload-time = "2026-03-13T17:55:49.193Z" }, + { url = "https://files.pythonhosted.org/packages/e5/df/fca5ed6bebdb61aa656dfa65cce4b4d03324a79c75857728230872fbdf7c/zensical-0.0.27-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e11d220181477040a4b22bf2b8678d5b0c878e7aae194fad4133561cb976d69", size = 12549796, upload-time = "2026-03-13T17:55:52.55Z" }, + { url = "https://files.pythonhosted.org/packages/4a/e2/43398b5ec64ed78204a5a5929a3990769fc0f6a3094a30395882bda1399a/zensical-0.0.27-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:06b9e308aec8c5db1cd623e2e98e1b25c3f5cab6b25fcc9bac1e16c0c2b93837", size = 12683568, upload-time = "2026-03-13T17:55:56.151Z" }, + { url = "https://files.pythonhosted.org/packages/b3/3c/5c98f9964c7e30735aacd22a389dacec12bcc5bc8162c58e76b76d20db6e/zensical-0.0.27-cp310-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:682085155126965b091cb9f915cd2e4297383ac500122fd4b632cf4511733eb2", size = 12725214, upload-time = "2026-03-13T17:55:59.286Z" }, + { url = "https://files.pythonhosted.org/packages/50/0f/ebaa159cac6d64b53bf7134420c2b43399acc7096cb79795be4fb10768fc/zensical-0.0.27-cp310-abi3-musllinux_1_2_i686.whl", hash = "sha256:b367c285157c8e1099ae9e2b36564e07d3124bf891e96194a093bc836f3058d2", size = 12860416, upload-time = "2026-03-13T17:56:02.456Z" }, + { url = "https://files.pythonhosted.org/packages/88/06/d82bfccbf5a1f43256dbc4d1984e398035a65f84f7c1e48b69ba15ea7281/zensical-0.0.27-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:847c881209e65e1db1291c59a9db77966ac50f7c66bf9a733c3c7832144dbfca", size = 12819533, upload-time = "2026-03-13T17:56:05.487Z" }, + { url = "https://files.pythonhosted.org/packages/4d/1f/d25e421d91f063a9404c59dd032f65a67c7c700e9f5f40436ab98e533482/zensical-0.0.27-cp310-abi3-win32.whl", hash = "sha256:f31ec13c700794be3f9c0b7d90f09a7d23575a3a27c464994b9bb441a22d880b", size = 11862822, upload-time = "2026-03-13T17:56:08.933Z" }, + { url = "https://files.pythonhosted.org/packages/5a/b5/5b86d126fcc42b96c5dbecde5074d6ea766a1a884e3b25b3524843c5e6a5/zensical-0.0.27-cp310-abi3-win_amd64.whl", hash = "sha256:9d3b1fca7ea99a7b2a8db272dd7f7839587c4ebf4f56b84ff01c97b3893ec9f8", size = 12059658, upload-time = "2026-03-13T17:56:11.859Z" }, +] diff --git a/zensical.toml b/zensical.toml new file mode 100644 index 0000000..1ff7ad2 --- /dev/null +++ b/zensical.toml @@ -0,0 +1,305 @@ +# ============================================================================ +# +# The configuration produced by default is meant to highlight the features +# that Zensical provides and to serve as a starting point for your own +# projects. +# +# ============================================================================ + +[project] + +# The site_name is shown in the page header and the browser window title +# +# Read more: https://zensical.org/docs/setup/basics/#site_name +site_name = "Documentation" + +# The site_description is included in the HTML head and should contain a +# meaningful description of the site content for use by search engines. +# +# Read more: https://zensical.org/docs/setup/basics/#site_description +site_description = "A new project generated from the default template project." + +# The site_author attribute. This is used in the HTML head element. +# +# Read more: https://zensical.org/docs/setup/basics/#site_author +site_author = "" + +# The site_url is the canonical URL for your site. When building online +# documentation you should set this. +# Read more: https://zensical.org/docs/setup/basics/#site_url +#site_url = "https://www.example.com/" + +# The copyright notice appears in the page footer and can contain an HTML +# fragment. +# +# Read more: https://zensical.org/docs/setup/basics/#copyright +copyright = """ +Copyright © 2026 The authors +""" + +# Zensical supports both implicit navigation and explicitly defined navigation. +# If you decide not to define a navigation here then Zensical will simply +# derive the navigation structure from the directory structure of your +# "docs_dir". The definition below demonstrates how a navigation structure +# can be defined using TOML syntax. +# +# Read more: https://zensical.org/docs/setup/navigation/ +# nav = [ +# { "Get started" = "index.md" }, +# { "Markdown in 5min" = "markdown.md" }, +# ] + +# With the "extra_css" option you can add your own CSS styling to customize +# your Zensical project according to your needs. You can add any number of +# CSS files. +# +# The path provided should be relative to the "docs_dir". +# +# Read more: https://zensical.org/docs/customization/#additional-css +# +#extra_css = ["stylesheets/extra.css"] + +# With the `extra_javascript` option you can add your own JavaScript to your +# project to customize the behavior according to your needs. +# +# The path provided should be relative to the "docs_dir". +# +# Read more: https://zensical.org/docs/customization/#additional-javascript +#extra_javascript = ["javascripts/extra.js"] + +# ---------------------------------------------------------------------------- +# Section for configuring theme options +# ---------------------------------------------------------------------------- +[project.theme] + +# change this to "classic" to use the traditional Material for MkDocs look. +#variant = "classic" + +# Zensical allows you to override specific blocks, partials, or whole +# templates as well as to define your own templates. To do this, uncomment +# the custom_dir setting below and set it to a directory in which you +# keep your template overrides. +# +# Read more: +# - https://zensical.org/docs/customization/#extending-the-theme +# +#custom_dir = "overrides" + +# With the "favicon" option you can set your own image to use as the icon +# browsers will use in the browser title bar or tab bar. The path provided +# must be relative to the "docs_dir". +# +# Read more: +# - https://zensical.org/docs/setup/logo-and-icons/#favicon +# - https://developer.mozilla.org/en-US/docs/Glossary/Favicon +# +#favicon = "images/favicon.png" + +# Zensical supports more than 60 different languages. This means that the +# labels and tooltips that Zensical's templates produce are translated. +# The "language" option allows you to set the language used. This language +# is also indicated in the HTML head element to help with accessibility +# and guide search engines and translation tools. +# +# The default language is "en" (English). It is possible to create +# sites with multiple languages and configure a language selector. See +# the documentation for details. +# +# Read more: +# - https://zensical.org/docs/setup/language/ +# +language = "en" + +# Zensical provides a number of feature toggles that change the behavior +# of the documentation site. +features = [ + # Zensical includes an announcement bar. This feature allows users to + # dismiss it when they have read the announcement. + # https://zensical.org/docs/setup/header/#announcement-bar + "announce.dismiss", + + # If you have a repository configured and turn on this feature, Zensical + # will generate an edit button for the page. This works for common + # repository hosting services. + # https://zensical.org/docs/setup/repository/#content-actions + #"content.action.edit", + + # If you have a repository configured and turn on this feature, Zensical + # will generate a button that allows the user to view the Markdown + # code for the current page. + # https://zensical.org/docs/setup/repository/#content-actions + #"content.action.view", + + # Code annotations allow you to add an icon with a tooltip to your + # code blocks to provide explanations at crucial points. + # https://zensical.org/docs/authoring/code-blocks/#code-annotations + "content.code.annotate", + + # This feature turns on a button in code blocks that allow users to + # copy the content to their clipboard without first selecting it. + # https://zensical.org/docs/authoring/code-blocks/#code-copy-button + "content.code.copy", + + # Code blocks can include a button to allow for the selection of line + # ranges by the user. + # https://zensical.org/docs/authoring/code-blocks/#code-selection-button + "content.code.select", + + # Zensical can render footnotes as inline tooltips, so the user can read + # the footnote without leaving the context of the document. + # https://zensical.org/docs/authoring/footnotes/#footnote-tooltips + "content.footnote.tooltips", + + # If you have many content tabs that have the same titles (e.g., "Python", + # "JavaScript", "Cobol"), this feature causes all of them to switch to + # at the same time when the user chooses their language in one. + # https://zensical.org/docs/authoring/content-tabs/#linked-content-tabs + "content.tabs.link", + + # With this feature enabled users can add tooltips to links that will be + # displayed when the mouse pointer hovers the link. + # https://zensical.org/docs/authoring/tooltips/#improved-tooltips + "content.tooltips", + + # With this feature enabled, Zensical will automatically hide parts + # of the header when the user scrolls past a certain point. + # https://zensical.org/docs/setup/header/#automatic-hiding + # "header.autohide", + + # Turn on this feature to expand all collapsible sections in the + # navigation sidebar by default. + # https://zensical.org/docs/setup/navigation/#navigation-expansion + # "navigation.expand", + + # This feature turns on navigation elements in the footer that allow the + # user to navigate to a next or previous page. + # https://zensical.org/docs/setup/footer/#navigation + "navigation.footer", + + # When section index pages are enabled, documents can be directly attached + # to sections, which is particularly useful for providing overview pages. + # https://zensical.org/docs/setup/navigation/#section-index-pages + "navigation.indexes", + + # When instant navigation is enabled, clicks on all internal links will be + # intercepted and dispatched via XHR without fully reloading the page. + # https://zensical.org/docs/setup/navigation/#instant-navigation + "navigation.instant", + + # With instant prefetching, your site will start to fetch a page once the + # user hovers over a link. This will reduce the perceived loading time + # for the user. + # https://zensical.org/docs/setup/navigation/#instant-prefetching + "navigation.instant.prefetch", + + # In order to provide a better user experience on slow connections when + # using instant navigation, a progress indicator can be enabled. + # https://zensical.org/docs/setup/navigation/#progress-indicator + #"navigation.instant.progress", + + # When navigation paths are activated, a breadcrumb navigation is rendered + # above the title of each page + # https://zensical.org/docs/setup/navigation/#navigation-path + "navigation.path", + + # When pruning is enabled, only the visible navigation items are included + # in the rendered HTML, reducing the size of the built site by 33% or more. + # https://zensical.org/docs/setup/navigation/#navigation-pruning + #"navigation.prune", + + # When sections are enabled, top-level sections are rendered as groups in + # the sidebar for viewports above 1220px, but remain as-is on mobile. + # https://zensical.org/docs/setup/navigation/#navigation-sections + "navigation.sections", + + # When tabs are enabled, top-level sections are rendered in a menu layer + # below the header for viewports above 1220px, but remain as-is on mobile. + # https://zensical.org/docs/setup/navigation/#navigation-tabs + #"navigation.tabs", + + # When sticky tabs are enabled, navigation tabs will lock below the header + # and always remain visible when scrolling down. + # https://zensical.org/docs/setup/navigation/#sticky-navigation-tabs + #"navigation.tabs.sticky", + + # A back-to-top button can be shown when the user, after scrolling down, + # starts to scroll up again. + # https://zensical.org/docs/setup/navigation/#back-to-top-button + "navigation.top", + + # When anchor tracking is enabled, the URL in the address bar is + # automatically updated with the active anchor as highlighted in the table + # of contents. + # https://zensical.org/docs/setup/navigation/#anchor-tracking + "navigation.tracking", + + # When search highlighting is enabled and a user clicks on a search result, + # Zensical will highlight all occurrences after following the link. + # https://zensical.org/docs/setup/search/#search-highlighting + "search.highlight", + + # When anchor following for the table of contents is enabled, the sidebar + # is automatically scrolled so that the active anchor is always visible. + # https://zensical.org/docs/setup/navigation/#anchor-following + # "toc.follow", + + # When navigation integration for the table of contents is enabled, it is + # always rendered as part of the navigation sidebar on the left. + # https://zensical.org/docs/setup/navigation/#navigation-integration + #"toc.integrate", +] + +# ---------------------------------------------------------------------------- +# You can configure your own logo to be shown in the header using the "logo" +# option in the "theme" subsection. The logo must be a relative path to a file +# in your "docs_dir", e.g., to use `docs/assets/logo.png` you would set: +# ---------------------------------------------------------------------------- +#logo = "assets/logo.png" + +# ---------------------------------------------------------------------------- +# If you don't have a dedicated project logo, you can use a built-in icon from +# the icon sets shipped in Zensical. Please note that the setting lives in a +# different subsection, and that the above take precedence over the icon. +# +# Read more: +# - https://zensical.org/docs/setup/logo-and-icons +# - https://github.com/zensical/ui/tree/master/dist/.icons +# ---------------------------------------------------------------------------- +#[project.theme.icon] +#logo = "lucide/smile" + +# ---------------------------------------------------------------------------- +# In the "font" subsection you can configure the fonts used. By default, fonts +# are loaded from Google Fonts, giving you a wide range of choices from a set +# of suitably licensed fonts. There are options for a normal text font and for +# a monospaced font used in code blocks. +# ---------------------------------------------------------------------------- +#[project.theme.font] +#text = "Inter" +#code = "Jetbrains Mono" + +# ---------------------------------------------------------------------------- +# In the "palette" subsection you can configure options for the color scheme. +# You can configure different color schemes, e.g., to turn on dark mode, +# that the user can switch between. Each color scheme can be further +# customized. +# +# Read more: +# - https://zensical.org/docs/setup/colors/ +# ---------------------------------------------------------------------------- +[[project.theme.palette]] +scheme = "default" +toggle.icon = "lucide/sun" +toggle.name = "Switch to dark mode" + +[[project.theme.palette]] +scheme = "slate" +toggle.icon = "lucide/moon" +toggle.name = "Switch to light mode" + +# ---------------------------------------------------------------------------- +# The "extra" section contains miscellaneous settings. +# ---------------------------------------------------------------------------- +#[[project.extra.social]] +#icon = "fontawesome/brands/github" +#link = "https://github.com/user/repo" From 587ea984ee3e1a89815d5a2c04639dbc44f8e922 Mon Sep 17 00:00:00 2001 From: hholb Date: Wed, 18 Mar 2026 14:50:16 -0600 Subject: [PATCH 2/4] first pass at docs site --- docs/api.md | 93 ++++++++++++++++++++++ docs/architecture.md | 77 ++++++++++++++++++ docs/cluster-setup.md | 161 ++++++++++++++++++++++++++++++++++++++ docs/clusters.md | 166 +++++++++++++++++++++++++++++++++++++++ docs/development.md | 53 +++++++++++++ docs/environments.md | 177 ++++++++++++++++++++++++++++++++++++++++++ docs/index.md | 177 ++++++++++-------------------------------- docs/installation.md | 41 ++++++++++ docs/lammps.md | 112 ++++++++++++++++++++++++++ docs/markdown.md | 98 ----------------------- zensical.toml | 36 ++++++--- 11 files changed, 948 insertions(+), 243 deletions(-) create mode 100644 docs/api.md create mode 100644 docs/architecture.md create mode 100644 docs/cluster-setup.md create mode 100644 docs/clusters.md create mode 100644 docs/development.md create mode 100644 docs/environments.md create mode 100644 docs/installation.md create mode 100644 docs/lammps.md delete mode 100644 docs/markdown.md diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..d745342 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,93 @@ +# API Reference + +## RootstockCalculator + +The main interface to Rootstock is the `RootstockCalculator` class, an ASE-compatible calculator. + +### Basic Usage + +```python +from ase.build import bulk +from rootstock import RootstockCalculator + +atoms = bulk("Cu", "fcc", a=3.6) * (5, 5, 5) + +with RootstockCalculator( + cluster="della", + model="mace", + checkpoint="medium", + device="cuda", +) as calc: + atoms.calc = calc + energy = atoms.get_potential_energy() + forces = atoms.get_forces() + stress = atoms.get_stress() +``` + +### Parameters + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `cluster` | `str` | Yes* | Cluster name (e.g., `"della"`, `"sophia"`) | +| `root` | `str` | Yes* | Custom root path instead of a known cluster | +| `model` | `str` | Yes | MLIP family: `"mace"`, `"chgnet"`, `"uma"`, `"tensornet"` | +| `checkpoint` | `str` | No | Specific model weights (uses environment default if omitted) | +| `device` | `str` | No | `"cuda"` (default) or `"cpu"` | + +*Either `cluster` or `root` must be provided, but not both. + +### Examples + +```python +# Using a known cluster with explicit checkpoint +RootstockCalculator(cluster="della", model="mace", checkpoint="medium") + +# Using a known cluster with default checkpoint +RootstockCalculator(cluster="della", model="uma") + +# Using a custom root path +RootstockCalculator(root="/scratch/gpfs/specific/install/path/rootstock", model="mace") +``` + +### Context Manager + +`RootstockCalculator` should be used as a context manager to ensure proper cleanup of the worker subprocess: + +```python +with RootstockCalculator(...) as calc: + # Use the calculator + atoms.calc = calc + energy = atoms.get_potential_energy() +# Worker process is automatically terminated +``` + +## Available Models + +The set of available models varies by cluster and changes as new environments are added. See the [dashboard](https://garden-ai-prod--rootstock-admin-dashboard.modal.run/) for what is currently deployed on each cluster. + +### Model Reference + +| Model | Environment | Default Checkpoint | Other Checkpoints | +|-------|-------------|-------------------|-------------------| +| `mace` | mace_env | `medium` | `small`, `large` | +| `chgnet` | chgnet_env | (pretrained) | — | +| `uma` | uma_env | `uma-s-1p1` | — | +| `tensornet` | tensornet_env | `TensorNet-MatPES-PBE-v2025.1-PES` | Other MatGL models | + +### Checking Available Models + +To see what models are available on your cluster: + +```bash +rootstock status --cluster della +``` + +Or programmatically: + +```python +from rootstock import list_environments + +envs = list_environments(cluster="della") +for env in envs: + print(f"{env.name}: {env.checkpoints}") +``` diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..5351706 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,77 @@ +# Architecture + +## Overview + +When you create a `RootstockCalculator`, Rootstock spawns a subprocess that runs the MLIP in its own pre-built virtual environment. The main process and worker communicate over a Unix domain socket using the [i-PI protocol](http://ipi-code.org/). This happens on a single node (no remote network calls). + +``` +Your script (on cluster node) Worker subprocess ++-------------------------+ +-----------------------------+ +| RootstockCalculator | | Pre-built MLIP environment | +| (ASE-compatible) | | | +| | | | +| server.py (i-PI server) |<-------->| worker.py (i-PI client) | +| - sends positions | Unix | - receives positions | +| - receives forces | socket | - calculates forces | ++-------------------------+ +-----------------------------+ +``` + +## Design Benefits + +This design takes out the pain of environment conflicts when experimenting with different MLIPs or using multiple MLIPs in a single workflow: + +- **No environment conflicts**: Each MLIP runs in isolation with its exact required dependencies +- **One-line model swapping**: Change `model="mace"` to `model="uma"` without reinstalling anything +- **Multi-model workflows**: Use multiple MLIPs in the same script (sequentially) +- **Clean user environments**: Users only install the lightweight `rootstock` package + +## Tradeoffs + +The tradeoff is that the architecture adds some overhead due to inter-process communication: + +- **~4% overhead** on an 864 atom system +- Communication happens via Unix domain socket (fast, no network) +- Positions and forces are serialized using the i-PI protocol + +For most use cases, this overhead is negligible compared to the time spent in the MLIP forward pass. + +## Directory Structure + +After setup, the rootstock root directory looks like this: + +``` +{root}/ +├── .python/ # uv-managed Python interpreters +├── environments/ # Environment source files (*.py with PEP 723 metadata) +│ ├── mace_env.py +│ ├── chgnet_env.py +│ ├── uma_env.py +│ └── tensornet_env.py +├── envs/ # Pre-built virtual environments +│ ├── mace_env/ +│ │ ├── bin/python +│ │ ├── lib/python3.11/site-packages/ +│ │ └── env_source.py +│ └── ... +├── home/ # Redirected HOME for not-well-behaved libraries +│ ├── .cache/fairchem/ +│ └── .matgl/ +└── cache/ # XDG_CACHE_HOME and HF_HOME for well-behaved libraries + ├── mace/ + └── huggingface/ +``` + +### Why the `home/` Directory? + +The `home/` directory exists because some ML libraries (FAIRChem, MatGL) ignore `XDG_CACHE_HOME` and write to `~/.cache/` unconditionally. Rootstock redirects `HOME` during builds and at worker runtime so that model weights end up in the shared directory rather than in individual users' home directories. + +## i-PI Protocol + +Rootstock uses the [i-PI protocol](http://ipi-code.org/) for communication between the main process and worker: + +1. **Main process** sends atomic positions and cell parameters +2. **Worker** receives positions, runs the MLIP forward pass +3. **Worker** sends back energy, forces, and stress +4. **Main process** receives results and returns them to ASE + +The protocol is text-based and designed for interoperability between different simulation codes. diff --git a/docs/cluster-setup.md b/docs/cluster-setup.md new file mode 100644 index 0000000..b4972e6 --- /dev/null +++ b/docs/cluster-setup.md @@ -0,0 +1,161 @@ +# Setting Up a New Cluster + +This section is for people setting up Rootstock on a new cluster. All commands below are run **on the cluster itself** (SSH in first). You'll need write access to a shared filesystem location visible to your users. + +## Prerequisites + +- SSH access to the cluster +- Write access to a shared filesystem location +- Python 3.10 or later +- `uv` package manager (Rootstock uses it internally) + +## Step 1: Install Rootstock + +On a login node: + +```bash +pip install rootstock +``` + +## Step 2: Initialize the Rootstock Directory + +Choose a location on an appropriate shared filesystem where users can read but only maintainers can write. Then run: + +```bash +rootstock init +``` + +This will interactively prompt you for: + +| Setting | Description | +|---------|-------------| +| **root** | The shared directory path (e.g., `/scratch/shared/rootstock`) | +| **api_key / api_secret** | Optional credentials for pushing the cluster manifest to the Rootstock dashboard | +| **maintainer name / email** | Identifies the maintainer for this installation | + +!!! tip "Dashboard Integration" + Contact a Rootstock maintainer if you want your cluster to appear on the [dashboard](https://garden-ai-prod--rootstock-admin-dashboard.modal.run/). The API credentials are [Modal Proxy Auth Tokens](https://modal.com/docs/guide/webhook-proxy-auth). + +## Step 3: Install Environments + +Still on the login node: + +```bash +# Install individual environments +rootstock install mace_env.py --models small,medium +rootstock install chgnet_env.py +rootstock install uma_env.py --models uma-s-1p1 +rootstock install tensornet_env.py + +# Or point it at a directory with multiple environments +rootstock install ./environments/ + +# Verify everything is set up +rootstock status +``` + +Each `rootstock install` command: + +1. Creates an isolated virtual environment under `{root}/envs/` +2. Installs the MLIP's dependencies +3. Optionally pre-downloads model weights (via `--models`) + +This can take several minutes per environment depending on the MLIP. + +!!! note "Finding Environment Files" + See the [dashboard](https://garden-ai-prod--rootstock-admin-dashboard.modal.run/) for environment files that are known to work — you can use these as a starting point for your cluster. + +## Step 4: Register with the Dashboard (Optional) + +If you configured API credentials during `rootstock init`, the manifest is pushed automatically when you install or update environments. If the push failed (e.g., due to network issues), you can retry: + +```bash +rootstock manifest push +``` + +## Verifying the Installation + +After setup, verify that everything works: + +```bash +# Check status +rootstock status + +# List all environments +rootstock list + +# Test a specific model (if you have GPU access) +rootstock test --model mace --checkpoint medium +``` + +## Directory Structure + +After setup, the rootstock root directory will look like this: + +``` +{root}/ +├── .python/ # uv-managed Python interpreters +├── environments/ # Environment source files (*.py with PEP 723 metadata) +│ ├── mace_env.py +│ ├── chgnet_env.py +│ ├── uma_env.py +│ └── tensornet_env.py +├── envs/ # Pre-built virtual environments +│ ├── mace_env/ +│ │ ├── bin/python +│ │ ├── lib/python3.11/site-packages/ +│ │ └── env_source.py +│ └── ... +├── home/ # Redirected HOME for not-well-behaved libraries +│ ├── .cache/fairchem/ +│ └── .matgl/ +└── cache/ # XDG_CACHE_HOME and HF_HOME for well-behaved libraries + ├── mace/ + └── huggingface/ +``` + +## Updating Environments + +To update an environment with new dependencies or model weights: + +```bash +# Rebuild with new models +rootstock install mace_env.py --models small,medium,large --force + +# Push updated manifest +rootstock manifest push +``` + +## Troubleshooting + +### Environment build fails + +Check that you have: + +- Sufficient disk space in `{root}/` +- Network access for downloading packages and model weights +- Correct Python version (3.10+) + +### Users can't access environments + +Verify permissions: + +```bash +# Environments should be readable by all users +ls -la {root}/envs/ + +# Model weights in cache should also be readable +ls -la {root}/cache/ +``` + +### Dashboard push fails + +Check your API credentials and network connectivity: + +```bash +# Verify credentials are configured +rootstock config show + +# Retry push +rootstock manifest push --verbose +``` diff --git a/docs/clusters.md b/docs/clusters.md new file mode 100644 index 0000000..d6ee48c --- /dev/null +++ b/docs/clusters.md @@ -0,0 +1,166 @@ +# Example Configs + +Example environment configurations from clusters where Rootstock is deployed. Use these as a starting point when setting up your own cluster. + + + +
+

Loading cluster configurations...

+
+ + diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000..3be6252 --- /dev/null +++ b/docs/development.md @@ -0,0 +1,53 @@ +# Development + +## Local Development Setup + +```bash +git clone https://github.com/Garden-AI/rootstock.git +cd rootstock +uv venv && source .venv/bin/activate +uv pip install -e ".[dev]" +``` + +## Code Quality + +Run linting before committing: + +```bash +ruff check rootstock/ +ruff format rootstock/ +``` + +## Project Structure + +``` +rootstock/ +├── rootstock/ +│ ├── __init__.py +│ ├── calculator.py # ASE Calculator interface +│ ├── server.py # Spawns worker subprocess, manages socket lifecycle +│ ├── worker.py # i-PI client state machine +│ ├── environment.py # Pre-built environment management +│ ├── clusters.py # Cluster registry and known environments +│ └── cli.py # CLI commands (build, status, list, register) +├── environments/ # Example environment files +├── lammps/ # LAMMPS fix source files +├── tests/ +└── docs/ +``` + +## Running Tests + +```bash +pytest tests/ +``` + +## Get Involved + +Rootstock is an early-stage project and we welcome feedback, bug reports, and collaborators. If you're interested in: + +- Deploying Rootstock on your cluster +- Contributing environment files for new MLIPs +- Using it for a research project + +Please contact Will Engler at [willengler@uchicago.edu](mailto:willengler@uchicago.edu). diff --git a/docs/environments.md b/docs/environments.md new file mode 100644 index 0000000..31d7e7e --- /dev/null +++ b/docs/environments.md @@ -0,0 +1,177 @@ +# Writing Environment Files + +Each MLIP is defined by a small Python file with [PEP 723](https://peps.python.org/pep-0723/) inline metadata specifying its dependencies and a `setup()` function that returns an ASE calculator. + +## Basic Structure + +```python +# /// script +# requires-python = ">=3.10" +# dependencies = ["mace-torch>=0.3.14", "ase>=3.22", "torch>=2.0,<2.10"] +# /// + +def setup(model: str, device: str = "cuda"): + from mace.calculators import mace_mp + return mace_mp(model=model, device=device, default_dtype="float32") +``` + +## How It Works + +1. **PEP 723 metadata**: The `# /// script` block defines Python version requirements and dependencies +2. **`setup()` function**: Called once when a worker starts; the returned calculator is reused for all calculations +3. **uv builds the environment**: Rootstock uses `uv` to create an isolated virtual environment from these dependencies + +## Required Elements + +### PEP 723 Metadata Block + +```python +# /// script +# requires-python = ">=3.10" +# dependencies = [ +# "mace-torch>=0.3.14", +# "ase>=3.22", +# "torch>=2.0,<2.10" +# ] +# /// +``` + +- `requires-python`: Minimum Python version +- `dependencies`: List of pip-installable packages with version constraints + +### The `setup()` Function + +```python +def setup(model: str, device: str = "cuda"): + # Import the MLIP library + from mace.calculators import mace_mp + + # Create and return an ASE calculator + return mace_mp(model=model, device=device, default_dtype="float32") +``` + +The function receives: + +- `model`: The checkpoint/model name passed by the user +- `device`: Either `"cuda"` or `"cpu"` + +It must return an ASE-compatible calculator object. + +## Examples + +### MACE + +```python +# /// script +# requires-python = ">=3.10" +# dependencies = ["mace-torch>=0.3.14", "ase>=3.22", "torch>=2.0,<2.10"] +# /// + +def setup(model: str, device: str = "cuda"): + from mace.calculators import mace_mp + return mace_mp(model=model, device=device, default_dtype="float32") +``` + +### CHGNet + +```python +# /// script +# requires-python = ">=3.10" +# dependencies = ["chgnet>=0.3.0", "ase>=3.22", "torch>=2.0"] +# /// + +def setup(model: str = "pretrained", device: str = "cuda"): + from chgnet.model import CHGNetCalculator + return CHGNetCalculator(use_device=device) +``` + +### UMA (FAIRChem) + +```python +# /// script +# requires-python = ">=3.10" +# dependencies = [ +# "fairchem-core>=1.0.0", +# "ase>=3.22", +# "torch>=2.0" +# ] +# /// + +def setup(model: str = "uma-s-1p1", device: str = "cuda"): + from fairchem.core import OCPCalculator + return OCPCalculator(checkpoint_path=model, device=device) +``` + +### TensorNet (MatGL) + +```python +# /// script +# requires-python = ">=3.10" +# dependencies = ["matgl>=1.0.0", "ase>=3.22", "torch>=2.0"] +# /// + +def setup(model: str = "TensorNet-MatPES-PBE-v2025.1-PES", device: str = "cuda"): + import matgl + from matgl.ext.ase import MatGLCalculator + + potential = matgl.load_model(model) + return MatGLCalculator(potential, device=device) +``` + +## Best Practices + +### Pin dependency versions + +Use version constraints to ensure reproducible builds: + +```python +# Good: pinned versions +# dependencies = ["mace-torch>=0.3.14,<0.4", "torch>=2.0,<2.10"] + +# Avoid: unpinned versions +# dependencies = ["mace-torch", "torch"] +``` + +### Handle model loading errors gracefully + +```python +def setup(model: str, device: str = "cuda"): + from mace.calculators import mace_mp + + try: + return mace_mp(model=model, device=device, default_dtype="float32") + except Exception as e: + raise RuntimeError(f"Failed to load MACE model '{model}': {e}") +``` + +### Document available checkpoints + +Add a comment listing known-good checkpoints: + +```python +# /// script +# requires-python = ">=3.10" +# dependencies = ["mace-torch>=0.3.14", "ase>=3.22", "torch>=2.0,<2.10"] +# /// +# +# Available checkpoints: small, medium, large + +def setup(model: str, device: str = "cuda"): + from mace.calculators import mace_mp + return mace_mp(model=model, device=device, default_dtype="float32") +``` + +## Testing Your Environment + +After creating an environment file, test it: + +```bash +# Build the environment +rootstock install my_env.py --models default_checkpoint + +# Check it was built successfully +rootstock status + +# Test the calculator (if you have GPU access) +rootstock test --env my_env --model default_checkpoint +``` diff --git a/docs/index.md b/docs/index.md index 3b76a8a..83816d6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,166 +1,75 @@ ---- -icon: lucide/rocket ---- +# Rootstock -# Get started +Rootstock makes it easy to use machine-learned interatomic potentials (MLIPs) on national lab and academic HPC clusters. Researchers can use multiple MLIPs (MACE, CHGNet, UMA, TensorNet, and others) with ASE or LAMMPS without managing the conflicting Python environments that each MLIP requires. -For full documentation visit [zensical.org](https://zensical.org/docs/). +Rootstock provides an [ASE](https://wiki.fysik.dtu.dk/ase/)-compatible calculator that runs each MLIP in an isolated, pre-built Python environment behind the scenes. Swapping models is a one-line change, even if the MLIPs require different Python or library versions. Rootstock also integrates with [LAMMPS](https://www.lammps.org/) through a `fix` with any supported MLIP. -## Commands +## Status -* [`zensical new`][new] - Create a new project -* [`zensical serve`][serve] - Start local web server -* [`zensical build`][build] - Build your site +Rootstock is **early-stage software under active development.** It is currently deployed on two HPC clusters: - [new]: https://zensical.org/docs/usage/new/ - [serve]: https://zensical.org/docs/usage/preview/ - [build]: https://zensical.org/docs/usage/build/ +- **Della** — Princeton Research Computing +- **Sophia** — Argonne Leadership Computing Facility (ALCF) -## Examples +We are looking for additional clusters and early users to help shape the tool. If you're interested in trying Rootstock on your cluster or for a specific project, please reach out to Will Engler at [willengler@uchicago.edu](mailto:willengler@uchicago.edu). -### Admonitions +## Quick Start -> Go to [documentation](https://zensical.org/docs/authoring/admonitions/) +Rootstock is designed for use on an HPC cluster where it has already been set up by a maintainer. The code below runs in your normal Python environment — inside a SLURM job script, an interactive session, or a Jupyter notebook on the cluster. Rootstock handles the MLIP environment isolation. -!!! note +```python +from ase.build import bulk +from rootstock import RootstockCalculator - This is a **note** admonition. Use it to provide helpful information. +atoms = bulk("Cu", "fcc", a=3.6) * (5, 5, 5) -!!! warning - - This is a **warning** admonition. Be careful! - -### Details - -> Go to [documentation](https://zensical.org/docs/authoring/admonitions/#collapsible-blocks) - -??? info "Click to expand for more info" - - This content is hidden until you click to expand it. - Great for FAQs or long explanations. - -## Code Blocks - -> Go to [documentation](https://zensical.org/docs/authoring/code-blocks/) - -``` python hl_lines="2" title="Code blocks" -def greet(name): - print(f"Hello, {name}!") # (1)! - -greet("Python") +with RootstockCalculator( + cluster="della", + model="mace", + checkpoint="medium", + device="cuda", +) as calc: + atoms.calc = calc + print(atoms.get_potential_energy()) + print(atoms.get_forces()) ``` -1. > Go to [documentation](https://zensical.org/docs/authoring/code-blocks/#code-annotations) - - Code annotations allow to attach notes to lines of code. - -Code can also be highlighted inline: `#!python print("Hello, Python!")`. - -## Content tabs - -> Go to [documentation](https://zensical.org/docs/authoring/content-tabs/) - -=== "Python" - - ``` python - print("Hello from Python!") - ``` - -=== "Rust" - - ``` rs - println!("Hello from Rust!"); - ``` - -## Diagrams - -> Go to [documentation](https://zensical.org/docs/authoring/diagrams/) - -``` mermaid -graph LR - A[Start] --> B{Error?}; - B -->|Yes| C[Hmm...]; - C --> D[Debug]; - D --> B; - B ---->|No| E[Yay!]; -``` - -## Footnotes - -> Go to [documentation](https://zensical.org/docs/authoring/footnotes/) - -Here's a sentence with a footnote.[^1] - -Hover it, to see a tooltip. - -[^1]: This is the footnote. +Changing `model="mace"` to `model="uma"` or `model="tensornet"` swaps the underlying potential. +## Next Steps -## Formatting +
-> Go to [documentation](https://zensical.org/docs/authoring/formatting/) +- :material-download:{ .lg .middle } **Installation** -- ==This was marked (highlight)== -- ^^This was inserted (underline)^^ -- ~~This was deleted (strikethrough)~~ -- H~2~O -- A^T^A -- ++ctrl+alt+del++ + --- -## Icons, Emojis + Install the lightweight `rootstock` package in your environment. -> Go to [documentation](https://zensical.org/docs/authoring/icons-emojis/) + [:octicons-arrow-right-24: Installation](installation.md) -* :sparkles: `:sparkles:` -* :rocket: `:rocket:` -* :tada: `:tada:` -* :memo: `:memo:` -* :eyes: `:eyes:` +- :material-api:{ .lg .middle } **API Reference** -## Maths + --- -> Go to [documentation](https://zensical.org/docs/authoring/math/) + Learn about the `RootstockCalculator` API and available models. -$$ -\cos x=\sum_{k=0}^{\infty}\frac{(-1)^k}{(2k)!}x^{2k} -$$ + [:octicons-arrow-right-24: API](api.md) -!!! warning "Needs configuration" - Note that MathJax is included via a `script` tag on this page and is not - configured in the generated default configuration to avoid including it - in a pages that do not need it. See the documentation for details on how - to configure it on all your pages if they are more Maths-heavy than these - simple starter pages. +- :material-earth:{ .lg .middle } **Example Configs** - - + --- -## Task Lists + See example environment configurations from deployed clusters. -> Go to [documentation](https://zensical.org/docs/authoring/lists/#using-task-lists) + [:octicons-arrow-right-24: Example Configs](clusters.md) -* [x] Install Zensical -* [x] Configure `zensical.toml` -* [x] Write amazing documentation -* [ ] Deploy anywhere +- :material-server:{ .lg .middle } **Cluster Setup** -## Tooltips + --- -> Go to [documentation](https://zensical.org/docs/authoring/tooltips/) + Set up Rootstock on a new HPC cluster. -[Hover me][example] + [:octicons-arrow-right-24: Cluster Setup](cluster-setup.md) - [example]: https://example.com "I'm a tooltip!" +
diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..e81e4c6 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,41 @@ +# Installation + +Users install only the lightweight `rootstock` package. The heavy ML dependencies (PyTorch, MACE, FAIRChem, etc.) live in the pre-built environments on the cluster. + +## Requirements + +- Python 3.10 or later +- Access to a supported HPC cluster (Della, Sophia, or a custom installation) + +## Install with pip + +```bash +pip install rootstock +``` + +## Install with uv + +```bash +uv pip install rootstock +``` + +## Verify Installation + +After installation, verify that Rootstock is working: + +```python +from rootstock import RootstockCalculator + +# Check available clusters +print(RootstockCalculator.list_clusters()) +``` + +## What Gets Installed + +The `rootstock` package is intentionally minimal. It includes: + +- The `RootstockCalculator` ASE-compatible calculator +- The i-PI protocol client/server implementation +- CLI tools for cluster administrators + +The heavy dependencies (PyTorch, CUDA, MACE, CHGNet, FAIRChem, etc.) are **not** installed on your system. Instead, they live in pre-built virtual environments managed by cluster administrators. diff --git a/docs/lammps.md b/docs/lammps.md new file mode 100644 index 0000000..2820f5e --- /dev/null +++ b/docs/lammps.md @@ -0,0 +1,112 @@ +# LAMMPS Integration + +!!! warning "Experimental" + LAMMPS integration is experimental and has not been tested as thoroughly as the ASE integration yet. If you try it and run into issues, please reach out. + +Rootstock includes a native LAMMPS `fix` that auto-spawns a worker subprocess, giving LAMMPS users access to any Rootstock-managed MLIP. + +## Quick Start + +Add one line to your LAMMPS input script: + +```lammps +fix mlip all rootstock cluster della model mace checkpoint medium device cuda elements Cu +``` + +The fix handles worker lifecycle, socket communication, and cleanup automatically. Virial information is passed through, so barostats (`npt`, `nph`) work correctly. Energy is accessible via `f_mlip` in thermo output. + +## Building the Fix + +The fix ships as two files (`fix_rootstock.h`, `fix_rootstock.cpp`) with no dependencies beyond the C++ standard library and POSIX sockets. Copy them into your LAMMPS `src/` directory and rebuild: + +```bash +./lammps/install.sh /path/to/lammps/src +cd /path/to/lammps/build +cmake ../cmake [your usual flags] +make -j 4 +``` + +Rootstock must also be installed and on `PATH` so the fix can call `rootstock resolve` and `rootstock serve`: + +```bash +pip install rootstock +``` + +## Fix Syntax + +```lammps +fix rootstock cluster model \ + checkpoint device [timeout ] elements ... +``` + +### Parameters + +| Keyword | Required | Default | Description | +|---------|----------|---------|-------------| +| `cluster` | yes | — | Cluster name (e.g., `della`) | +| `model` | yes | — | MLIP family: `mace`, `chgnet`, `uma`, `tensornet` | +| `checkpoint` | no | `default` | Model weights (e.g., `medium`, `uma-s-1p1`) | +| `device` | no | `cuda` | `cuda` or `cpu` | +| `timeout` | no | `120` | Seconds to wait for worker startup | +| `elements` | yes | — | Element symbols mapping atom types (must be last) | + +## Example Input Script + +```lammps +units metal +atom_style atomic +boundary p p p + +# Create or read your structure +lattice fcc 3.6 +region box block 0 5 0 5 0 5 +create_box 1 box +create_atoms 1 box +mass 1 63.546 # Cu + +# Use pair_style zero - the fix provides all forces +pair_style zero 6.0 +pair_coeff * * + +# Rootstock fix +fix mlip all rootstock cluster della model mace checkpoint medium device cuda elements Cu + +# Thermo output - energy accessible via f_mlip +thermo_style custom step temp pe f_mlip press +thermo 100 + +# Run dynamics +velocity all create 300.0 12345 +fix nve all nve +run 1000 +``` + +## Important Notes + +- **Requires `units metal`**: The fix checks this at startup and will error if a different unit system is used. +- **Use `pair_style zero`**: The fix provides all interatomic forces, so you need a placeholder pair style. +- **Single-node only**: The worker sees all atoms and computes its own neighborhoods. MPI-parallel LAMMPS runs are not yet supported. +- **Element order matters**: The `elements` keyword must be last, and element symbols must map to LAMMPS atom types in order (type 1 = first element, type 2 = second element, etc.). + +## Accessing Energy + +The fix stores the potential energy computed by the MLIP. Access it in thermo output: + +```lammps +thermo_style custom step temp pe f_mlip press +``` + +Or use it in a variable: + +```lammps +variable mlip_energy equal f_mlip +``` + +## Barostat Support + +Virial information is correctly passed through, so NPT and NPH ensembles work: + +```lammps +fix mlip all rootstock cluster della model mace checkpoint medium device cuda elements Cu +fix npt all npt temp 300 300 0.1 iso 1.0 1.0 1.0 +``` diff --git a/docs/markdown.md b/docs/markdown.md deleted file mode 100644 index 7ea6d1e..0000000 --- a/docs/markdown.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -icon: simple/markdown ---- - -# Markdown in 5min - -## Headers -``` -# H1 Header -## H2 Header -### H3 Header -#### H4 Header -##### H5 Header -###### H6 Header -``` - -## Text formatting -``` -**bold text** -*italic text* -***bold and italic*** -~~strikethrough~~ -`inline code` -``` - -## Links and images -``` -[Link text](https://example.com) -[Link with title](https://example.com "Hover title") -![Alt text](image.jpg) -![Image with title](image.jpg "Image title") -``` - -## Lists -``` -Unordered: -- Item 1 -- Item 2 - - Nested item - -Ordered: -1. First item -2. Second item -3. Third item -``` - -## Blockquotes -``` -> This is a blockquote -> Multiple lines ->> Nested quote -``` - -## Code blocks -```` -```javascript -function hello() { - console.log("Hello, world!"); -} -``` -```` - -## Tables -``` -| Header 1 | Header 2 | Header 3 | -|----------|----------|----------| -| Row 1 | Data | Data | -| Row 2 | Data | Data | -``` - -## Horizontal rule -``` ---- -or -*** -or -___ -``` - -## Task lists -``` -- [x] Completed task -- [ ] Incomplete task -- [ ] Another task -``` - -## Escaping characters -``` -Use backslash to escape: \* \_ \# \` -``` - -## Line breaks -``` -End a line with two spaces -to create a line break. - -Or use a blank line for a new paragraph. -``` \ No newline at end of file diff --git a/zensical.toml b/zensical.toml index 1ff7ad2..e8b63fe 100644 --- a/zensical.toml +++ b/zensical.toml @@ -11,18 +11,18 @@ # The site_name is shown in the page header and the browser window title # # Read more: https://zensical.org/docs/setup/basics/#site_name -site_name = "Documentation" +site_name = "Rootstock Documentation" # The site_description is included in the HTML head and should contain a # meaningful description of the site content for use by search engines. # # Read more: https://zensical.org/docs/setup/basics/#site_description -site_description = "A new project generated from the default template project." +site_description = "Documentation for the Rootstock package." # The site_author attribute. This is used in the HTML head element. # # Read more: https://zensical.org/docs/setup/basics/#site_author -site_author = "" +site_author = "Hayden Holbrook" # The site_url is the canonical URL for your site. When building online # documentation you should set this. @@ -44,10 +44,17 @@ Copyright © 2026 The authors # can be defined using TOML syntax. # # Read more: https://zensical.org/docs/setup/navigation/ -# nav = [ -# { "Get started" = "index.md" }, -# { "Markdown in 5min" = "markdown.md" }, -# ] +nav = [ + { "Home" = "index.md" }, + { "Installation" = "installation.md" }, + { "Example Configs" = "clusters.md" }, + { "LAMMPS Integration" = "lammps.md" }, + { "Cluster Setup" = "cluster-setup.md" }, + { "Writing Environments" = "environments.md" }, + { "API Reference" = "api.md" }, + { "Architecture" = "architecture.md" }, + { "Development" = "development.md" }, +] # With the "extra_css" option you can add your own CSS styling to customize # your Zensical project according to your needs. You can add any number of @@ -122,7 +129,7 @@ features = [ # will generate an edit button for the page. This works for common # repository hosting services. # https://zensical.org/docs/setup/repository/#content-actions - #"content.action.edit", + "content.action.edit", # If you have a repository configured and turn on this feature, Zensical # will generate a button that allows the user to view the Markdown @@ -297,9 +304,16 @@ scheme = "slate" toggle.icon = "lucide/moon" toggle.name = "Switch to light mode" +# ---------------------------------------------------------------------------- +# Repository configuration for edit links +# ---------------------------------------------------------------------------- +[project.repo] +url = "https://github.com/Garden-AI/rootstock" +name = "GitHub" + # ---------------------------------------------------------------------------- # The "extra" section contains miscellaneous settings. # ---------------------------------------------------------------------------- -#[[project.extra.social]] -#icon = "fontawesome/brands/github" -#link = "https://github.com/user/repo" +[[project.extra.social]] +icon = "fontawesome/brands/github" +link = "https://github.com/Garden-AI/rootstock" From 4e56261d890779128de7063ea336f44cf8020e7b Mon Sep 17 00:00:00 2001 From: hholb Date: Thu, 19 Mar 2026 11:20:23 -0600 Subject: [PATCH 3/4] use prod url for clutster fetching --- docs/clusters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/clusters.md b/docs/clusters.md index d6ee48c..7c19871 100644 --- a/docs/clusters.md +++ b/docs/clusters.md @@ -35,7 +35,7 @@ Example environment configurations from clusters where Rootstock is deployed. Us