epfl-archive/cs457-gc/assignment_2_4/notebook/inverse_design_beam.ipynb

484 lines
34 KiB
Plaintext
Raw Normal View History

2022-04-07 18:46:57 +02:00
{
"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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
"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
}