Skip to content

Commit

Permalink
Merge pull request #186 from proxystore/issue-140-rebased
Browse files Browse the repository at this point in the history
Add physics app based on Globus Compute golf demo
  • Loading branch information
gpauloski authored Dec 12, 2024
2 parents 65ad39e + 84328c3 commit 5070408
Show file tree
Hide file tree
Showing 8 changed files with 664 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/apps/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ These applications, summarized below, span many domains, datasets, and structure
| [MapReduce](mapreduce.md) | Text Analysis | Python Functions | File, In-memory |
| [Molecular Design](moldesign.md) | Molecular Design | Python Functions | In-memory |
| [Montage](montage.md) | Astronomy | Executable | File |
| [Physics](physics.md) | Physics | Python Functions | In-memory |
| [Synthetic](synthetic.md) | N/A | Python Functions | In-memory |

Check out the application specific guides for more information and instructions.
24 changes: 24 additions & 0 deletions docs/apps/physics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Physics Simulations

This application is modified from the [Globus Compute Golf Demo](https://github.com/globus-labs/globus-compute-golf-demo){target=_blank}.

Simulates the physics of golf balls landing on a randomly generated golf green using perlin noise for terrain generation and [pybullet3](https://github.com/bulletphysics/bullet3){target=_blank} for physics simulations.
This application is embarrassingly parallel---every ball is simulated in its own task.

## Installation

This application requires numpy, matplotlib, scipy, and pybullet3 which can be installed automatically when installing the TaPS package.
```bash
pip install -e .[physics]
```

## Example

The following command simulated 32 balls where each ball is simulated in a separate task.
```bash
python -m taps.run --app physics --app.simulations 32 --engine.executor process-pool
```
The initial and final ball positions are plotted and saved to `{run_dir}/images/`.
By default, the simulations run at "real time".
I.e., sleeps are added at each timestep to ensure timesteps take as long as they would in real life.
This can be disabled with `--app.real-time false`.
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ nav:
- MapReduce: apps/mapreduce.md
- Molecular Design: apps/moldesign.md
- Montage: apps/montage.md
- Physics: apps/physics.md
- Synthetic: apps/synthetic.md
- Guides:
- guides/index.md
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ docking = ["numpy", "pandas", "requests", "scikit-learn", "rdkit"]
fedlearn = ["numpy", "torch", "torchvision"]
moldesign = ["ase", "matplotlib", "numpy", "pandas", "rdkit==2023.9.6", "scikit-learn", "tqdm"]
montage = ["montage_wrapper", "pandas"]
physics = ["matplotlib", "noise", "numpy<2", "pybullet", "scipy"]
dev = [
"taps[cholesky,montage]",
"covdefaults>=2.2",
Expand Down Expand Up @@ -87,6 +88,7 @@ omit = [
"taps/apps/docking/*",
"taps/apps/fedlearn/*",
"taps/apps/moldesign/*",
"taps/apps/physics.py",
]
parallel = true

Expand Down
88 changes: 88 additions & 0 deletions taps/apps/configs/physics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
from __future__ import annotations

from typing import Literal
from typing import Optional

from pydantic import Field

from taps.apps import App
from taps.apps import AppConfig
from taps.plugins import register


@register('app')
class PhysicsConfig(AppConfig):
"""Physics application configuration."""

name: Literal['physics'] = Field(
'physics',
description='Application name.',
)
simulations: int = Field(description='Number of parallel simulations.')
ball_diameter: float = Field(
0.2,
description='Golf ball diameter in meters.',
)
ball_mass: float = Field(0.05, description='Golf ball mass in kilograms.')
tick_rate: int = Field(240, description='Simulation steps per seconds.')
total_time: int = Field(10, description='Simulation runtime in seconds.')
real_time: bool = Field(True, description='Simulate at real time.')
seed: Optional[int] = Field(None, description='Random seed.') # noqa: UP007
terrain_width: int = Field(
20,
description='Terrain width/length in meters.',
)
terrain_height: int = Field(3, description='Terrain max height in meters.')
terrain_resolution: int = Field(
10,
description='Terrain vertices per meter.',
)
terrain_scale: float = Field(
10.0,
description='Noise map scale (how far away map is viewed from).',
)
terrain_octaves: int = Field(3, description='Detail level in noise map.')
terrain_persistence: float = Field(
0.2,
description='Octave contributions (amplitude).',
)
terrain_lacunarity: float = Field(
2.0,
description='Detail added/removed at each octave (frequency).',
)
terrain_filter_size: int = Field(
2,
description='Terrain smoothing filter size.',
)

def get_app(self) -> App:
"""Create an application instance from the config."""
from taps.apps.physics import PhysicsApp
from taps.apps.physics import SimulationConfig
from taps.apps.physics import TerrainConfig

terrain = TerrainConfig(
width=self.terrain_width,
height=self.terrain_height,
resolution=self.terrain_resolution,
scale=self.terrain_scale,
octaves=self.terrain_octaves,
persistence=self.terrain_persistence,
lacunarity=self.terrain_lacunarity,
filter_size=self.terrain_filter_size,
)

simulation = SimulationConfig(
ball_diameter=self.ball_diameter,
ball_mass=self.ball_mass,
tick_rate=self.tick_rate,
total_time=self.total_time,
real_time=self.real_time,
)

return PhysicsApp(
num_simulations=self.simulations,
terrain=terrain,
simulation=simulation,
seed=self.seed,
)
Loading

0 comments on commit 5070408

Please sign in to comment.