epfl-archive/cs457-gc/assignment_2_4/notebook/inverse_design_beam.ipynb
2022-04-07 18:46:57 +02:00

484 lines
34 KiB
Plaintext

{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import torch\n",
"import igl\n",
"import time\n",
"\n",
"import meshplot as mp\n",
"import sys as _sys\n",
"_sys.path.append(\"../src\")\n",
"from elasticenergy import *\n",
"from elasticsolid import *\n",
"from adjoint_sensitivity import *\n",
"from vis_utils import *\n",
"from objectives import *\n",
"from harmonic_interpolator import *\n",
"from shape_optimizer import *\n",
"\n",
"from utils import *\n",
"\n",
"shadingOptions = {\n",
" \"flat\":True,\n",
" \"wireframe\":False, \n",
"}\n",
"\n",
"rot = np.array(\n",
" [[1, 0, 0 ],\n",
" [0, 0, 1],\n",
" [0, -1, 0 ]]\n",
")\n",
"\n",
"torch.set_default_dtype(torch.float64)\n",
"\n",
"def to_numpy(tensor):\n",
" return tensor.detach().clone().numpy()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Create the deformed object\n",
"\n",
"## Load the mesh"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"scrolled": false
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "732bc7276b654a1db0b501b750c8fd87",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(5.0, 1.0,…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"<meshplot.Viewer.Viewer at 0x7f4f18719760>"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vNP, _, _, tNP, _, _ = igl.read_obj(\"../data/beam.obj\")\n",
"\n",
"aabb = np.max(vNP, axis=0) - np.min(vNP, axis=0)\n",
"length_scale = np.mean(aabb)\n",
"\n",
"\n",
"v, t = torch.tensor(vNP), torch.tensor(tNP)\n",
"eNP = igl.edges(tNP)\n",
"beNP = igl.edges(igl.boundary_facets(tNP))\n",
"\n",
"def get_boundary_and_interior(vlen, t):\n",
" bv = np.unique(igl.boundary_facets(t))\n",
" vIdx = np.arange(vlen)\n",
" iv = vIdx[np.invert(np.in1d(vIdx, bv))]\n",
" return bv, iv\n",
"# Compute boundary vertices and interior vertex indices\n",
"bvNP, ivNP = get_boundary_and_interior(v.shape[0], tNP)\n",
"\n",
"mp.plot(vNP @ rot.T, np.array(tNP), shading=shadingOptions)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Add some physical characteristics"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Pinned vertices: [ 0 1 11 12 22 23 33 34 44 54 55 75 76 86 87 88 89]\n"
]
}
],
"source": [
"rho = 131 # [kg.m-3]\n",
"damping = 0.\n",
"young = 5e7 # [Pa] \n",
"poisson = 0.2\n",
"\n",
"# Find some of the lowest vertices and pin them\n",
"minX = torch.min(v[:, 0])\n",
"pin_idx = torch.arange(v.shape[0])[v[:, 0] < minX + 0.2*aabb[0]]\n",
"vIdx = np.arange(v.shape[0])\n",
"pin_idx = vIdx[np.in1d(vIdx, bvNP) & np.in1d(vIdx, pin_idx)]\n",
"print(\"Pinned vertices: {}\".format(pin_idx))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Initial guess\n",
"\n",
"The idea is that we start deforming the mesh by inverting gravity."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"scrolled": false
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "f4fe02d4e90b47cea101747098c5b3bd",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(4.9017367…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Inverted gravity\n",
"force_mass = torch.zeros(size=(3,))\n",
"force_mass[2] = + rho * 9.81\n",
"\n",
"# Gravity going in the wrong direction\n",
"\n",
"ee = NeoHookeanElasticEnergy(young, poisson)\n",
"\n",
"v = HarmonicInterpolator(v, t, ivNP).interpolate(v[bvNP])\n",
"solid_init = ElasticSolid(v, t, ee, rho=rho, pin_idx=pin_idx, f_mass=force_mass)\n",
"\n",
"solid_init.find_equilibrium()\n",
"plot_torch_solid(solid_init, beNP, rot, length_scale)\n",
"\n",
"# Use these as initial guesses\n",
"v_init_rest = solid_init.v_def.clone().detach()\n",
"v_init_def = solid_init.v_rest.clone().detach()\n",
"\n",
"# v_init_rest = solid_init.v_rest.clone().detach()\n",
"# v_init_def = solid_init.v_def.clone().detach()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Inverse design\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"scrolled": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Initial objective: 1.6230e+00\n",
"\n"
]
}
],
"source": [
"force_mass = torch.zeros(size=(3,))\n",
"force_mass[2] = - rho * 9.81\n",
"use_linear = False\n",
"\n",
"# The target is the initial raw mesh\n",
"vt_surf = torch.tensor(vNP[bvNP, :])\n",
"\n",
"# Create solid\n",
"if use_linear:\n",
" ee = LinearElasticEnergy(young, poisson)\n",
"else:\n",
" ee = NeoHookeanElasticEnergy(young, poisson)\n",
"solid_ = ElasticSolid(v_init_rest, t, ee, rho=rho, pin_idx=pin_idx, f_mass=force_mass)\n",
"solid_.update_def_shape(v_init_def)\n",
"\n",
"optimizer = ShapeOptimizer(solid_, vt_surf, weight_reg=10.)\n",
"\n",
"v_eq_init = optimizer.solid.v_def.clone().detach() #bookkeeping"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Objective after 40 optimization step(s): 1.5788e+00\n",
" Line search Iters: 9\n",
"Elapsed time: 97.1s. \n",
"Estimated remaining time: 0.0s\n",
"\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "10cffc9c94334b8aa1529d4b6fb36278",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(5.0444669…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"optimizer.optimize(step_size_init=1e-2, max_l_iter=10, n_optim_steps=40)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 720x432 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"import matplotlib.pyplot as plt\n",
"\n",
"plt.figure(figsize=(10, 6))\n",
"plt.plot(to_numpy(optimizer.objectives[optimizer.objectives > 0]))\n",
"plt.title(\"Objective as optimization goes\", fontsize=14)\n",
"plt.xlabel(\"Optimization steps\", fontsize=12)\n",
"plt.ylabel(\"Objective\", fontsize=12)\n",
"plt.grid()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Green (Initial guess for rest state) deploys to Black\n",
"\n",
"Blue (Optimized rest state) deploys to Yellow\n",
"\n",
"Red is the Target Shape\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "cc0e6ec0eb174783a516c85f67697225",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(5.0444669…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"4"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"p = mp.plot(np.array(optimizer.solid.v_def) @ rot.T, tNP, shading=shadingOptions)\n",
"# p.add_points(np.array(optimizer.solid.v_def)[pin_idx, :] @ rot.T, shading={\"point_color\":\"black\", \"point_size\": 0.2})\n",
"p.add_edges(np.array(v_init_rest) @ rot.T, beNP, shading={\"line_color\": \"green\"})\n",
"p.add_edges(vNP @ rot.T, beNP, shading={\"line_color\": \"red\"})\n",
"p.add_edges(np.array(v_eq_init) @ rot.T, beNP, shading={\"line_color\": \"black\"})\n",
"p.add_edges(np.array(optimizer.solid.v_rest) @ rot.T, beNP, shading={\"line_color\": \"blue\"})\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"v_rest_optim_g = optimizer.solid.v_rest.clone().detach() #bookkeeping"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Add point load to the right most vertices\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"maxX = torch.min(v[:, 0])\n",
"f_point_idx = torch.arange(v.shape[0])[v[:, 0] > maxX - 0.01*aabb[0]]\n",
"\n",
"f_point = torch.zeros(size=(f_point_idx.shape[0], 3))\n",
"f_point[:, 2] = -5e4\n",
"\n",
"optimizer.solid.add_point_load(f_point_idx, f_point)\n",
"optimizer.set_params(optimizer.params)\n",
"v_def_optim_g_under_point = optimizer.solid.v_def.clone().detach() #bookkeeping"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Objective after 21 optimization step(s): 2.2335e+01\n",
" Line search Iters: 9\n",
"Elapsed time: 2215.2s. \n",
"Estimated remaining time: 8333.3s\n",
"\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "f0b258afc95d4bdf8e8bb0e3fb529d05",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(5.0945925…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"optimizer.reset_BFGS()\n",
"optimizer.optimize(step_size_init=1e-2, max_l_iter=10, n_optim_steps=100)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Green (Optimum rest state under gravity) deploys to Black with the additional point load\n",
"\n",
"Blue (Optimized rest state) deploys to Yellow\n",
"\n",
"Red is the Target Shape\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"p = mp.plot(np.array(optimizer.solid.v_def) @ rot.T, tNP, shading=shadingOptions)\n",
"# p.add_points(np.array(optimizer.solid.v_def)[pin_idx, :] @ rot.T, shading={\"point_color\":\"black\", \"point_size\": 0.2})\n",
"p.add_edges(np.array(v_rest_optim_g) @ rot.T, beNP, shading={\"line_color\": \"green\"})\n",
"p.add_edges(vNP @ rot.T, beNP, shading={\"line_color\": \"red\"})\n",
"p.add_edges(np.array(v_def_optim_g_under_point) @ rot.T, beNP, shading={\"line_color\": \"black\"})\n",
"p.add_edges(np.array(optimizer.solid.v_rest) @ rot.T, beNP, shading={\"line_color\": \"blue\"})\n"
]
}
],
"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.9.7"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": true,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}