Problems

Topology optimization problem to solve.

Base Problem

class topopt.problems.Problem(bc, penalty)[source]

Abstract topology optimization problem.

bc

The boundary conditions for the problem.

Type:BoundaryConditions
penalty

The SIMP penalty value.

Type:float
f

The right-hand side of the FEM equation (forces).

Type:numpy.ndarray
u

The variables of the FEM equation.

Type:numpy.ndarray
obje

The per element objective values.

Type:numpy.ndarray
__init__(bc, penalty)[source]

Create the topology optimization problem.

Parameters:
  • bc (BoundaryConditions) – The boundary conditions of the problem.
  • penalty (float) – The penalty value used to penalize fractional densities in SIMP.
compute_objective(xPhys, dobj)[source]

Compute objective and its gradient.

Parameters:
  • xPhys (ndarray) – The design variables.
  • dobj (ndarray) – The gradient of the objective to compute.
Returns:

The objective value.

Return type:

float

penalize_densities(x, drho=None)[source]

Compute the penalized densties (and optionally its derivative).

Parameters:
  • x (ndarray) – The density variables to penalize.
  • drho (Optional[ndarray]) – The derivative of the penealized densities to compute. Only set if drho is not None.
Returns:

The penalized densities used for SIMP.

Return type:

numpy.ndarray

Compliance Problem

class topopt.problems.ComplianceProblem(bc, penalty)[source]

Topology optimization problem to minimize compliance.

\(\begin{aligned} \min_{\boldsymbol{\rho}} \quad & \mathbf{f}^T\mathbf{u}\\ \textrm{subject to}: \quad & \mathbf{K}\mathbf{u} = \mathbf{f}\\ & \sum_{e=1}^N v_e\rho_e \leq V_\text{frac}, \quad 0 < \rho_\min \leq \rho_e \leq 1\\ \end{aligned}\)

where \(\mathbf{f}\) are the forces, \(\mathbf{u}\) are the displacements, \(\mathbf{K}\) is the striffness matrix, and \(V\) is the volume.

compute_objective(xPhys, dobj)[source]

Compute compliance and its gradient.

The objective is \(\mathbf{f}^{T} \mathbf{u}\). The gradient of the objective is

\(\begin{align} \mathbf{f}^T\mathbf{u} &= \mathbf{f}^T\mathbf{u} - \boldsymbol{\lambda}^T(\mathbf{K}\mathbf{u} - \mathbf{f})\\ \frac{\partial}{\partial \rho_e}(\mathbf{f}^T\mathbf{u}) &= (\mathbf{K}\boldsymbol{\lambda} - \mathbf{f})^T \frac{\partial \mathbf u}{\partial \rho_e} + \boldsymbol{\lambda}^T\frac{\partial \mathbf K}{\partial \rho_e} \mathbf{u} = \mathbf{u}^T\frac{\partial \mathbf K}{\partial \rho_e}\mathbf{u} \end{align}\)

where \(\boldsymbol{\lambda} = \mathbf{u}\).

Parameters:
  • xPhys (ndarray) – The element densities.
  • dobj (ndarray) – The gradient of compliance.
Returns:

The compliance value.

Return type:

float

Time-Harmonic Loads Problem

class topopt.problems.HarmonicLoadsProblem(bc, penalty)[source]

Topology optimization problem to minimize dynamic compliance.

Replaces standard forces with undamped forced vibrations.

\(\begin{aligned} \min_{\boldsymbol{\rho}} \quad & \mathbf{f}^T\mathbf{u}\\ \textrm{subject to}: \quad & \mathbf{S}\mathbf{u} = \mathbf{f}\\ & \sum_{e=1}^N v_e\rho_e \leq V_\text{frac}, \quad 0 < \rho_\min \leq \rho_e \leq 1\\ \end{aligned}\)

where \(\mathbf{f}\) is the amplitude of the load, \(\mathbf{u}\) is the amplitude of vibration, and \(\mathbf{S}\) is the system matrix (or “dynamic striffness” matrix) defined as

\(\begin{aligned} \mathbf{S} = \mathbf{K} - \omega^2\mathbf{M} \end{aligned}\)

where \(\omega\) is the angular frequency of the load, and \(\mathbf{M}\) is the global mass matrix.

__init__(bc, penalty)[source]

Create the topology optimization problem.

Parameters:
  • bc (BoundaryConditions) – The boundary conditions of the problem.
  • penalty (float) – The penalty value used to penalize fractional densities in SIMP.
build_M(xPhys, remove_constrained=True)[source]

Build the stiffness matrix for the problem.

Parameters:
  • xPhys (ndarray) – The element densisities used to build the stiffness matrix.
  • remove_constrained (bool) – Should the constrained nodes be removed?
Returns:

The stiffness matrix for the mesh.

Return type:

scipy.sparse.coo_matrix

build_indices()[source]

Build the index vectors for the finite element coo matrix format.

Return type:None
compute_displacements(xPhys)[source]

Compute the amplitude of vibration given the densities.

Compute the amplitude of vibration, \(\mathbf{u}\), using linear elastic finite element analysis (solving \(\mathbf{S}\mathbf{u} = \mathbf{f}\) where \(\mathbf{S} = \mathbf{K} - \omega^2\mathbf{M}\) is the system matrix and \(\mathbf{f}\) is the force vector).

Parameters:xPhys (ndarray) – The element densisities used to build the stiffness matrix.
Returns:The displacements solve using linear elastic finite element analysis.
Return type:numpy.ndarray
compute_objective(xPhys, dobj)[source]

Compute compliance and its gradient.

The objective is \(\mathbf{f}^{T} \mathbf{u}\). The gradient of the objective is

\(\begin{align} \mathbf{f}^T\mathbf{u} &= \mathbf{f}^T\mathbf{u} - \boldsymbol{\lambda}^T(\mathbf{K}\mathbf{u} - \mathbf{f})\\ \frac{\partial}{\partial \rho_e}(\mathbf{f}^T\mathbf{u}) &= (\mathbf{K}\boldsymbol{\lambda} - \mathbf{f})^T \frac{\partial \mathbf u}{\partial \rho_e} + \boldsymbol{\lambda}^T\frac{\partial \mathbf K}{\partial \rho_e} \mathbf{u} = \mathbf{u}^T\frac{\partial \mathbf K}{\partial \rho_e}\mathbf{u} \end{align}\)

where \(\boldsymbol{\lambda} = \mathbf{u}\).

Parameters:
  • xPhys (ndarray) – The element densities.
  • dobj (ndarray) – The gradient of compliance.
Returns:

The compliance value.

Return type:

float

static lm(nel)[source]

Build the element mass matrix.

\(M = \frac{1}{9 \times 4n}\begin{bmatrix} 4 & 0 & 2 & 0 & 1 & 0 & 2 & 0 \\ 0 & 4 & 0 & 2 & 0 & 1 & 0 & 2 \\ 2 & 0 & 4 & 0 & 2 & 0 & 1 & 0 \\ 0 & 2 & 0 & 4 & 0 & 2 & 0 & 1 \\ 1 & 0 & 2 & 0 & 4 & 0 & 2 & 0 \\ 0 & 1 & 0 & 2 & 0 & 4 & 0 & 2 \\ 2 & 0 & 1 & 0 & 2 & 0 & 4 & 0 \\ 0 & 2 & 0 & 1 & 0 & 2 & 0 & 4 \end{bmatrix}\)

Where \(n\) is the total number of elements. The total mass is equal to unity.

Parameters:nel (int) – The total number of elements.
Returns:The element mass matrix for the material.
Return type:numpy.ndarray

von Mises Stress Problem

class topopt.problems.VonMisesStressProblem(nelx, nely, penalty, bc, side=1)[source]

Topology optimization problem to minimize stress.

Todo

  • Currently this problem minimizes compliance and computes stress on the side. This needs to be replaced to match the promise of minimizing stress.
