def forces(self): """Return the force vector for the problem.""" f = numpy.zeros((2 * (self.nelx + 1) * (self.nely + 1), 1)) id1 = 2 * xy_to_id(7 * self.nelx // 20, 0, self.nelx, self.nely) + 1 id2 = 2 * xy_to_id(13 * self.nelx // 20, 0, self.nelx, self.nely) + 1 f[[id1, id2], 0] = -1 return f
def get_fixed_nodes(self): # Return a list of fixed nodes for the problem bottom_left = 2 * xy_to_id(0, self.nely, self.nelx, self.nely) bottom_right = 2 * xy_to_id(self.nelx, self.nely, self.nelx, self.nely) fixed = np.array( [bottom_left, bottom_left + 1, bottom_right, bottom_right + 1]) return fixed
def fixed_nodes(self): """Return a list of fixed nodes for the problem.""" bottom_left = 2 * xy_to_id(0, self.nely, self.nelx, self.nely) bottom_right = 2 * xy_to_id(self.nelx, self.nely, self.nelx, self.nely) fixed = numpy.array( [bottom_left, bottom_left + 1, bottom_right, bottom_right + 1]) return fixed
def get_fixed_nodes(self): # Return a list of fixed nodes for the problem bottom_left = 2 * xy_to_id(0, self.nely, self.nelx, self.nely) bottom_right = 2 * xy_to_id( self.nelx, self.nely, self.nelx, self.nely) fixed = np.array([bottom_left, bottom_left + 1, bottom_right, bottom_right + 1]) return fixed
def on_press(self, event): """Create a hole at the point pressed.""" # Clamp the point to the domain selected_x = int(max(0, min(self.nelx, numpy.round(event.xdata)))) selected_y = int(max(0, min(self.nely, numpy.round(event.ydata)))) print("Selected: x = {:d}, y = {:d}".format(selected_x, selected_y)) selected_point = numpy.array([selected_x, selected_y]) def dist_from_selected_point(x, y): """Compute the distance from the selected_point.""" return numpy.linalg.norm(selected_point - numpy.array([x, y])) # Create a bounding box of the selected point and the selection radius min_x = max(0, selected_x - self.radius + 1) max_x = min(self.nelx, selected_x + self.radius) min_y = max(0, selected_y - self.radius + 1) max_y = min(self.nely, selected_y + self.radius) for x in range(min_x, max_x): for y in range(min_y, max_y): if dist_from_selected_point(x, y) <= self.radius: solver.xPhys[xy_to_id( x, y, self.nelx - 1, self.nely - 1)] = (0.0 if event.button == 1 else 1.0) self.problem.compute_objective2(solver.xPhys, self.problem.dstress)
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 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 topx_to_id = np.vectorize( lambda x: xy_to_id(x, 0, self.nelx, self.nely)) topx = 2 * topx_to_id(np.arange((self.nelx + 1) // 2)) + 1 f = np.zeros((2 * (self.nelx + 1) * (self.nely + 1), 1)) f[topx, 0] = -100 return f
def forces(self): """Return the force vector for the problem.""" topx_to_id = numpy.vectorize( lambda x: xy_to_id(x, 0, self.nelx, self.nely)) topx = 2 * topx_to_id(numpy.arange(self.nelx + 1)) + 1 f = numpy.zeros((2 * (self.nelx + 1) * (self.nely + 1), 1)) f[topx, 0] = -1 return f
def fixed_nodes(self): """Return a list of fixed nodes for the problem.""" x = numpy.arange(self.nelx + 1) botx_to_id = numpy.vectorize( lambda x: xy_to_id(x, self.nely, self.nelx, self.nely)) ids = 2 * botx_to_id(x) fixed = numpy.union1d(ids, ids + 1) return fixed
def nonuniform_forces(self): """Return the force vector for the problem.""" topx_to_id = numpy.vectorize( lambda x: xy_to_id(x, 0, self.nelx, self.nely)) topx = 2 * topx_to_id(numpy.arange(self.nelx + 1)) + 1 f = numpy.zeros((2 * (self.nelx + 1) * (self.nely + 1), 1)) f[topx, 0] = (0.5 * numpy.cos( numpy.linspace(0, 2 * numpy.pi, topx.shape[0])) - 0.5) return f
def forces(self): """Return the force vector for the problem.""" topx_to_id = numpy.vectorize( lambda x: xy_to_id(x, 0, self.nelx, self.nely)) topx = 2 * topx_to_id(numpy.arange(self.nelx + 1)) + 1 nForces = topx.shape[0] cols = numpy.arange(nForces) f = numpy.zeros((2 * (self.nelx + 1) * (self.nely + 1), nForces)) f[topx, cols] = -1 return f
def forces(self): """Return the force vector for the problem.""" ndof = 2 * (self.nelx + 1) * (self.nely + 1) x = numpy.arange(0, self.nelx + 1, 10) topx_to_id = numpy.vectorize( lambda x: xy_to_id(x, 0, self.nelx, self.nely)) ids = 2 * topx_to_id(x) + 1 f = numpy.zeros((ndof, 1)) f[ids] = -1 return f
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 onrelease(event): if event.button == 1: global selected_x, selected_y dx = event.xdata - selected_x dy = event.ydata - selected_y id = xy_to_id(selected_x, selected_y, nelx, nely) u[2 * id] += dx u[2 * id + 1] += dy stress = vms.calculate_stress(xPhys, u, nu) im.set_array(stress.reshape((nelx, nely)).T) set_labels(stress.reshape((nelx, nely)).T) print("Released: dx = {:g}, dy = {:g}".format(dx, dy)) selected_x = selected_y = None
def onpress(event): global selected_x, selected_y selected_x = int(max(0, min(nelx, numpy.round(event.xdata)))) selected_y = int(max(0, min(nely, numpy.round(event.ydata)))) if event.button == 1: print("Selected: x = {:d}, y = {:d}".format(selected_x, selected_y)) else: id = xy_to_id(selected_x, selected_y, nelx, nely) u[2 * id] = 0 u[2 * id + 1] = 0 stress = vms.calculate_stress(xPhys, u, nu) im.set_array(stress.reshape((nelx, nely)).T) set_labels(stress.reshape((nelx, nely)).T) selected_x = selected_y = None
def set_displacements(u, func, nelx, nely, min_corner=(-1, -1), max_corner=(1, 1)): for i in range(nelx + 1): for j in range(nely + 1): id = xy_to_id(i, j, nelx, nely) x = min_corner[0] + (i / nelx) * (max_corner[0] - min_corner[0]) y = min_corner[1] + (j / nely) * (max_corner[1] - min_corner[1]) fx, fy = func(x, y) u[2 * id] = fx u[2 * id + 1] = fy
def main(nelx, nely, volfrac, penalty, rmin, ft): print("Minimum compliance problem with OC") print("ndes: %d x %d" % (nelx, nely)) print("volfrac: %s, rmin: %s, penalty: %s" % (volfrac, rmin, penalty)) print("Filter method: " + ["Sensitivity based", "Density based"][ft]) # Max and min stiffness Emin = 1e-9 Emax = 1.0 # dofs: ndof = 2 * (nelx + 1) * (nely + 1) # Allocate design variables (as array), initialize and allocate sens. x = volfrac * np.ones(nely * nelx) xold = x.copy() xPhys = x.copy() g = 0 # must be initialized to use the NGuyen/Paulino OC approach dc = np.zeros((nely, nelx)) # FE: Build the index vectors for the for coo matrix format. KE = lk() edofMat = np.zeros((nelx * nely, 8), dtype=int) for elx in range(nelx): for ely in range(nely): el = ely + elx * nely n1 = (nely + 1) * elx + ely n2 = (nely + 1) * (elx + 1) + ely edofMat[el, :] = np.array([ 2 * n1 + 2, 2 * n1 + 3, 2 * n2 + 2, 2 * n2 + 3, 2 * n2, 2 * n2 + 1, 2 * n1, 2 * n1 + 1 ]) # Construct the index pointers for the coo format iK = np.kron(edofMat, np.ones((8, 1))).flatten() jK = np.kron(edofMat, np.ones((1, 8))).flatten() # Filter: Build (and assemble) the index + data vectors for the coo matrix # format nfilter = int(nelx * nely * ((2 * (np.ceil(rmin) - 1) + 1)**2)) iH = np.zeros(nfilter) jH = np.zeros(nfilter) sH = np.zeros(nfilter) cc = 0 for i in range(nelx): for j in range(nely): row = i * nely + j kk1 = int(np.maximum(i - (np.ceil(rmin) - 1), 0)) kk2 = int(np.minimum(i + np.ceil(rmin), nelx)) ll1 = int(np.maximum(j - (np.ceil(rmin) - 1), 0)) ll2 = int(np.minimum(j + np.ceil(rmin), nely)) for k in range(kk1, kk2): for l in range(ll1, ll2): col = k * nely + l fac = rmin - np.sqrt( ((i - k) * (i - k) + (j - l) * (j - l))) iH[cc] = row jH[cc] = col sH[cc] = np.maximum(0.0, fac) cc = cc + 1 # Finalize assembly and convert to csc format H = coo_matrix((sH, (iH, jH)), shape=(nelx * nely, nelx * nely)).tocsc() Hs = H.sum(1) # BC's and support dofs = np.arange(2 * (nelx + 1) * (nely + 1)) bottom_left = 2 * xy_to_id(0, nely, nelx, nely) bottom_right = 2 * xy_to_id(nelx, nely, nelx, nely) fixed = np.array( [bottom_left, bottom_left + 1, bottom_right, bottom_right + 1]) free = np.setdiff1d(dofs, fixed) # Solution and RHS vectors f = np.zeros((ndof, 2)) u = np.zeros((ndof, 2)) # Set load f = np.zeros((2 * (nelx + 1) * (nely + 1), 2)) id1 = 2 * xy_to_id(7 * nelx // 20, 0, nelx, nely) + 1 id2 = 2 * xy_to_id(13 * nelx // 20, 0, nelx, nely) + 1 f[id1, 0] = -1 f[id2, 1] = -1 # f[1, 0] = -1 # f[2 * (nelx - 1) * (nely + 1), 1] = -1 # Initialize plot and plot the initial design plt.ion() # Ensure that redrawing is possible fig, ax = plt.subplots() im = ax.imshow(-xPhys.reshape((nelx, nely)).T, cmap='gray', interpolation='none', norm=colors.Normalize(vmin=-1, vmax=0)) plt.xlabel( "ndes: {:d} x {:d}\nvolfrac: {:g}, rmin: {:g}, penalty: {:g}".format( nelx, nely, volfrac, rmin, penalty)) plot_force_arrows(nelx, nely, f, ax) fig.tight_layout() fig.show() # Set loop counter and gradient vectors dv = np.ones(nely * nelx) ce = np.ones(nely * nelx) for loop in range(2000): # while change > 0.01 and loop < 100: # Setup and solve FE problem sK = ((KE.flatten()[np.newaxis]).T * (Emin + (xPhys)**penalty * (Emax - Emin))).flatten(order='F') K = coo_matrix((sK, (iK, jK)), shape=(ndof, ndof)).tocsc() # Remove constrained dofs from matrix K = deleterowcol(K, fixed, fixed).tocoo() # Solve system # u[free, :] = spsolve(K.tocsc(), f[free, :]) K = cvxopt.spmatrix(K.data, K.row, K.col) B = cvxopt.matrix(f[free, :]) cvxopt.cholmod.linsolve(K, B) u[free, :] = np.array(B)[:, :] # Objective and sensitivity obj = 0 dc = np.zeros(nely * nelx) # import pdb; pdb.set_trace() for i in range(f.shape[1]): ui = u[:, i][edofMat] ce[:] = (ui.dot(KE) * ui).sum(1) obj += ((Emin + xPhys**penalty * (Emax - Emin)) * ce).sum() dc[:] += (-penalty * xPhys**(penalty - 1) * (Emax - Emin)) * ce dv[:] = np.ones(nely * nelx) # Sensitivity filtering: if ft == 0: dc[:] = (np.asarray((H * (x * dc))[np.newaxis].T / Hs)[:, 0] / np.maximum(0.001, x)) elif ft == 1: dc[:] = np.asarray(H * (dc[np.newaxis].T / Hs))[:, 0] dv[:] = np.asarray(H * (dv[np.newaxis].T / Hs))[:, 0] # Optimality criteria xold[:] = x (x[:], g) = oc(nelx, nely, x, volfrac, dc, dv, g) # Filter design variables if ft == 0: xPhys[:] = x elif ft == 1: xPhys[:] = np.asarray(H * x[np.newaxis].T / Hs)[:, 0] # Compute the change by the inf. norm change = (np.linalg.norm( x.reshape(nelx * nely, 1) - xold.reshape(nelx * nely, 1), np.inf)) # Plot to screen im.set_array(-xPhys.reshape((nelx, nely)).T) fig.canvas.draw() fig.canvas.flush_events() plt.pause(0.005) # Write iteration history to screen print("it.: %3d, obj.: %9.3f, Vol.: %.2f, ch.: %.3f" % (loop, obj, (g + volfrac * nelx * nely) / (nelx * nely), change)) if change < 0.01: break # Make sure the plot stays and that the shell remains plt.show() input("Press any key...")