Skip to content

Commit 2db8d56

Browse files
committed
add trajectory optimization tutorial
1 parent 774583a commit 2db8d56

File tree

3 files changed

+178
-0
lines changed

3 files changed

+178
-0
lines changed
982 KB
Loading
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# Trajectory Optimization
2+
3+
<div class="md-source-date"><small>Author: Zizhou Huang</small></div>
4+
5+
In this tutorial, we will demonstrate how to use polyfem to optimize the initial velocity of throwing a ball to match a given trajectory.
6+
7+
<p float="left">
8+
<img src="../sim.gif" width="60%" />
9+
</p>
10+
11+
The data for this tutorial can be found [here](https://github.com/polyfem/polyfem-data/tree/main/multi-material).
12+
13+
## Prerequisites
14+
15+
The following items are necessary to complete this tutorial. To replicate the experiment, you can feel free to use either the given mesh files or your own mesh.
16+
17+
- [ ] [Build PolyFEM](../../../cxx_index)
18+
- [ ] [Download File: square.obj](https://github.com/polyfem/polyfem-data/blob/main/contact/meshes/2D/simple/square.obj)
19+
- [ ] [Download File: circle.msh](https://github.com/polyfem/polyfem-data/blob/main/differentiable/circle.msh)
20+
- [ ] [Download File: barycenter-opt.json](https://github.com/polyfem/polyfem-data/blob/main/differentiable/optimizations/initial-condition-trajectory-opt/barycenter-opt.json)
21+
- [ ] [Download File: barycenter.json](https://github.com/polyfem/polyfem-data/blob/main/differentiable/optimizations/initial-condition-trajectory-opt/barycenter.json)
22+
- [ ] [Download File: barycenter-target.json](https://github.com/polyfem/polyfem-data/blob/main/differentiable/optimizations/initial-condition-trajectory-opt/barycenter-target.json)
23+
24+
### Build PolyFEM
25+
26+
The instructions for building PolyFEM can be found [here](../../../cxx_index).
27+
28+
Then you can use it by
29+
30+
```shell
31+
polyfem --help
32+
```
33+
34+
## Setting up the Optimization
35+
36+
We will setup the optimization using PolyFEM's JSON interface. For more details, please refer to the [JSON Input](../../../json) documentation.
37+
38+
We will only go over the JSON script for the optimization configuration, please refer to other tutorials for the JSON script for the simulation configuration.
39+
40+
### Parameters
41+
42+
```json
43+
{
44+
"parameters": [
45+
{
46+
"number": 2,
47+
"initial": [4, 0]
48+
}
49+
]
50+
}
51+
```
52+
53+
In `parameters`, we specify the dimension and initial guess of the variable to be optimized. Since we are going to optimize the initial velocity of a ball in 2D, the dimension is 2.
54+
55+
In more complex optimizations, where several types of parameters are optimized, the `parameters` can be a list of variables of different dimensions.
56+
57+
### States
58+
59+
```json
60+
{
61+
"states": [
62+
{
63+
"path": "barycenter.json"
64+
},
65+
{
66+
"path": "barycenter-target.json"
67+
}
68+
]
69+
}
70+
```
71+
72+
In `states`, we specify the path to the JSON files of simulations, they follow the same [rules](../../../json) for the simulation JSON scripts. PolyFEM will create a number of simulators, one for each JSON file, whose parameters can be optimized. During the optimization, certain parameters in these configurations are optimized, but the optimized values will not overwrite the values in these JSON files. Each simulator gets an ID starting from 0, following the order in this list. The ID of simulators may be used in `variable to simulation` and `functionals`.
73+
74+
Here we have two simulators: The first one is the simulator being optimized, while the second one is a fixed simulation that generates a reference trajectory. These JSON files are only for initializing the simulators, so one can use the same path for multiple simulators if possible.
75+
76+
### Variable to Simulation
77+
78+
```json
79+
{
80+
"variable_to_simulation": [
81+
{
82+
"type": "initial",
83+
"state": 0,
84+
"composition": [{
85+
"type": "append-values",
86+
"values": [0, 0]
87+
},{
88+
"type": "per-body-to-per-node",
89+
"state": 0
90+
},{
91+
"type": "append-const",
92+
"value": 0,
93+
"size": 146,
94+
"start": 0
95+
}]
96+
}
97+
]
98+
}
99+
```
100+
101+
In `variable to simulation`, we specify how the optimization variables in `parameters` control the simulation configurations. Since different types of parameters in a number of simulations can be controlled at the same time, the `variable to simulation` is a list, where each entry specifies the control of one type of parameter, e.g. initial condition, in one simulation. The `type` specifies the type of parameter in the simulation, and `state` points to the ID of the simulation (according to the order in `states`).
102+
103+
The initial condition parameter has a dimension of `2 * dim * n_basis`, where `dim` is the dimension of the simulation (2 or 3), `n_basis` is the number of finite element basis in the simulation, because it consists of the initial displacement and velocity at every basis node. This allows the user to specify the initial condition not only as a rigid body transformation, but also as an arbitrary deformation, e.g. stretching and shearing.
104+
105+
In this tutorial, we only optimize the initial velocity of the ball, so we need to build a mapping, which we call `composition` in the JSON script, from the variable of size 2 to the full initial condition parameter of size `2 * dim * n_basis`. The `composition` is a list of some pre-defined mappings, which will apply to the optimization variables in order, and the final output of the mappings will be assigned to the initial condition parameter.
106+
107+
There are two objects with different volume IDs, specified in `barycenter.json` and `barycenter-target.json`, and we only want to control the initial velocity of the ball, with volume ID 1. First, in `append-values` we append two zeros to the optimization variable, which represents the zero initial velocity of the floor. Second, in `per-body-to-per-node` we map the per-volume values to per-node, whose output has the dimension of `dim * n_basis`. Finally, in `append-const` we append more zeros to the start of the vector, to account for the zero initial displacement. Please refer to the [opt-input-spec.json](https://github.com/geometryprocessing/adjoint-polyfem/blob/shock/opt-input-spec.json) for the documentation of compositions.
108+
109+
### Functionals
110+
111+
```json
112+
{
113+
"functionals": [
114+
{
115+
"type": "transient_integral",
116+
"state": 0,
117+
"integral_type": "uniform",
118+
"static_objective":
119+
{
120+
"type": "center-target",
121+
"state": 0,
122+
"target_state": 1,
123+
"volume_selection": [1]
124+
}
125+
}
126+
]
127+
}
128+
```
129+
130+
The `functionals` specify the objective being minimized in the optimization. Please refer to [objective-input-spec.json](https://github.com/geometryprocessing/adjoint-polyfem/blob/shock/objective-input-spec.json) for the documentation of `functionals`.
131+
132+
Here we perform trajectory optimization on the ball, so the objective is the $L^2$ difference between the two ball barycenters in the two simulations, integrated over time.
133+
134+
```json
135+
{
136+
"type": "center-target",
137+
"state": 0,
138+
"target_state": 1,
139+
"volume_selection": [1]
140+
}
141+
```
142+
143+
The `center-target` computes the $L^2$ difference between the solutions in `state` and `target_state`, integrated over the space with `volume selection` ID 1. We assume that both simulators have the same number of basis and dimension on the same volume selection (number of basis on other volume selections can be different).
144+
145+
```json
146+
{
147+
"type": "transient_integral",
148+
"state": 0,
149+
"integral_type": "uniform",
150+
"static_objective": { ... }
151+
}
152+
```
153+
154+
The `transient integral` computes the integral over time of the `static objective`. The `integral type` and `state` specify the quadrature scheme and the simulator (the objective gets information like the number of time steps and dt from the simulator).
155+
156+
### Output
157+
158+
```json
159+
"output": {
160+
"solve_log_level": 3
161+
}
162+
```
163+
164+
The `output` contains options regarding the logging of the optimization, here `solve_log_level` specifies a log level of 3, corresponding to `warning`, for simulations so that we can focus more on the optimization logs.
165+
166+
### Solver
167+
168+
```json
169+
"solver": {
170+
"nonlinear": {
171+
"history_size": 2,
172+
"grad_norm": 1e-4
173+
}
174+
}
175+
```
176+
177+
The `solver` contains options of the nonlinear solver for the optimization. Since our forward problem and inverse problem share the same nonlinear solver code, the options of the inverse problem are the same as in the forward problem. However, since we can't compute the second order derivatives of the inverse problem, the Newton's method is not available here. By default the solver is [L-BFGS](https://github.com/yixuan/LBFGSpp), a quasi-Newton method using a limited amount of memory.

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ nav:
106106
- IPC Quick Start Guide: tutorials/ipc_quick_start_guide/ipc_quick_start_guide.md
107107
- Multi-Material: tutorials/multi-material/multi-material.md
108108
- Screwing a Bolt into a Nut: tutorials/screw/screw.md
109+
- Trajectory Optimization: tutorials/trajectory-optimization/trajectory-optimization.md
109110
- Robotics:
110111
- Pushing A Box: tutorials/sphere-pushing-box/sphere-pushing-box.md
111112
- Sling-shot: tutorials/sling-shot/sling-shot.md

0 commit comments

Comments
 (0)