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

34 KiB

In [1]:
import numpy as np
import torch
import igl
import time

import meshplot as mp
import sys as _sys
_sys.path.append("../src")
from elasticenergy import *
from elasticsolid import *
from adjoint_sensitivity import *
from vis_utils import *
from objectives import *
from harmonic_interpolator import *
from shape_optimizer import *

from utils import *

shadingOptions = {
    "flat":True,
    "wireframe":False,   
}

rot = np.array(
    [[1, 0, 0 ],
     [0, 0, 1],
     [0, -1, 0 ]]
)

torch.set_default_dtype(torch.float64)

def to_numpy(tensor):
    return tensor.detach().clone().numpy()

Create the deformed object

Load the mesh

In [2]:
vNP, _, _, tNP, _, _ = igl.read_obj("../data/beam.obj")

aabb = np.max(vNP, axis=0) - np.min(vNP, axis=0)
length_scale = np.mean(aabb)


v, t  = torch.tensor(vNP), torch.tensor(tNP)
eNP   = igl.edges(tNP)
beNP  = igl.edges(igl.boundary_facets(tNP))

def get_boundary_and_interior(vlen, t):
    bv = np.unique(igl.boundary_facets(t))
    vIdx  = np.arange(vlen)
    iv  = vIdx[np.invert(np.in1d(vIdx, bv))]
    return bv, iv
# Compute boundary vertices and interior vertex indices
bvNP, ivNP  = get_boundary_and_interior(v.shape[0], tNP)

mp.plot(vNP @ rot.T, np.array(tNP), shading=shadingOptions)
Out [2]:
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(5.0, 1.0,…
<meshplot.Viewer.Viewer at 0x7f4f18719760>

Add some physical characteristics

In [3]:
rho     = 131 # [kg.m-3]
damping = 0.
young   = 5e7 # [Pa] 
poisson = 0.2

# Find some of the lowest vertices and pin them
minX    = torch.min(v[:, 0])
pin_idx = torch.arange(v.shape[0])[v[:, 0] < minX + 0.2*aabb[0]]
vIdx  = np.arange(v.shape[0])
pin_idx  = vIdx[np.in1d(vIdx, bvNP) & np.in1d(vIdx, pin_idx)]
print("Pinned vertices: {}".format(pin_idx))
Pinned vertices: [ 0  1 11 12 22 23 33 34 44 54 55 75 76 86 87 88 89]

Initial guess

The idea is that we start deforming the mesh by inverting gravity.

In [4]:
# Inverted gravity
force_mass = torch.zeros(size=(3,))
force_mass[2] = + rho * 9.81

# Gravity going in the wrong direction

ee = NeoHookeanElasticEnergy(young, poisson)

v = HarmonicInterpolator(v, t, ivNP).interpolate(v[bvNP])
solid_init = ElasticSolid(v, t, ee, rho=rho, pin_idx=pin_idx, f_mass=force_mass)

solid_init.find_equilibrium()
plot_torch_solid(solid_init, beNP, rot, length_scale)

# Use these as initial guesses
v_init_rest = solid_init.v_def.clone().detach()
v_init_def  = solid_init.v_rest.clone().detach()

# v_init_rest = solid_init.v_rest.clone().detach()
# v_init_def  = solid_init.v_def.clone().detach()
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(4.9017367…

Inverse design

In [5]:
force_mass = torch.zeros(size=(3,))
force_mass[2] = - rho * 9.81
use_linear  = False

# The target is the initial raw mesh
vt_surf = torch.tensor(vNP[bvNP, :])

# Create solid
if use_linear:
    ee      = LinearElasticEnergy(young, poisson)
else:
    ee      = NeoHookeanElasticEnergy(young, poisson)
solid_      = ElasticSolid(v_init_rest, t, ee, rho=rho, pin_idx=pin_idx, f_mass=force_mass)
solid_.update_def_shape(v_init_def)

optimizer = ShapeOptimizer(solid_, vt_surf, weight_reg=10.)

v_eq_init    = optimizer.solid.v_def.clone().detach() #bookkeeping
Initial objective: 1.6230e+00

In [6]:
optimizer.optimize(step_size_init=1e-2, max_l_iter=10, n_optim_steps=40)
Objective after 40 optimization step(s): 1.5788e+00
    Line search Iters: 9
Elapsed time: 97.1s. 
Estimated remaining time: 0.0s

Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(5.0444669…
In [7]:
import matplotlib.pyplot as plt

plt.figure(figsize=(10, 6))
plt.plot(to_numpy(optimizer.objectives[optimizer.objectives > 0]))
plt.title("Objective as optimization goes", fontsize=14)
plt.xlabel("Optimization steps", fontsize=12)
plt.ylabel("Objective", fontsize=12)
plt.grid()
plt.show()

Green (Initial guess for rest state) deploys to Black

Blue (Optimized rest state) deploys to Yellow

Red is the Target Shape

In [8]:
p = mp.plot(np.array(optimizer.solid.v_def) @ rot.T, tNP, shading=shadingOptions)
# p.add_points(np.array(optimizer.solid.v_def)[pin_idx, :] @ rot.T, shading={"point_color":"black", "point_size": 0.2})
p.add_edges(np.array(v_init_rest) @ rot.T, beNP, shading={"line_color": "green"})
p.add_edges(vNP @ rot.T, beNP, shading={"line_color": "red"})
p.add_edges(np.array(v_eq_init) @ rot.T, beNP, shading={"line_color": "black"})
p.add_edges(np.array(optimizer.solid.v_rest) @ rot.T, beNP, shading={"line_color": "blue"})
Out [8]:
Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(5.0444669…
4
In [9]:
v_rest_optim_g = optimizer.solid.v_rest.clone().detach() #bookkeeping

Add point load to the right most vertices

In [10]:
maxX        = torch.min(v[:, 0])
f_point_idx = torch.arange(v.shape[0])[v[:, 0] > maxX - 0.01*aabb[0]]

f_point = torch.zeros(size=(f_point_idx.shape[0], 3))
f_point[:, 2] = -5e4

optimizer.solid.add_point_load(f_point_idx, f_point)
optimizer.set_params(optimizer.params)
v_def_optim_g_under_point = optimizer.solid.v_def.clone().detach() #bookkeeping
In [ ]:
optimizer.reset_BFGS()
optimizer.optimize(step_size_init=1e-2, max_l_iter=10, n_optim_steps=100)
Objective after 21 optimization step(s): 2.2335e+01
    Line search Iters: 9
Elapsed time: 2215.2s. 
Estimated remaining time: 8333.3s

Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(5.0945925…

Green (Optimum rest state under gravity) deploys to Black with the additional point load

Blue (Optimized rest state) deploys to Yellow

Red is the Target Shape

In [ ]:
p = mp.plot(np.array(optimizer.solid.v_def) @ rot.T, tNP, shading=shadingOptions)
# p.add_points(np.array(optimizer.solid.v_def)[pin_idx, :] @ rot.T, shading={"point_color":"black", "point_size": 0.2})
p.add_edges(np.array(v_rest_optim_g) @ rot.T, beNP, shading={"line_color": "green"})
p.add_edges(vNP @ rot.T, beNP, shading={"line_color": "red"})
p.add_edges(np.array(v_def_optim_g_under_point) @ rot.T, beNP, shading={"line_color": "black"})
p.add_edges(np.array(optimizer.solid.v_rest) @ rot.T, beNP, shading={"line_color": "blue"})