def create_forest(comm, depth, htarget): """ Create an initial forest for analysis and optimization. This code loads in the model, sets names, meshes the geometry and creates an OctForest from the mesh. The forest is populated with octrees with the specified depth. Args: comm (MPI_Comm): MPI communicator depth (int): Depth of the initial trees htarget (float): Target global element mesh size Returns: OctForest: Initial forest for topology optimization """ # Load the geometry model geo = TMR.LoadModel('../cantilever/cantilever.stp') # Mark the boundary condition faces verts = geo.getVertices() edges = geo.getEdges() faces = geo.getFaces() volumes = geo.getVolumes() faces[3].setName('fixed') faces[4].setSource(volumes[0], faces[5]) verts[4].setName('pt1') verts[3].setName('pt2') # Set the boundary conditions for the problem bcs = TMR.BoundaryConditions() bcs.addBoundaryCondition('fixed') # Create the mesh mesh = TMR.Mesh(comm, geo) # Set the meshing options opts = TMR.MeshOptions() # Create the surface mesh mesh.mesh(args.htarget, opts) # Create a model from the mesh model = mesh.createModelFromMesh() # Create the corresponding mesh topology from the mesh-model topo = TMR.Topology(comm, model) # Create the quad forest and set the topology of the forest forest = TMR.OctForest(comm) forest.setTopology(topo) # Create the trees forest.createTrees(depth) return forest
opts = TMR.MeshOptions() opts.frontal_quality_factor = 1.25 opts.num_smoothing_steps = 50 opts.triangularize_print_iter = 50000 opts.write_mesh_quality_histogram = 1 # Create the surface mesh mesh.mesh(0.02, opts) # Create a model from the mesh model = mesh.createModelFromMesh() # Create the corresponding mesh topology from the mesh-model topo = TMR.Topology(comm, model) # Create the quad forest and set the topology of the forest forest = TMR.OctForest(comm) forest.setTopology(topo) forest.createTrees(1) forest.createNodes() ar = computeAR(forest) min_ang = computeMinAngle(forest) fshape = computeShape(forest) # Wrtie the mesh quality to vtk writeQualityToVtk(forest, ar, min_ang, fshape,fname='quality-bracket.vtk') plotShapeHist(fshape, xmin=np.amin(fshape), fname='bracket_shape_hist.pdf') plotARHist(ar, fname='bracket_ar_hist.pdf', xmax=np.ceil(4.0*np.amax(ar))/4.0) plotMinAngHist(min_ang, fname='bracket_ang_hist.pdf', xmin=np.amin(min_ang)-1.0)
# Set the meshing options opts = TMR.MeshOptions() opts.frontal_quality_factor = 1.25 opts.num_smoothing_steps = 10 opts.write_mesh_quality_histogram = 0 # Create the surface mesh htarget = 4.0 mesh.mesh(htarget, opts) # Create a model from the mesh model = mesh.createModelFromMesh() # Create the corresponding mesh topology from the mesh-model topo = TMR.Topology(comm, model) fine = TMR.OctForest(comm) fine.setTopology(topo) else: conn = np.array([[0, 1, 3, 4, 6, 7, 9, 10], [8, 11, 2, 5, 7, 10, 1, 4]], dtype=np.intc) fine = TMR.OctForest(comm) fine.setConnectivity(conn) # Create the fine mesh fine.createTrees(0) refine = np.zeros(len(fine.getOctants()), dtype=np.intc) if comm.rank == 0: refine[0] = 4 fine.refine(refine) fine.balance(1) fine.repartition()
def create_3d_unstruct_mesh(n, AR, prob, ratio1, ratio2, hole_r, forced_portion, force_magnitude, MBB_bc_portion, loaded_thickness, ly): comm = MPI.COMM_WORLD # Create the egads context ctx = egads.context() # dimensions Lx = ly * AR Ly = ly h = ly parts = [] if prob == 'lbracket': # Create base x0 = [0, 0, 0] x1 = [Lx * ratio1, Ly * ratio2, h] B0 = ctx.makeSolidBody(egads.BOX, rdata=[x0, x1]) parts.append(ctx.makeTopology(egads.MODEL, children=[B0])) # Create arm 1 x0 = [0, Ly * ratio2, 0] x1 = [Lx * ratio1, Ly * (1 - ratio2), h] B1 = ctx.makeSolidBody(egads.BOX, rdata=[x0, x1]) parts.append(ctx.makeTopology(egads.MODEL, children=[B1])) # Create arm 2 x0 = [Lx * ratio1, 0, 0] x1 = [Lx * (1 - ratio1), Ly * ratio2, h] B2 = ctx.makeSolidBody(egads.BOX, rdata=[x0, x1]) # Create the cylinder cutout xc = Lx * (ratio1 + 1) * 0.5 yc = Ly * ratio2 * 0.5 x0 = [xc, yc, 0] x1 = [xc, yc, h] r = hole_r * Ly * ratio2 C1 = ctx.makeSolidBody(egads.CYLINDER, rdata=[x0, x1, r]) parts.append(B2.solidBoolean(C1, egads.SUBTRACTION)) else: # Create the box x0 = [0, 0, 0] x1 = [Lx, Ly, h] B1 = ctx.makeSolidBody(egads.BOX, rdata=[x0, x1]) # Create the cylinder cutout xc = Lx / 2 yc = Ly / 2 x0 = [xc, yc, 0] x1 = [xc, yc, h] r = hole_r * Ly C1 = ctx.makeSolidBody(egads.CYLINDER, rdata=[x0, x1, r]) # parts.append(ctx.makeTopology(egads.MODEL, children=[B1])) parts.append(B1.solidBoolean(C1, egads.SUBTRACTION)) # Create all of the models geos = [] for p in parts: geos.append(TMR.ConvertEGADSModel(p)) # Create the full list of vertices, edges, faces and volumes verts = [] edges = [] faces = [] vols = [] for geo in geos: verts.extend(geo.getVertices()) edges.extend(geo.getEdges()) faces.extend(geo.getFaces()) vols.extend(geo.getVolumes()) # Set all of the matching faces TMR.setMatchingFaces(geos) # Create the geometry geo = TMR.Model(verts, edges, faces, vols) # Create the new mesh mesh = TMR.Mesh(comm, geo) # Set the meshing options opts = TMR.MeshOptions() # opts.mesh_type_default = TMR.UNSTRUCTURED opts.write_mesh_quality_histogram = 1 opts.triangularize_print_iter = 50000 # Create the surface mesh htarget = ly / n mesh.mesh(htarget, opts) # Write the surface mesh to a file # mesh.writeToVTK('block.vtk', 'hex') # Create the model from the unstructured volume mesh model = mesh.createModelFromMesh() # Create the corresponding mesh topology from the mesh-model topo = TMR.Topology(comm, model) # Create the quad forest and set the topology of the forest forest = TMR.OctForest(comm) forest.setTopology(topo) forest.createTrees() forest.balance(1) # Create the nodes forest.createNodes() # Get the mesh connectivity conn = forest.getMeshConn() nnodes = np.max(conn) + 1 nelems = len(conn) # Get the node locations X = forest.getPoints() # Set boundary conditions dof = -np.ones((nnodes, 3), dtype=int) geo_bc_tol = 1e-6 if prob == 'cantilever' or prob == 'michell': bc_x_max = geo_bc_tol bc_x_min = -geo_bc_tol bc_y_max = Ly + geo_bc_tol bc_y_min = -geo_bc_tol bc_z_max = h + geo_bc_tol bc_z_min = -geo_bc_tol ndof = 0 for i in range(nnodes): if (bc_x_min <= X[i, 0] <= bc_x_max and bc_y_min <= X[i, 1] <= bc_y_max and bc_z_min <= X[i, 2] <= bc_z_max): # This is the bc node pass else: dof[i, 0] = ndof ndof += 1 dof[i, 1] = ndof ndof += 1 dof[i, 2] = ndof ndof += 1 elif prob == 'MBB': bc1_x_max = geo_bc_tol bc1_x_min = -geo_bc_tol bc1_y_max = Ly + geo_bc_tol bc1_y_min = -geo_bc_tol bc1_z_max = h + geo_bc_tol bc1_z_min = -geo_bc_tol bc2_x_max = Lx + geo_bc_tol bc2_x_min = Lx * (1 - MBB_bc_portion) - geo_bc_tol bc2_y_max = geo_bc_tol + geo_bc_tol bc2_y_min = -geo_bc_tol bc2_z_max = h + geo_bc_tol bc2_z_min = -geo_bc_tol ndof = 0 for i in range(nnodes): if (bc1_x_min <= X[i, 0] <= bc1_x_max and bc1_y_min <= X[i, 1] <= bc1_y_max and bc1_z_min <= X[i, 2] <= bc1_z_max): # This is the bc node dof[i, 1] = ndof ndof += 1 elif (bc2_x_min <= X[i, 0] <= bc2_x_max and bc2_y_min <= X[i, 1] <= bc2_y_max and bc2_z_min <= X[i, 2] <= bc2_z_max): # This is also bc node dof[i, 0] = ndof ndof += 1 else: dof[i, 0] = ndof ndof += 1 dof[i, 1] = ndof ndof += 1 dof[i, 2] = ndof ndof += 1 elif prob == 'lbracket': bc_x_max = Lx * ratio1 + geo_bc_tol bc_x_min = -geo_bc_tol bc_y_max = Ly + geo_bc_tol bc_y_min = Ly - geo_bc_tol bc_z_max = h + geo_bc_tol bc_z_min = -geo_bc_tol ndof = 0 for i in range(nnodes): if (bc_x_min <= X[i, 0] <= bc_x_max and bc_y_min <= X[i, 1] <= bc_y_max and bc_z_min <= X[i, 2] <= bc_z_max): # This is the bc node pass else: dof[i, 0] = ndof ndof += 1 dof[i, 1] = ndof ndof += 1 dof[i, 2] = ndof ndof += 1 # Set loading force = np.zeros(ndof) geo_tol = 1e-6 if prob == 'cantilever': load_x_max = Lx + geo_tol load_x_min = Lx - geo_tol load_y_max = Ly * forced_portion + geo_tol load_y_min = -geo_tol load_z_max = 0.5 * h * (1 + loaded_thickness) load_z_min = 0.5 * h * (1 - loaded_thickness) force_dir = 1 force_scal = -1.0 elif prob == 'MBB': load_x_max = Lx * MBB_bc_portion + geo_tol load_x_min = -geo_tol load_y_max = Ly + geo_tol load_y_min = Ly - geo_tol load_z_max = 0.5 * h * (1 + loaded_thickness) + geo_tol load_z_min = 0.5 * h * (1 - loaded_thickness) - geo_tol force_dir = 1 force_scal = -1.0 elif prob == 'michell': load_x_max = Lx + geo_tol load_x_min = Lx - geo_tol load_y_max = 0.5 * Ly * (1 + forced_portion) + geo_tol load_y_min = 0.5 * Ly * (1 - forced_portion) - geo_tol load_z_max = 0.5 * h * (1 + loaded_thickness) + geo_tol load_z_min = 0.5 * h * (1 - loaded_thickness) - geo_tol force_dir = 1 force_scal = -1.0 elif prob == 'lbracket': load_x_max = Lx + geo_tol load_x_min = Lx - geo_tol load_y_max = Ly * ratio2 + geo_tol load_y_min = Ly * ratio2 * (1 - forced_portion) - geo_tol load_z_max = 0.5 * h * (1 + loaded_thickness) + geo_tol load_z_min = 0.5 * h * (1 - loaded_thickness) - geo_tol force_dir = 1 force_scal = -1.0 nforce = 0 for i in range(nnodes): if (load_x_min <= X[i, 0] <= load_x_max and load_y_min <= X[i, 1] <= load_y_max and load_z_min <= X[i, 2] <= load_z_max): force[dof[i, force_dir]] = force_scal * force_magnitude nforce += 1 force /= nforce # for n in range(X.shape[0]): # print('node:{:4d} x:{:6f} y:{:6f} z:{:6f}'.format(n, X[n, 0], X[n, 1], X[n, 2])) # for ne in range(conn.shape[0]): # print('elem:{:4d} conn = [{:3d} {:3d} {:3d} {:3d}]'.format(ne, conn[ne,0], conn[ne,1], conn[ne,2], conn[ne,3])) return nelems, nnodes, ndof, conn, X, dof, force