def surface(self, f, axis=None, mesh=None, derivative=(0, ), shading=True, grid=False, resolution=(100, 100), edge_resolution=10, flag=None): """ Plot the surface of a function defined on the finite element mesh Inputs: ax: axis (don't forget to initialize it using projection='3d') f: Function, function to be plotted mesh: Mesh, on which to plot the function *derivatives [(0,)]: int, tuple specifying what derivatives to plot (see Function.eval for details). *shading [True]: bool, shade surface or use wire plot? *grid [False]: bool, display grid? *resolution [(100,100)]: int, tuple (nx,ny) number of points in the x- and y directions. *edge_resolution: int, number of points along each each edge *flag [None]: str/int marker for submesh TODO: Not implemented Output: ax: Axis, containing plot. """ # # Check if input is a Function object # assert isinstance(f, Map), 'Can only plot Map objects.' if mesh is None: if f.mesh is not None: mesh = f.mesh else: mesh_error = 'Mesh must be specified, either explicitly, '+\ 'or as part of the Function.' raise Exception(mesh_error) x0, x1, y0, y1 = mesh.bounding_box() system = Assembler() if shading: # # Colormap # # Define Grid nx, ny = resolution x, y = np.linspace(x0, x1, nx), np.linspace(y0, y1, ny) xx, yy = np.meshgrid(x, y) xy = np.array([xx.ravel(), yy.ravel()]).transpose() # Evaluate function zz = f.eval(xy, derivative=derivative) z_min, z_max = zz.min(), zz.max() if grid: alpha = 0.5 else: alpha = 1 axis.plot_surface(xx,yy,zz.reshape(xx.shape),cmap='viridis', \ linewidth=1, antialiased=True, alpha=alpha) self.exit(axis=axis) if grid: # # Wirefunction # ne = edge_resolution lines = [] node_count = 0 initialize_min_max = True for node in mesh.root_node().get_leaves(): # # Function type # if callable(f): # # Explicit function # assert derivative==(0,),\ 'Discretize before plotting derivatives.' f_loc = f elif isinstance(f, Map): # # Function object # f_loc = f elif len(f) == system.n_dofs(): # # Nodal function # f_loc = f[system.get_global_dofs(node)] elif len(f) == mesh.n_nodes(): # # Mesh function # f_loc = f[node_count] cell = node.cell() for edge in cell.get_edges(): # Points on edges v = edge.vertex_coordinates() x0, y0 = v[0] x1, y1 = v[1] t = np.linspace(0, 1, ne) xx = (1 - t) * x0 + t * x1 yy = (1 - t) * y0 + t * y1 # Evaluate function at edge points zz = system.f_eval_loc(f_loc, node, x=np.array([xx,yy]).T, \ derivatives=derivative) if initialize_min_max: z_min = zz.min() z_max = zz.max() initialize_min_max = False else: z_max = max(zz.max(), z_max) z_min = min(zz.min(), z_min) for i in range(ne - 1): lines.append([(xx[i], yy[i], zz[i]), (xx[i + 1], yy[i + 1], zz[i + 1])]) node_count += 1 axis.add_collection( Line3DCollection(lines, colors='k', linewidth=0.5)) x0, x1, y0, y1 = mesh.box() hx = x1 - x0 hy = y1 - y0 hz = z_max - z_min spc = 0.1 #print(z_min,z_max) axis.set_xlim(x0 - spc * hx, x1 + spc * hx) axis.set_ylim(y0 - spc * hy, y1 + spc * hy) axis.set_zlim(z_min - spc * hz, z_max + spc * hz) return axis