Skip to content

A contact solver for physics-based simulations involving ๐Ÿ‘š shells, ๐Ÿชต solids and ๐Ÿชข rods.

License

Notifications You must be signed in to change notification settings

st-tech/ppf-contact-solver

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

ZOZO's Contact Solver ๐Ÿซถ

A contact solver for physics-based simulations involving ๐Ÿ‘š shells, ๐Ÿชต solids and ๐Ÿชข rods. All made by ZOZO. Published in ACM Transactions on Graphics (TOG).

Getting Started All Examples Python API Docs Docker Build

solver logo

โœจ Highlights

  • ๐Ÿ’ช Robust: Contact resolutions are penetration-free. No snagging intersections.
  • โฒ Scalable: An extreme case includes beyond 150M contacts. Not just one million.
  • ๐Ÿšฒ Cache Efficient: All on the GPU runs in single precision. No double precision.
  • ๐Ÿฅผ Inextensible: Cloth never extends beyond very strict upper bounds, such as 1%.
  • ๐Ÿ“ Physically Accurate: Our deformable solver is driven by the Finite Element Method.
  • โš”๏ธ Highly Stressed: We run GitHub Actions to run stress tests 10 times in a row.
  • ๐Ÿš€ Massively Parallel: Both contact and elasticity solvers are run on the GPU.
  • ๐Ÿณ Docker Sealed: Everything is designed to work out of the box.
  • ๐ŸŒ JupyterLab Included: Open your browser and run examples right away [Video].
  • ๐Ÿ Documtened Python APIs: Our Python code is fully docstringed and lintable [Video].
  • โ˜๏ธ Cloud-Ready: Our solver can be seamlessly deployed on major cloud platforms.
  • โœจ Stay Clean: You can remove all traces after use.

๐Ÿ”– Table of Contents

๐Ÿ“š Advanced Contents

  • ๐Ÿง‘โ€๐Ÿ’ป Setting Up Your Development Environment [Markdown]
  • ๐Ÿž Bug Fixes and Updates [Markdown]

๐Ÿ“ Change History

๐ŸŽ“ Technical Materials

โšก๏ธ Requirements

  • ๐Ÿ”ฅ A modern NVIDIA GPU (Turing or newer)
  • ๐Ÿณ A Docker environment (see below)

๐Ÿ’จ Getting Started

Install a ๐ŸŽฎ NVIDIA driver [Link] on your ๐Ÿ’ป host system and follow the ๐Ÿ“ instructions below specific to the ๐Ÿ–ฅ๏ธ operating system to get a ๐Ÿณ Docker running:

๐Ÿง Linux ๐ŸชŸ Windows
Install the Docker engine from here [Link]. Also, install the NVIDIA Container Toolkit [Link]. Just to make sure that the Container Toolkit is loaded, run sudo service docker restart. Install the Docker Desktop [Link]. You may need to log out or reboot after the installation. After logging back in, launch Docker Desktop to ensure that Docker is running.

Next, run the following command to start the ๐Ÿ“ฆ container:

๐ŸชŸ Windows (PowerShell)

$MY_WEB_PORT = 8080  # Web port number for web interface
$IMAGE_NAME = "ghcr.io/st-tech/ppf-contact-solver-compiled:latest"
docker run --rm --gpus all -p ${MY_WEB_PORT}:8080 $IMAGE_NAME

๐Ÿง Linux (Bash/Zsh)

MY_WEB_PORT=8080  # Web port number for web interface
IMAGE_NAME=ghcr.io/st-tech/ppf-contact-solver-compiled:latest
docker run --rm --gpus all -p ${MY_WEB_PORT}:8080 $IMAGE_NAME

โณ Wait for a while until the container becomes a steady state. Next, open your ๐ŸŒ browser and navigate to http://localhost:8080, where 8080 is the port number specified in the MY_WEB_PORT variable. Keep your terminal window open.

๐ŸŽ‰ Now you are ready to go! ๐Ÿš€

๐Ÿ›‘ Shutting Down

To shut down the container, just press Ctrl+C in the terminal. The container will be removed and all traces will be ๐Ÿงน cleaned up.

๐Ÿ”ง Advanced Installation

If you wish to build the container from scratch ๐Ÿ› ๏ธ, please refer to the cleaner installation guide [Markdown] ๐Ÿ“.

๐Ÿ How To Use

Our frontend is accessible through ๐ŸŒ a browser using our built-in JupyterLab ๐Ÿ interface. All is set up when you open it for the first time. Results can be interactively viewed through the browser and exported as needed.

