Source code for topopt.cli

# -*- coding: utf-8 -*-
"""Command-line utility to run topology optimization."""

import textwrap
import argparse

import numpy

import topopt.guis
import topopt.boundary_conditions
import topopt.problems
import topopt.filters
import topopt.solvers


[docs]def create_parser(nelx: int = 180, nely: int = 60, volfrac: float = 0.4, penalty: float = 3.0, rmin: float = 5.4, ft: int = 1 ) -> argparse.ArgumentParser: """ Create an argument parser with the given values as defaults. Parameters ---------- nelx: The default number of elements in the x direction. nely: The default number of elements in the y direction. volfrac: The default fraction of the total volume to use. penalty: The default penalty exponent value in SIMP. rmin: The default filter radius. ft: The default filter method to use. - ``0``: :obj:`topopt.filters.SensitivityBasedFilter` - ``1``: :obj:`topopt.filters.DensityBasedFilter` Returns ------- Argument parser with given defaults. """ parser = argparse.ArgumentParser(description="Topology Optimization") parser.add_argument("--nelx", type=int, default=nelx, help="number of elements in the x direction") parser.add_argument("--nely", type=int, default=nely, help="number of elements in the x direction") parser.add_argument("--volfrac", type=float, default=volfrac, help="fraction of the total volume usable") parser.add_argument("--penalty", type=float, default=penalty, help="penalty exponent value in SIMP") parser.add_argument("--rmin", "--filter-radius", type=float, dest="rmin", default=rmin, help="filter radius") parser.add_argument( "--ft", "--filter-type", choices=[0, 1], dest="ft", default=ft, help="filter type (0: sensitivity based, 1: density based)") return parser
[docs]def parse_args(nelx: int = 180, nely: int = 60, volfrac: float = 0.4, penalty: float = 3.0, rmin: float = 5.4, ft: int = 1 ) -> tuple: """ Parse the system args with the given values as defaults. Parameters ---------- nelx: The default number of elements in the x direction. nely: The default number of elements in the y direction. volfrac: The default fraction of the total volume to use. penalty: The default penalty exponent value in SIMP. rmin: The default filter radius. ft: The default filter method to use. - ``0``: :obj:`topopt.filters.SensitivityBasedFilter` - ``1``: :obj:`topopt.filters.DensityBasedFilter` Returns ------- Parsed command-line arguments. """ args = create_parser(nelx, nely, volfrac, penalty, rmin, ft).parse_args() return args.nelx, args.nely, args.volfrac, args.penalty, args.rmin, args.ft
[docs]def title_str(nelx: int, nely: int, volfrac: float, rmin: float, penalty: float) -> str: """ Create a title string for the problem. Parameters ---------- nelx: The number of elements in the x direction. nely: The number of elements in the y direction. volfrac: The fraction of the total volume to use. rmin: The filter radius. penalty: The penalty exponent value in SIMP. Returns ------- Title string for the GUI. """ return textwrap.dedent(f"""\ dims: {nelx:d} x {nely:d} volfrac: {volfrac:g}, penalty: {penalty:g}, rmin: {rmin:g}""")
[docs]def main(nelx: int, nely: int, volfrac: float, penalty: float, rmin: float, ft: int, gui: topopt.guis.GUI = None, bc: topopt.boundary_conditions.BoundaryConditions = None, problem: topopt.problems.Problem = None, filter: topopt.filters.Filter = None, solver: topopt.solvers.TopOptSolver = None) -> None: """ Run the main application of the command-line tools. Parameters ---------- nelx: The number of elements in the x direction. nely: The number of elements in the y direction. volfrac: The fraction of the total volume to use. penalty: The penalty exponent value in SIMP. rmin: The filter radius. ft: The filter method to use. - ``0``: :obj:`topopt.filters.SensitivityBasedFilter` - ``1``: :obj:`topopt.filters.DensityBasedFilter` gui: The GUI to use. bc: The boundary conditions to use. problem: The problem to use. filter: The filter to use. solver: The solver to use. """ # Allocate design variables (as array), initialize and allocate sens. x = volfrac * numpy.ones(nely * nelx, dtype=float) # Initialize optional arguments if solver is None: if problem is None: if bc is None: bc = topopt.boundary_conditions.MBBBeamBoundaryConditions( nelx, nely) problem = topopt.problems.ComplianceProblem(bc, penalty) gui = gui if gui else topopt.guis.GUI( problem, title_str(nelx, nely, volfrac, rmin, penalty)) filter = (filter if filter else [ topopt.filters.SensitivityBasedFilter, topopt.filters.DensityBasedFilter][ft](nelx, nely, rmin)) solver = topopt.solvers.TopOptSolver(problem, volfrac, filter, gui) print(textwrap.dedent(f"""\ {solver:s} dims: {nelx:d} x {nely:d} volfrac: {volfrac:g}, penalty: {penalty:g}, rmin: {rmin:g} Filter method: {solver.filter:s}""")) # Solve the problem x_opt = solver.optimize(x) x_opt = solver.filter_variables(x_opt) if gui is not None: gui.update(x_opt) # Make sure the plot stays and that the shell remains input("Press any key...")