```#! /usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import division
import sys
import pdb

import numpy as np

from topopt.gui import GUI
from topopt.boundary_conditions import BoundaryConditions
from topopt.solver import Solver
from topopt.utils import xy_to_id, id_to_xy

# Python 2/3 compatibility
try:
input = raw_input
except NameError:
pass

class LessTolerantSolver(Solver):
def __init__(self, nelx, nely, volfrac, penal, rmin, ft, gui, bc):
super(LessTolerantSolver, self).__init__(nelx, nely, volfrac, penal,
rmin, ft, gui, bc)
# set stopping criteria
self.opt.set_maxeval(4000)
self.opt.set_ftol_rel(0.0001)

class LBracketBoundaryConditions(BoundaryConditions):
def __init__(self, nelx, nely, minx, maxy):
super(LBracketBoundaryConditions, self).__init__(nelx, nely)
(self.passive_min_x, self.passive_min_y, self.passive_max_x,
self.passive_max_y) = [minx, 0, nelx - 1, maxy]

def get_fixed_nodes(self):
""" Return a list of fixed nodes for the problem. """
x = np.arange(self.passive_min_x)
topx_to_id = np.vectorize(
lambda x: xy_to_id(x, 0, self.nelx, self.nely))
ids = topx_to_id(x)
fixed = np.union1d(2 * ids, 2 * ids + 1)
return fixed

def get_forces(self):
""" Return the force vector for the problem. """
ndof = 2 * (self.nelx + 1) * (self.nely + 1)
f = np.zeros((ndof, 1))
fx = self.nelx
# fy = (self.nely - self.passive_max_y) // 2 + self.passive_max_y
for i in range(1, 2):
fy = self.passive_max_y - 1 + 2 * i
id = xy_to_id(fx, fy, self.nelx, self.nely)
f[2 * id + 1, 0] = -1
return f

def get_passive_elements(self):
X, Y = np.mgrid[self.passive_min_x:self.passive_max_x + 1,
self.passive_min_y:self.passive_max_y]
pairs = np.vstack([X.ravel(), Y.ravel()]).T
passive_to_ids = np.vectorize(lambda pair: xy_to_id(*pair,
nelx=self.nelx - 1, nely=self.nely - 1), signature="(m)->()")
return passive_to_ids(pairs)

def main(nelx, nely, volfrac, penal, rmin, ft):
print("Minimum compliance problem with MMA")
print("ndes: {:d} x {:d}".format(nelx, nely))
print("volfrac: {:g}, rmin: {:g}, penal: {:g}".format(volfrac, rmin, penal))
print("Filter method: " + ["Sensitivity based", "Density based"][ft])

# Allocate design variables (as array), initialize and allocate sens.
x = volfrac * np.ones(nely * nelx, dtype=float)

title = "ndes: {:d} x {:d}\nvolfrac: {:g}, rmin: {:g}, penal: {:g}".format(
nelx, nely, volfrac, rmin, penal)
gui    = GUI(nelx, nely, title)
solver = LessTolerantSolver(nelx, nely, volfrac, penal, rmin, ft, gui,
LBracketBoundaryConditions(nelx, nely, nelx // 3, 2 * nely // 3))
x_opt  = solver.optimize(x)
x_opt  = solver.filter_variables(x_opt)
gui.update(x_opt)

from PIL import Image
x_opt.clip(0.0, 1.0)
x_opt = ((1 - x_opt.reshape(nelx, nely)) * 255).round().astype("uint8").T
result = Image.fromarray(x_opt)
result.save("tmp.png")

# Make sure the plot stays and that the shell remains
input("Press any key...")

if __name__ == "__main__":
def run():
# Default input parameters
nelx, nely, volfrac, penal, rmin, ft = (sys.argv[1:] +
[120, 120, 0.2, 6.0, 4, 1][len(sys.argv) - 1:])[:6]
nelx, nely, ft = map(int, [nelx, nely, ft])
volfrac, penal, rmin = map(float, [volfrac, penal, rmin])
main(nelx, nely, volfrac, penal, rmin, ft)
run()
```