This allows you to interact with the simulator on your ๐Ÿ’ป laptop while the actual simulation runs on a remote headless server over ๐ŸŒ the internet. This means that you don't have to buy โš™๏ธ hardware, but can rent it at vast.ai or RunPod for less than ๐Ÿ’ต $1 per hour. For example, this [Video] was recorded on a vast.ai instance. The experience is ๐Ÿ‘ good!

Our Python interface is designed with the following principles in mind:

  • ๐Ÿ› ๏ธ Dynamic Tri/Tet Creation: Relying on non-integrated third-party tools for triangulation, tetrahedralization, and loading can make it difficult to dynamically adjust resolutions. Our built-in tri/tet creation tools eliminate this issue.

  • ๐Ÿšซ No Mesh Data: Preparing mesh data using external tools can be cumbersome. Our frontend minimizes this effort by allowing meshes to be created on the fly or downloaded when needed.

  • ๐Ÿ”— Method Chaining: We adopt the method chaining style from JavaScript, making the API intuitive and easy to understand.

  • ๐Ÿ“ฆ Single Import for Everything: All frontend features are accessible by simply importing with from frontend import App.

Here's an example of draping five sheets over a sphere with two corners pinned. Please look into the examples directory for more examples.

# import our frontend
from frontend import App

# make an app with the label "drape"
app = App("drape", renew=True)

# create a square mesh resolution 128 spanning the xz plane
V, F = app.mesh.square(res=128, ex=[1,0,0], ey=[0,0,1])

# add to the asset and name it "sheet"
app.asset.add.tri("sheet", V, F)

# create an icosphere mesh radius 0.5 and 5 subdivisions
V, F = app.mesh.icosphere(r=0.5, subdiv_count=5)

# add to the asset and name it "sphere"
app.asset.add.tri("sphere", V, F)

# create a scene "five-sheets"
scene = app.scene.create("five-sheets")

# define gap between sheets
gap = 0.01

for i in range(5):
    
    # add a sheet to the scene
    obj = scene.add("sheet")

    # pick two vertices max towards directions [1,0,-1] and [-1,0,-1]
    corner = obj.grab([1, 0, -1]) + obj.grab([-1, 0, -1])

    # place it with a vertical offset and pin the corners
    obj.at(0, gap * i, 0).pin(corner)

    # set fiber directions required for the Baraff-Witkin model
    obj.direction([1, 0, 0], [0, 0, 1])

# add a sphere mesh at a lower position and set it to a static collider
scene.add("sphere").at(0, -0.5 - gap, 0).pin()

# compile the scene and report stats
fixed = scene.build().report()

# interactively preview the built scene (image left)
fixed.preview()

# set simulation parameter(s)
param = app.session.param()
param.set("dt", 0.01)

# create a new session with the built scene
session = app.session.create(fixed)

# start the simulation and live-preview the results (image right)
session.start(param).preview()

# also show streaming logs
session.stream()

# or interactively view the animation sequences
session.animate()

# export all simulated frames and zip them
path = f"export/{scene.info.name}/{session.info.name}"
session.export.animation(path).zip()

drape

๐Ÿ“š Python APIs and Parameters

  • Full API documentation ๐Ÿ“– is available on our GitHub Pages. The major APIs are documented using docstrings โœ๏ธ and compiled with Sphinx โš™๏ธ. We have also included jupyter-lsp to provide interactive linting assistance ๐Ÿ› ๏ธ and display docstrings as you type. See this video [Video] for an example. The behaviors can be changed through the settings.

  • A list of parameters used in param.set(key,value) is documented here [GitHub Pages].

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 ๐Ÿงฎ.

# get a list of log names
logs = session.get.log.names()
assert 'time-per-frame' in logs
assert 'newton-steps' in logs

# get a list of time per video frame
msec_per_video = session.get.log.numbers('time-per-frame')

# compute the average time per video frame
print('avg per frame:', sum([n for _,n in msec_per_video])/len(msec_per_video))

# get a list of newton steps
newton_steps = session.get.log.numbers('newton-steps')

# compute the average of consumed newton steps
print('avg newton steps:', sum([n for _,n in newton_steps])/len(newton_steps))

Below are some representatives. vid_time refers to the video time in seconds and is recorded as float. ms refers to the consumed simulation time in milliseconds recorded as int. vid_frame is the video frame count recorede as int.

