Skip to content

Commit

Permalink
add domino example
Browse files Browse the repository at this point in the history
  • Loading branch information
ryichando committed Jan 7, 2025
1 parent 922b799 commit 9a14f1d
Show file tree
Hide file tree
Showing 9 changed files with 689 additions and 65 deletions.
68 changes: 68 additions & 0 deletions .github/workflows/example_domino.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# File: example_domino.yml
# Author: Ryoichi Ando ([email protected])
# License: Apache v2.0

name: domino.ipynb

on:
workflow_dispatch:
inputs:
runner:
type: string
required: true
description: 'Runner Name'

env:
VAST_API_KEY: ${{ secrets.VAST_API_KEY }}
EXAMPLE_NAME: domino
HELPER_PATH: .github/workflows/vast/helper.sh

jobs:
run:
runs-on: ${{ github.event.inputs.runner }}
steps:

- name: check out repo
uses: actions/checkout@v3

- name: print scene
run: |
echo "Scene: $EXAMPLE_NAME" >> $GITHUB_STEP_SUMMARY
- name: prepare
timeout-minutes: 30
run: bash $HELPER_PATH create $VAST_API_KEY

- name: 1st run
run: bash $HELPER_PATH run ${EXAMPLE_NAME}.py

- name: 2nd run
run: bash $HELPER_PATH run ${EXAMPLE_NAME}.py

- name: 3rd run
run: bash $HELPER_PATH run ${EXAMPLE_NAME}.py

- name: 4th run
run: bash $HELPER_PATH run ${EXAMPLE_NAME}.py

- name: 5th run
run: bash $HELPER_PATH run ${EXAMPLE_NAME}.py

- name: 6th run
run: bash $HELPER_PATH run ${EXAMPLE_NAME}.py

- name: 7th run
run: bash $HELPER_PATH run ${EXAMPLE_NAME}.py

- name: 8th run
run: bash $HELPER_PATH run ${EXAMPLE_NAME}.py

- name: 9th run
run: bash $HELPER_PATH run ${EXAMPLE_NAME}.py

- name: 10th run
run: bash $HELPER_PATH run ${EXAMPLE_NAME}.py

- name: shutdown
if: always()
run: bash $HELPER_PATH delete
19 changes: 19 additions & 0 deletions .github/workflows/vast-all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,22 @@ jobs:
- name: shutdown
if: always()
run: bash $HELPER_PATH delete

part_5:
runs-on: ${{ github.event.inputs.runner }}
timeout-minutes: 300
steps:

- name: check out repo
uses: actions/checkout@v3

- name: prepare
timeout-minutes: 30
run: bash $HELPER_PATH create $VAST_API_KEY

- name: domino
run: bash $HELPER_PATH run domino.py

- name: shutdown
if: always()
run: bash $HELPER_PATH delete
18 changes: 12 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ Published in [ACM Transactions on Graphics (TOG)](https://dl.acm.org/doi/abs/10.

## 📝 Change History

- (2025.1.8) Added a [domino example](./examples/domino.ipynb) [[Video]](https://drive.google.com/file/d/1N9y8eZrjSQhAUhKwiO9w8jW_T18zPnYf/view).
- (2025.1.5) Added a [single twist example](./examples/twist.ipynb) [[Video]](https://drive.google.com/file/d/1LDFKS-iBvl2uDdPVKaazQL25tYGEEyXr/view).
- (2024.12.31) Added full documentation for Python APIs, parameters, and log files [[GitHub Pages]](https://st-tech.github.io/ppf-contact-solver).
- (2024.12.27) Line search for strain limiting is improved [[Markdown]](./articles/bug.md#new-strain-limiting-line-search)
Expand Down Expand Up @@ -181,6 +182,9 @@ The behaviors can be changed through the settings.

- A list of parameters used in `param.set(key,value)` is documented here [[GitHub Pages]](https://st-tech.github.io/ppf-contact-solver/parameters.html).

> [!NOTE]
> ⚠️ Please note that our Python APIs are subject to breaking changes as this repository undergoes frequent iterations. 🚧
## 🔍 Obtaining Logs

📊 Logs for the simulation can also be queried through the Python APIs 🐍. Here's an example of how to get a list of recorded logs 📝, fetch them 📥, and compute the average 🧮.
Expand Down Expand Up @@ -257,7 +261,7 @@ All the log files 📂 are available ✅ and can be fetched ⬇️ during the si
|![](./asset/image/catalogue/woven.mp4.gif)|![](./asset/image/catalogue/stack.mp4.gif)|![](./asset/image/catalogue/trampoline.mp4.gif)|![](./asset/image/catalogue/needle.mp4.gif)|
|[cards](./examples/cards.ipynb) [[Video]](https://drive.google.com/file/d/1PMdDnlyCsjinbvICKph_0UcXUfUvvUmZ/view)|codim|[hang](./examples/hang.ipynb) [[Video]](https://drive.google.com/file/d/1gIjwaRrEifH0FQnZ8HO8Q9-f9FF5ZivG/view)|[trapped](./examples/trapped.ipynb)|
|![](./asset/image/catalogue/cards.mp4.gif)|![](./asset/image/catalogue/codim.mp4.gif)|![](./asset/image/catalogue/hang.mp4.gif)|![](./asset/image/catalogue/trapped.mp4.gif)|
|domino|noodle|[drape](./examples/drape.ipynb) [[Video]](https://drive.google.com/file/d/1PGL3tbA451VhHOViSJJNNdQvmUpg7bQd/view)|[twist](./examples/twist.ipynb) [[Video]](https://drive.google.com/file/d/1LDFKS-iBvl2uDdPVKaazQL25tYGEEyXr/view)|
|[domino](./examples/domino.ipynb) [[Video]](https://drive.google.com/file/d/1N9y8eZrjSQhAUhKwiO9w8jW_T18zPnYf/view)|noodle|[drape](./examples/drape.ipynb) [[Video]](https://drive.google.com/file/d/1PGL3tbA451VhHOViSJJNNdQvmUpg7bQd/view)|[twist](./examples/twist.ipynb) [[Video]](https://drive.google.com/file/d/1LDFKS-iBvl2uDdPVKaazQL25tYGEEyXr/view)|
|![](./asset/image/catalogue/domino.mp4.gif)|![](./asset/image/catalogue/noodle.mp4.gif)|![](./asset/image/catalogue/drape.mp4.gif)|![](./asset/image/catalogue/quintupletwist.mp4.gif)|
|ribbon|[curtain](./examples/curtain.ipynb) [[Video]](https://drive.google.com/file/d/1c9W3YAFAS5r9m9i7sZHsFu8h98C8yy1T/view)|fishingknot|[friction](./examples/friction.ipynb) [[Video]](https://drive.google.com/file/d/12WGdfDTFIwCT0UFGEZzfmQreM6WSSHet/view)|
|![](./asset/image/catalogue/ribbon.mp4.gif)|![](./asset/image/catalogue/curtain.mp4.gif)|![](./asset/image/catalogue/fishingknot.mp4.gif)|![](./asset/image/catalogue/friction-armadillo.mp4.gif)|
Expand Down Expand Up @@ -302,13 +306,15 @@ Also, we apply small jitters to the position of objects in the scene 🔄, so at

#### ⚠️ Disclaimer


Our long stress tests can fail due to following reasons:

<img align="right" width="150" src="./asset/image/snag-failure.jpg">
We are constantly updating our algorithms 🔄, which may lead to failures ❌.
Of course, we push our code after a few tests ✅ passed, but still, failures can occur 🚫 in this long stress test.
Please understand that this stress test is indeed designed for this purpose 🎯.
Failures can be also due to excessively difficult spots 🔬, which are unintended.

- We are constantly updating our algorithms 🔄, which may introduce bugs. This stress test is indeed designed for this purpose 🎯.
- Failures can be also due to excessively difficult spots 🔬, which are unintended.
An example is shown in the right inset 👉.
We also update scene settings to avoid such unreasonable cases 🔧.
- Occasionally, we experience [vast.ai](https://vast.ai) instances shutting down before simulations finish.

## 💨 Getting Started

Expand Down
16 changes: 8 additions & 8 deletions examples/cards.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,20 @@
" x, _y, ceil_x = 0, 0, []\n",
" for i in range(n):\n",
" left = scene.add(\"card\").rotate(-angle, \"z\")\n",
" left.at(x - left.min(0) + (_x if i == 0 else 0), y - left.min(1), 0)\n",
" left.at(x - left.min(\"x\") + (_x if i == 0 else 0), y - left.min(\"y\"), 0)\n",
" if i == 0:\n",
" _x = left.max(0)\n",
" _x = left.max(\"x\")\n",
" right = scene.add(\"card\").rotate(angle, \"z\")\n",
" shift = gap + left.max(0) - right.min(0)\n",
" right.at(shift, y - right.min(1), 0)\n",
" shift = gap + left.max(\"x\") - right.min(\"x\")\n",
" right.at(shift, y - right.min(\"y\"), 0)\n",
" if i < n - 1:\n",
" ceil_x.append(right.max(0))\n",
" x = right.max(0) + gap\n",
" max_y = right.max(1) + gap\n",
" ceil_x.append(right.max(\"x\"))\n",
" x = right.max(\"x\") + gap\n",
" max_y = right.max(\"y\") + gap\n",
" for i, x in enumerate(ceil_x):\n",
" z = max_y if i % 2 == 0 else max_y + gap\n",
" ceil = scene.add(\"card\").rotate(-90, \"z\").at(x, z, 0)\n",
" _y = max(_y, ceil.max(1))\n",
" _y = max(_y, ceil.max(\"y\"))\n",
" return _x, _y + gap\n",
"\n",
"\n",
Expand Down
168 changes: 168 additions & 0 deletions examples/domino.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"id": "834a079d-fb9f-43e1-95b3-1e373a7096fa",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"from frontend import App\n",
"\n",
"app = App.create(\"domino\")\n",
"V, F, T = (\n",
" app.mesh.cube(Nx=6, Ny=12, Nz=3, size_x=1, size_z=0.2).tetrahedralize().scale(0.3)\n",
")\n",
"app.asset.add.tet(\"block\", V, F, T)\n",
"scene = app.scene.create(\"domino\")\n",
"\n",
"R, minR, d, N, C = 2.5, 1.2, 0.3, 4096, 3\n",
"xz = None\n",
"for i in reversed(range(N)):\n",
" t = 2.0 * C * np.pi * i / N - np.pi / 2\n",
" r = (R - minR) * i / N + minR\n",
" angle = 180 * t / np.pi\n",
" x, z = -r * np.cos(t), r * np.sin(t)\n",
" if xz is None or np.linalg.norm(np.array([x, z]) - xz) > d:\n",
" scene.add(\"block\").at(x, 0, z).rotate(angle, \"y\")\n",
" xz = np.array([x, z])\n",
"\n",
"scene.add(\"block\").at(-0.15, 0.25, -R).rotate(90, \"y\").rotate(-20, \"z\")\n",
"\n",
"gap = app.session.param().get(\"contact-ghat\")\n",
"scene.add.invisible.wall([0, scene.min(\"y\") - 0.5 * gap, 0], [0, 1, 0])\n",
"\n",
"fixed = scene.build().report().shading(shading={\"flat\": True})\n",
"fixed.preview()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5e6f26d9-03d8-4e50-8315-7d41afbc8532",
"metadata": {},
"outputs": [],
"source": [
"param = app.session.param()\n",
"(\n",
" param.set(\"volume-young-mod\", 6000)\n",
" .set(\"volume-poiss-rat\", 0.49)\n",
" .set(\"friction\", 0.1)\n",
" .set(\"min-newton-steps\", 32)\n",
" .set(\"dt\", 0.01)\n",
" .set(\"fps\", 15)\n",
" .set(\"frames\", 180)\n",
")\n",
"\n",
"session = app.session.create(fixed)\n",
"session.start(param).preview()\n",
"session.stream()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f3755897-773b-4541-9d6b-61eca227a9f6",
"metadata": {},
"outputs": [],
"source": [
"session.animate()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7338acaa-f007-48c5-94a8-e481dd0f8cfc",
"metadata": {},
"outputs": [],
"source": [
"# this is for CI\n",
"assert session.finished()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "972f82eb-76bb-4cfc-9d4d-be3f7202131d",
"metadata": {},
"outputs": [],
"source": [
"if not app.CI:\n",
" # An extremely stiff case with a quadratic barrier\n",
" extreme_param = app.session.param()\n",
" (\n",
" extreme_param.set(\"volume-young-mod\", 1e5)\n",
" .set(\"volume-poiss-rat\", 0.499)\n",
" .set(\"friction\", 0.1)\n",
" .set(\"frames\", 32)\n",
" .set(\"min-newton-steps\", 32)\n",
" .set(\"dt\", 0.01)\n",
" .set(\"fps\", 15)\n",
" .set(\"barrier\", \"quad\")\n",
" )\n",
" quad_session = app.session.create(fixed)\n",
" quad_session.start(extreme_param).preview()\n",
" quad_session.stream()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5c494187-2705-4ce5-abb9-a91f6ce1da33",
"metadata": {},
"outputs": [],
"source": [
"if not app.CI:\n",
" quad_session.animate()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "257072c9-f606-494b-b571-3b1d3f9646eb",
"metadata": {},
"outputs": [],
"source": [
"if not app.CI:\n",
" # The same extremely stiff case with our cubic barrier\n",
" extreme_param.set(\"barrier\", \"cubic\")\n",
" cubic_session = app.session.create(fixed)\n",
" cubic_session.start(extreme_param).preview()\n",
" cubic_session.stream()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5e00dfda-8e70-465c-a60d-0055fce1af31",
"metadata": {},
"outputs": [],
"source": [
"if not app.CI:\n",
" cubic_session.animate()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
32 changes: 1 addition & 31 deletions examples/walkthrough.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -56,37 +56,7 @@
" app.mesh.preset(\"armadillo\").decimate(19000).tetrahedralize().normalize()\n",
")\n",
"app.asset.add.tet(\"armadillo-tet\", vert, tri, tet)\n",
"app.plot.create().tet(vert, tet, shading={\"flat\": True});"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ba25226c-0f20-4d67-9c3a-1970ffa610f3",
"metadata": {},
"outputs": [],
"source": [
"import numpy as np # noqa\n",
"\n",
"scene = app.scene.select(\"sample-scene\")\n",
"scene.clear()\n",
"obj = scene.add(\"armadillo-tet\").rotate(30, \"x\").velocity(0.01, 0, 0)\n",
"obj = (\n",
" scene.add(\"armadillo-tet\")\n",
" .rotate(180, \"x\")\n",
" .rotate(90, \"y\")\n",
" .rotate(45, \"z\")\n",
" .atop(obj, 0.1)\n",
" .pin()\n",
")\n",
"obj = scene.add(\"armadillo-tet\").atop(obj, 0.1)\n",
"\n",
"x = obj.vertex()\n",
"obj.pin(np.where(x[:, 0] < 0)[0]).move_by([0, 1, 0], 60)\n",
"\n",
"fixed = scene.build()\n",
"fixed.report()\n",
"fixed.preview()"
"app.plot.create().tet(vert, tet, shading={\"flat\": True})"
]
}
],
Expand Down
Loading

0 comments on commit 9a14f1d

Please sign in to comment.