Hencky (Logarithmic) Strain

The Hencky strain (or Logarithmic strain) is the natural logarithm of the stretch tensor. It is widely considered the “true” strain measure for large deformations because it possesses the property of additivity (strain increments can be summed).

Theory

The Hencky strain \(\mathbf{E}\) is defined via the spectral decomposition of the Right Cauchy-Green tensor \(\mathbf{C}\).

\[\mathbf{C} = \mathbf{F}^T \mathbf{F}\]
\[\mathbf{E}_{Hencky} = \frac{1}{2} \ln(\mathbf{C})\]

Since \(\ln(\mathbf{C})\) is a tensor logarithm, it is computed by solving the eigenvalue problem for \(\mathbf{C}\). If \(\lambda_i\) are the eigenvalues of \(\mathbf{C}\) (squared principal stretches), the principal Hencky strains are:

\[\varepsilon_i = \frac{1}{2} \ln(\lambda_i)\]

Python Implementation

Calculating the matrix logarithm using scipy.linalg.logm in a loop is computationally expensive. The preferred method is vectorized spectral decomposition.

import numpy as np

def compute_strain_logarithmic(disp_x, disp_y, dx, dy):
    """
    Compute Principal Hencky Strains (Logarithmic).

    Assumes indexing='ij' (axis 0 is x, axis 1 is y).
    """
    # 1. Compute Gradients
    grad_u = np.gradient(disp_x, dx, dy)
    du_dx, du_dy = grad_u[0], grad_u[1]

    grad_v = np.gradient(disp_y, dx, dy)
    dv_dx, dv_dy = grad_v[0], grad_v[1]

    # 2. Construct C Tensor Components (C = F.T @ F)
    # C11 = (1 + u_x)^2 + (v_x)^2
    C11 = (1.0 + du_dx)**2 + dv_dx**2

    # C22 = (u_y)^2 + (1 + v_y)^2
    C22 = du_dy**2 + (1.0 + dv_dy)**2

    # C12 = (1 + u_x)(u_y) + (v_x)(1 + v_y)
    C12 = (1.0 + du_dx)*du_dy + dv_dx*(1.0 + dv_dy)

    # 3. Assemble Tensor Field (m x n x 2 x 2)
    m, n = disp_x.shape
    C_tensor = np.zeros((m, n, 2, 2))
    C_tensor[..., 0, 0] = C11
    C_tensor[..., 1, 1] = C22
    C_tensor[..., 0, 1] = C12
    C_tensor[..., 1, 0] = C12

    # 4. Solve Eigenvalues (Vectorized)
    # eigvalsh is stable for symmetric matrices
    eigvals = np.linalg.eigvalsh(C_tensor)

    # 5. Compute Logarithmic Strain
    # Returns the two principal strains at each point
    eps_principal = 0.5 * np.log(eigvals)

    return eps_principal[..., 0], eps_principal[..., 1]

References