Name Description Format
time-per-frame Time per video frame list[(vid_frame,ms)]
matrix-assembly Matrix assembly time list[(vid_time,ms)]
pcg-linsolve Linear system solve time list[(vid_time,ms)]
line-search Line search time list[(vid_time,ms)]
time-per-step Time per step list[(vid_time,ms)]
newton-steps Newton iterations per step list[(vid_time,count)]
num-contact Contact count list[(vid_time,count)]
max-sigma Max stretch list(vid_time,float)

The full list of log names and their descriptions is documented here: [GitHub Pages].

Note that some entries have multiple records at the same video time โฑ๏ธ. This occurs because the same operation is executed multiple times ๐Ÿ”„ within a single step during the inner Newton's iterations ๐Ÿงฎ. For example, the linear system solve is performed at each Newton's step, so if multiple Newton's steps are ๐Ÿ” executed, multiple linear system solve times appear in the record at the same ๐Ÿ“Š video time.

If you would like to retrieve the raw log stream, you can do so by

# Last 8 lines. Omit for everything.
for line in session.get.log.stream(n_lines=8):
    print(line)

This will output something like:

* dt: 1.000e-03
* max_sigma: 1.045e+00
* avg_sigma: 1.030e+00
------ newton step 1 ------
   ====== contact_matrix_assembly ======
   > dry_pass...0 msec
   > rebuild...7 msec
   > fillin_pass...0 msec

If you would like to read stdout and stderr, you can do so using session.get.stdout() and session.get.stderr() (if it exists). They return list[str].

All the log files ๐Ÿ“‚ are available โœ… and can be fetched โฌ‡๏ธ during the simulation ๐Ÿง‘โ€๐Ÿ’ป.

๐Ÿ–ผ๏ธ Catalogue

woven stack [Video] trampoline [Video] needle [Video]
cards [Video] codim hang [Video] trapped
domino [Video] noodle drape [Video] twist [Video]
ribbon curtain [Video] fishingknot friction [Video]

At the moment, not all examples are ready yet, but they will be added/updated one by one. The author is actively woriking on it.

๐Ÿš€ GitHub Actions

We implemented GitHub Actions that test all of our examples. We perform explicit intersection checks ๐Ÿ” at the end of each step, which raises an error โŒ if an intersection is detected. This ensures that all steps are confirmed to be penetration-free if tests are pass โœ…. The runner types are described as follows:

Getting Started

The tested ๐Ÿš€ runner of this action is the Ubuntu NVIDIA GPU-Optimized Image for AI and HPC with an NVIDIA Tesla T4 (16 GB VRAM) with Driver version 550.127.05. This is not a self-hosted runner, meaning that each time the runner launches, all environments are ๐ŸŒฑ fresh.

All Examples

We use the GitHub-hosted runner ๐Ÿ–ฅ๏ธ, but the actual simulation runs on a provisioned vast.ai instance ๐ŸŒ. We do this for performance โšก and budget ๐Ÿ’ฐ reasons. We choose an RTX 4090 ๐ŸŽฎ, which typically costs less than $0.50 per hour ๐Ÿ’ต. Since we start with a fresh ๐ŸŒฑ instance, the environment is clean ๐Ÿงน every time. We take advantage of the ability to deploy on the cloud; this action is performed in parallel, which reduces the total action time.

โš”๏ธ Ten Consecutive Runs

We know that you can't judge the reliability of contact resolution by simply watching a success case in a single ๐ŸŽฅ video. To ensure greater transparency, we implemented GitHub Actions to run many of our examples via automated GitHub Actions โš™๏ธ, not just once, but 10 times in a row ๐Ÿ”. This means that a single failure out of 10 tests is considered a failure of the entire test suite!

drape.ipynb cards.ipynb curtain.ipynb friction.ipynb hang.ipynb needle.ipynb stack.ipynb trampoline.ipynb trapped.ipynb twist.ipynb domino.ipynb

Also, we apply small jitters to the position of objects in the scene ๐Ÿ”„, so at each run, the scene is slightly different.

โš ๏ธ Disclaimer

Our long stress tests can fail due to following reasons:

  • 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 ๐Ÿ‘‰.
  • Occasionally, we experience vast.ai instances shutting down before simulations finish.

๐Ÿ“ก Deploying on Cloud Services

