Problem definition
Suppose we are given the experimental data of one pair of strain \(\boldsymbol{\varepsilon}^*\) and stress \(\boldsymbol{\sigma}^*\) measurement of a specimen, and we are tasked to infer the bulk \(K\) and shear \(G\) modulus of the material.
Let us define the loss function as the distance between the stress prediction and the stress measurement, i.e.
\[
l(K, G) = \norm{\boldsymbol{\sigma}(\boldsymbol{\varepsilon}^*; K, G) - \boldsymbol{\sigma}^*}^2.
\]
The material parameters, \(K^*\) and \(G^*\), can then be "inferred" by minimizing the loss function
\[
\left( K^*, G^* \right) = \mathop{\mathrm{argmin}}\limits_{K, G} \ l.
\]
Calibration
The following Python script uses the simple gradient descent algorithm to find \(K^*\) and \(G^*\):
\begin{align*}
K_{i+1} &= K_i - \gamma \pdv{l}{K_i}, \\
G_{i+1} &= G_i - \gamma \pdv{l}{G_i},
\end{align*}
which iterates until the loss function \(l\) is sufficiently small. A constant learning rate \(\gamma = 1\) is chosen in this example.
import neml2
from neml2.tensors import SR2
import torch
from matplotlib import pyplot as plt
torch.set_default_dtype(torch.double)
strain_exp = SR2.fill(0.1, 0.05, -0.03, 0.02, 0.06, 0.03)
stress_exp = SR2.fill(2.616, 1.836, 0.588, 0.312, 0.9361, 0.468)
gamma = 1
loss_history = []
K_history = []
G_history = []
for i in range(100):
model.K.requires_grad_()
model.G.requires_grad_()
stress = model.value({"forces/E" : strain_exp})["state/S" ]
l = torch.linalg.norm(stress.torch() - stress_exp.torch()) ** 2
loss_history.append(l.item())
K_history.append(model.K.torch().item())
G_history.append(model.G.torch().item())
l.backward()
model.K = model.K.tensor().detach() - gamma * model.K.grad
model.G = model.G.tensor().detach() - gamma * model.G.grad
fig, axl = plt.subplots(figsize=(8, 5))
axl.plot(torch.arange(100), loss_history, "k-" )
axl.set_xscale("log" )
axl.set_yscale("log" )
axl.set_xlabel("Iteration" )
axl.set_ylabel("Loss" )
axp = axl.twinx()
axp.plot(torch.arange(100), K_history, "r--" , label="Bulk modulus" )
axp.plot(torch.arange(100), G_history, "b--" , label="Shear modulus" )
axp.set_ylabel("Parameter value" )
axp.legend()
fig.tight_layout()
fig.savefig("calibration.svg" )
std::shared_ptr< Model > load_model(const std::filesystem::path &path, const std::string &mname)
A convenient function to load an input file and get a model.
Definition Model.cxx:45
Material parameter calibration