static B(side)[source]

Construct a strain-displacement matrix for a 2D regular grid.

\(B = \frac{1}{2s}\begin{bmatrix} 1 & 0 & -1 & 0 & -1 & 0 & 1 & 0 \\ 0 & 1 & 0 & 1 & 0 & -1 & 0 & -1 \\ 1 & 1 & 1 & -1 & -1 & -1 & -1 & 1 \end{bmatrix}\)

where \(s\) is the side length of the square elements.

Todo

  • Check that this is not -B
Parameters:side (float) – The side length of the square elements.
Returns:The strain-displacement matrix for a 2D regular grid.
Return type:numpy.ndarray
static E(nu)[source]

Construct a constitutive matrix for a 2D regular grid.

\(E = \frac{1}{1 - \nu^2}\begin{bmatrix} 1 & \nu & 0 \\ \nu & 1 & 0 \\ 0 & 0 & \frac{1 - \nu}{2} \end{bmatrix}\)

Parameters:nu – The Poisson’s ratio of the material.
Returns:The constitutive matrix for a 2D regular grid.
Return type:numpy.ndarray
__init__(nelx, nely, penalty, bc, side=1)[source]

Create the topology optimization problem.

Parameters:
  • bc – The boundary conditions of the problem.
  • penalty – The penalty value used to penalize fractional densities in SIMP.
build_dK(xPhys, remove_constrained=True)[source]
build_dK0(drho_xi, i, remove_constrained=True)[source]
compute_objective(xPhys, dobj)[source]

Compute compliance and its gradient.

compute_stress_objective(xPhys, dobj, p=4)[source]

Compute stress objective and its gradient.

static dsigma_pow(s11, s22, s12, ds11, ds22, ds12, p)[source]

Compute the gradient of the stress to the \(p^{\text{th}}\) power.

\(\nabla\sigma^p = \frac{p\sigma^{p-1}}{2\sigma}\nabla(\sigma^2)\)

Todo

  • Properly document what the sigma variables represent.
  • Rename the sigma variables to something more readable.
Parameters:
  • s11 (ndarray) – \(\sigma_{11}\)
  • s22 (ndarray) – \(\sigma_{22}\)
  • s12 (ndarray) – \(\sigma_{12}\)
  • ds11 (ndarray) – \(\nabla\sigma_{11}\)
  • ds22 (ndarray) – \(\nabla\sigma_{22}\)
  • ds12 (ndarray) – \(\nabla\sigma_{12}\)
  • p (float) – The power (\(p\)) to raise the von Mises stress.
Returns:

The gradient of the von Mises stress to the \(p^{\text{th}}\) power.

Return type:

numpy.ndarray

static sigma_pow(s11, s22, s12, p)[source]

Compute the von Mises stress raised to the \(p^{\text{th}}\) power.

\(\sigma^p = \left(\sqrt{\sigma_{11}^2 - \sigma_{11}\sigma_{22} + \sigma_{22}^2 + 3\sigma_{12}^2}\right)^p\)

Todo

  • Properly document what the sigma variables represent.
  • Rename the sigma variables to something more readable.
Parameters:
  • s11 (ndarray) – \(\sigma_{11}\)
  • s22 (ndarray) – \(\sigma_{22}\)
  • s12 (ndarray) – \(\sigma_{12}\)
  • p (float) – The power (\(p\)) to raise the von Mises stress.
Returns:

The von Mises stress to the \(p^{\text{th}}\) power.

Return type:

numpy.ndarray

test_calculate_objective(xPhys, dobj, p=4, dx=1e-06)[source]

Calculate the gradient of the stresses using finite differences.

Parameters:
  • xPhys (ndarray) – The element densities.
  • dobj (ndarray) – The gradient of the stresses to compute.
  • p (float) – The exponent for computing the softmax of the stresses.
  • dx (float) – The difference in x values used for finite differences.
Returns:

The analytic objective value.

Return type:

float