Our contact solver is designed for heavy use in cloud services โ˜๏ธ, enabling us to:

  • ๐Ÿ’ฐ Cost-Effective Development: Quickly deploy testing environments ๐Ÿš€ and delete ๐Ÿ—‘๏ธ them when not in use, saving costs.
  • ๐Ÿ“ˆ Flexible Scalability: Scale as needed based on demand ๐Ÿ“ˆ. For example, you can launch multiple instances before a specific deadline โฐ.
  • ๐ŸŒ High Accessibility: Allow anyone with an internet connection ๐ŸŒ to try our solver, even on a smartphone ๐Ÿ“ฑ or tablet ๐Ÿ–ฅ๏ธ.
  • ๐Ÿ› Easier Bug Tracking: Users and developers can easily share the same hardware, kernel, and driver environment, making it easier to track and fix bugs.

This is all made possible with our purely web-based frontends ๐ŸŒ and scalable capability ๐Ÿงฉ. Our main target is the NVIDIA L4 ๐Ÿ–ฑ๏ธ, a data-center-targeted GPU ๐Ÿ–ฅ๏ธ that offers reasonable pricing ๐Ÿ’ฒ, delivering both practical performance ๐Ÿ’ช and scalability ๐Ÿ“Š without investing in expensive hardware ๐Ÿ’ป.

Below, we describe how to deploy our solver on major cloud services โ˜๏ธ. These instructions are up to date as of late 2024 ๐Ÿ“… and are subject to change ๐Ÿ”„.

Important: For all the services below, don't forget to โŒ delete the instance after use, or youโ€™ll be ๐Ÿ’ธ charged for nothing.

๐Ÿ“ฆ Deploying on vast.ai

  • Select our template [Link].
  • Create an instance and click Open button.

๐Ÿ“ฆ Deploying on RunPod

  • Follow this link [Link] and deploy an instance using our template.
  • Click Connect button and open the HTTP Services link.

๐Ÿ“ฆ Deploying on Scaleway

  • Set zone to fr-par-2
  • Select type L4-1-24G or GPU-3070-S
  • Choose Ubuntu Jammy GPU OS 12
  • Do not skip the Docker container creation in the installation process; it is required.
  • This setup costs approximately โ‚ฌ0.76 per hour.
  • CLI instructions are described in [Markdown].

๐Ÿ“ฆ Deploying on Amazon Web Services

  • Amazon Machine Image (AMI): Deep Learning Base OSS Nvidia Driver GPU AMI (Ubuntu 22.04)
  • Instance Type: g6.2xlarge (Recommended)
  • This setup costs around $1 per hour.
  • Do not skip the Docker container creation in the installation process; it is required.

๐Ÿ“ฆ Deploying on Google Compute Engine

  • Select GPUs. We recommend the GPU type NVIDIA L4 because it's affordable and accessible, as it does not require a high quota. You may select T4 instead for testing purposes.

  • Do not check Enable Virtual Workstation (NVIDIA GRID).

  • We recommend the machine type g2-standard-8.

  • Choose the OS type Deep Learning VM with CUDA 11.8 M126 and set the disk size to 50GB.

  • As of late 2024, this configuration costs approximately $0.86 per hour in us-central1 (Iowa) and $1.00 per hour in asia-east1 (Taiwan).

  • Port number 8080 is reserved by the OS image. Set $MY_WEB_PORT to 8888. When connecting via gcloud, use the following format: gcloud compute ssh --zone "xxxx" "instance-name" -- -L 8080:localhost:8888.

  • Do not skip the Docker container creation in the installation process; it is required.

  • CLI instructions are described in [Markdown].

๐Ÿ™ Acknowledgements

The author would like to thank ZOZO, Inc. for allowing him to work on this topic as part of his main workload. The author also extends thanks to the teams in the IP department for permitting the publication of our technical work and the release of our code, as well as to many others for assisting with the internal paperwork required for publication.

๐Ÿ–‹ Citation

@article{Ando2024CB,
    author = {Ando, Ryoichi},
    title = {A Cubic Barrier with Elasticity-Inclusive Dynamic Stiffness},
    year = {2024},
    issue_date = {December 2024},
    publisher = {Association for Computing Machinery},
    address = {New York, NY, USA},
    volume = {43},
    number = {6},
    issn = {0730-0301},
    url = {https://doi.org/10.1145/3687908},
    doi = {10.1145/3687908},
    journal = {ACM Trans. Graph.},
    month = nov,
    articleno = {224},
    numpages = {13},
    keywords = {collision, contact}
}

It should be emphasized that this work was strongly inspired by the IPC. The author kindly encourages citing their original work as well.

About

A contact solver for physics-based simulations involving ๐Ÿ‘š shells, ๐Ÿชต solids and ๐Ÿชข rods.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages