Source code for topopt.filters

"""Filter the solution to topology optimization."""
from __future__ import division

# Import standard library
import abc

# Import modules
import numpy
import scipy


[docs]class Filter(abc.ABC): """Filter solutions to topology optimization to avoid checker boarding."""
[docs] def __init__(self, nelx: int, nely: int, rmin: float): """ Create a filter to filter solutions. Build (and assemble) the index+data vectors for the coo matrix format. Parameters ---------- nelx: The number of elements in the x direction. nely: The number of elements in the y direction. rmin: The filter radius. """ self._repr_string = "{}(nelx={:d}, nely={:d}, rmin={:g})".format( self.__class__.__name__, nelx, nely, rmin) nfilter = int(nelx * nely * ((2 * (numpy.ceil(rmin) - 1) + 1)**2)) iH = numpy.zeros(nfilter) jH = numpy.zeros(nfilter) sH = numpy.zeros(nfilter) cc = 0 for i in range(nelx): for j in range(nely): row = i * nely + j kk1 = int(numpy.maximum(i - (numpy.ceil(rmin) - 1), 0)) kk2 = int(numpy.minimum(i + numpy.ceil(rmin), nelx)) ll1 = int(numpy.maximum(j - (numpy.ceil(rmin) - 1), 0)) ll2 = int(numpy.minimum(j + numpy.ceil(rmin), nely)) for k in range(kk1, kk2): for l in range(ll1, ll2): col = k * nely + l fac = rmin - numpy.sqrt( ((i - k) * (i - k) + (j - l) * (j - l))) iH[cc] = row jH[cc] = col sH[cc] = numpy.maximum(0.0, fac) cc = cc + 1 # Finalize assembly and convert to csc format self.H = scipy.sparse.coo_matrix( (sH, (iH, jH)), shape=(nelx * nely, nelx * nely)).tocsc() self.Hs = self.H.sum(1)
def __str__(self) -> str: """Create a string representation of the filter.""" return self.__class__.__name__ def __format__(self, format_spec) -> str: """Create a formated representation of the filter.""" return str(self) def __repr__(self) -> str: """Create a formated representation of the filter.""" return self._repr_string
[docs] @abc.abstractmethod def filter_variables(self, x: numpy.ndarray, xPhys: numpy.ndarray) -> None: """ Filter the variable of the solution to produce xPhys. Parameters ---------- x: The raw density values. xPhys: The filtered density values to be computed """ pass
[docs] @abc.abstractmethod def filter_objective_sensitivities( self, xPhys: numpy.ndarray, dobj: numpy.ndarray) -> None: """ Filter derivative of the objective. Parameters ---------- xPhys: The filtered density values. dobj: The filtered objective sensitivities to be computed. """ pass
[docs] @abc.abstractmethod def filter_volume_sensitivities( self, xPhys: numpy.ndarray, dv: numpy.ndarray) -> None: """ Filter derivative of the volume. Parameters ---------- xPhys: The filtered density values. dv: The filtered volume sensitivities to be computed. """ pass
[docs]class SensitivityBasedFilter(Filter): """Sensitivity based filter of solutions."""
[docs] def filter_variables(self, x: numpy.ndarray, xPhys: numpy.ndarray) -> None: """ Filter the variable of the solution to produce xPhys. Parameters ---------- x: The raw density values. xPhys: The filtered density values to be computed """ xPhys[:] = x
[docs] def filter_objective_sensitivities( self, xPhys: numpy.ndarray, dobj: numpy.ndarray) -> None: """ Filter derivative of the objective. Parameters ---------- xPhys: The filtered density values. dobj: The filtered objective sensitivities to be computed. """ dobj[:] = (numpy.asarray( (self.H * (xPhys * dobj))[numpy.newaxis].T / self.Hs)[:, 0] / numpy.maximum(0.001, xPhys))
[docs] def filter_volume_sensitivities( self, xPhys: numpy.ndarray, dv: numpy.ndarray) -> None: """ Filter derivative of the volume. Parameters ---------- xPhys: The filtered density values. dv: The filtered volume sensitivities to be computed. """ return
[docs]class DensityBasedFilter(Filter): """Density based filter of solutions."""
[docs] def filter_variables(self, x: numpy.ndarray, xPhys: numpy.ndarray) -> None: """ Filter the variable of the solution to produce xPhys. Parameters ---------- x: The raw density values. xPhys: The filtered density values to be computed """ xPhys[:] = numpy.asarray(self.H * x[numpy.newaxis].T / self.Hs)[:, 0]
[docs] def filter_objective_sensitivities( self, xPhys: numpy.ndarray, dobj: numpy.ndarray) -> None: """ Filter derivative of the objective. Parameters ---------- xPhys: The filtered density values. dobj: The filtered objective sensitivities to be computed. """ dobj[:] = numpy.asarray( self.H * (dobj[numpy.newaxis].T / self.Hs))[:, 0]
[docs] def filter_volume_sensitivities( self, xPhys: numpy.ndarray, dv: numpy.ndarray) -> None: """ Filter derivative of the volume. Parameters ---------- xPhys: The filtered density values. dv: The filtered volume sensitivities to be computed. """ dv[:] = numpy.asarray(self.H * (dv[numpy.newaxis].T / self.Hs))[:, 0]