def run(self): domain = self._create_domain() mesh = generate_mesh(domain, MESH_PTS) # fe.plot(mesh) # plt.show() self._create_boundary_expression() Omega = fe.FiniteElement("Lagrange", mesh.ufl_cell(), 1) R = fe.FiniteElement("Real", mesh.ufl_cell(), 0) W = fe.FunctionSpace(mesh, Omega*R) Theta, c = fe.TrialFunction(W) v, d = fe.TestFunctions(W) sigma = self.conductivity LHS = (sigma * fe.inner(fe.grad(Theta), fe.grad(v)) + c*v + Theta*d) * fe.dx RHS = self.boundary_exp * v * fe.ds w = fe.Function(W) fe.solve(LHS == RHS, w) Theta, c = w.split() print(c(0, 0)) # fe.plot(Theta, "solution", mode='color', vmin=-3, vmax=3) # plt.show() plot(fe.interpolate(Theta, fe.FunctionSpace(mesh, Omega)), mode='color') plt.show()
def run(self): e_domain = self._create_e_domain() mesh = generate_mesh(e_domain, MESH_PTS) self._create_boundary_expression() Omega_e = fe.FiniteElement("Lagrange", mesh.ufl_cell(), 1) Omega_i = fe.FiniteElement("Lagrange", self.passive_seg.mesh.ufl_cell(), 1) Omega = fe.FunctionSpace(mesh, Omega_e * Omega_i) Theta_e, Theta_i = fe.TrialFunction(Omega) v_e, v_i = fe.TestFunctions(Omega) sigma_e, sigma_i = 0.3, 0.4 LHS = sigma_e * fe.inner(fe.grad(Theta_e), fe.grad(v_e)) * fe.dx # poisson LHS += sigma_i * fe.inner(fe.grad(Theta_i), fe.grad(v_i)) * fe.dx # poisson LHS -= sigma_e * fe.grad(Theta_e) * v_e * fe.ds # current LHS += sigma_i * fe.grad(Theta_i) * v_i * fe.ds # current RHS = self.boundary_exp * v_e * fe.ds # source term # TODO: solve Poisson in extracellular space w = fe.Function(Omega) fe.solve(LHS == RHS, w) Theta_e, Theta_i = w.split() plot(fe.interpolate(Theta, fe.FunctionSpace(mesh, Omega)), mode='color') plt.show() # Set the potential just inside the membrane to Ve (just computed) # minus V_m (from prev timestep) self.passive_seg.set_v(Theta, self.passive_seg_vm) # Solve for the potential and current inside the passive cell self.passive_seg.run() # Use Im to compute a new Vm for the next timestep, eq (8) self.passive_seg_vm = self.passive_seg_vm + self.dt / self.cm * ( self.passive_seg_im - self.passive_seg_vm / self.rm)
"""Compute some quantity in each node of a mesh (by looping on the nodes) and then build a piecewise linear function with computed nodal values.""" from dolfin import * from vtkplotter.dolfin import plot def f(coordinate): return coordinate[0] * coordinate[1] mesh = UnitSquareMesh(10, 10) V = FunctionSpace(mesh, "CG", 1) g = Function(V) coords = V.tabulate_dof_coordinates() for i in range(V.dim()): g.vector()[i] = f(coords[i]) plot(g, text=__doc__)
''' Mark mesh with boundary function ''' from dolfin import * mesh = UnitCubeMesh(5, 5, 5) V = FunctionSpace(mesh, "Lagrange", 1) class left(SubDomain): def inside(self, x, on_boundary): return on_boundary and abs(x[0]) < DOLFIN_EPS left = left() tcond = MeshFunction("size_t", mesh, 0) tcond.set_all(0) left.mark(tcond, 1) ################################## from vtkplotter.dolfin import plot plot(tcond, cmap='cool', elevation=20, text=__doc__)
solver.parameters["convergence_criterion"] = "incremental" solver.parameters["relative_tolerance"] = 1e-6 # Step in time from vtkplotter.dolfin import plot t = 0 T = 10 * dt scalarbar = False while t < T: t += dt u0.vector()[:] = u.vector() solver.solve(problem, u.vector()) if t == T: scalarbar = 'horizontal' plot( u.split()[0], z=t * 2e4, add=True, # do not clear the canvas style=0, lw=0, scalarbar=scalarbar, elevation=-3, # move camera a bit azimuth=1, text='time: ' + str(t * 2e4), lighting='plastic', interactive=0) plot()
# Define variational problem (u, p) = TrialFunctions(W) (v, q) = TestFunctions(W) f = Constant((0, 0)) a = (inner(grad(u), grad(v)) - div(v) * p + q * div(u)) * dx L = inner(f, v) * dx w = Function(W) solve(a == L, w, bcs, solver_parameters={'linear_solver': 'mumps'}) tf = time() print("time to solve:", tf - t0) # Split the mixed solution using a shallow copy (u, p) = w.split() ######################################################## vtkplotter: f = r'-\nabla \cdot(\nabla u+p I)=f ~\mathrm{in}~\Omega' formula = Latex(f, pos=(0.55, 0.45, -.05), s=0.1) plot(u, formula, at=0, N=2, text="velocity", mode='mesh and arrows', scale=.03, wire=1, scalarbar=False, style=1) plot(p, at=1, text="pressure", cmap='jet')
# Pressure correction b2 = assemble(L2) [bc.apply(A2, b2) for bc in bcp] [bc.apply(p1.vector()) for bc in bcp] solve(A2, p1.vector(), b2, "bicgstab", prec) # Velocity correction b3 = assemble(L3) [bc.apply(A3, b3) for bc in bcu] solve(A3, u1.vector(), b3, "bicgstab", "default") # Move to next time step u0.assign(u1) t += dt # Plot solution plot(u1, mode='mesh and arrows', text="Velocity of fluid", bg='w', cmap='jet', scale=0.3, # unit conversion factor scalarbar=False, interactive=False) pb.print() plot()
""" import mshr import dolfin from vtkplotter.dolfin import datadir, plot fname = "shuttle.stl" surface = mshr.Surface3D(datadir + fname) # add a cylinder cyl = mshr.Cylinder(dolfin.Point(-1.4, 0, 0), dolfin.Point(-1.0, 0, 0), 0.5, 0.7) totdomain = surface + cyl polyhedral_domain = mshr.CSGCGALDomain3D(totdomain) dolfin.info(polyhedral_domain, True) generator = mshr.CSGCGALMeshGenerator3D() #### Try automatic generator.parameters["mesh_resolution"] = 35.0 mesh = generator.generate(polyhedral_domain) xmlname = fname.split(".")[0] + ".xml" dolfin.File(xmlname) << mesh print(mesh, "saved to " + xmlname) ################################## plot(mesh, text=__doc__) ##################################
xdmffile_u.write(u_, t) xdmffile_p.write(p_, t) # Save nodal values to file timeseries_u.store(u_.vector(), t) timeseries_p.store(p_.vector(), t) # Update previous solution u_n.assign(u_) p_n.assign(p_) # Update progress bar print('n:', n) # Plot solution plot( u_, cmap='bone', scalarbar=False, bg='w', axes=0, # no axes interactive=False, ) plot(u_, cmap='bone', scalarbar='h', title='Velocity', text=__doc__, interactive=True)
""" Visualize a Fenics/dolfin mesh. Select mesh and press X to slice it. """ import dolfin from vtkplotter.dolfin import plot, datadir mesh1 = dolfin.Mesh(datadir + "dolfin_fine.xml") plot(mesh1) # show another light-green mesh in a new plotter window, # show file header too as an additional text comment mesh2 = dolfin.UnitCubeMesh(8,8,8) plot(mesh2, text=__doc__, color='lg', newPlotter=True)
"+cos(atan2(x[1]/b, x[0]))*sin(nharmonic*atan2(x[1]/b, x[0]))") bc = DirichletBC(W.sub(0), Expression(flow_profile, degree=2, b=b, nharmonic=2), "on_boundary") # Define trial and test functions (u, p) = TrialFunctions(W) (v, q) = TestFunctions(W) def epsilon(u): return grad(u) + nabla_grad(u) a = inner(mu*epsilon(u) + p*Identity(2), epsilon(v))*dx -div(u)*q*dx -1e-10*p*q*dx L = dot(force, v)*dx + g*q*dx # Solve system U = Function(W) solve(a == L, U, bc) # Get sub-functions u, p = U.split() from vtkplotter.dolfin import plot plot(u, mode='mesh and arrows', scale=0.1, warpZfactor=-0.1, lw=0, scalarbar='horizontal', axes={'xLabelSize':0.01,'yLabelSize':0.01, 'ztitle':''}, title="Velocity")
bc1 = DirichletBC(W.sub(0), inflow, sub_domains, 1) bcs = [bc0, bc1] # Define variational problem (u, p) = TrialFunctions(W) (v, q) = TestFunctions(W) f = Constant((0, 0)) a = (inner(grad(u), grad(v)) - div(v) * p + q * div(u)) * dx L = inner(f, v) * dx w = Function(W) solve(a == L, w, bcs) # Split the mixed solution using a shallow copy (u, p) = w.split() ######################################################## vtkplotter: f = r'-\nabla \cdot(\nabla u+p I)=f ~\mathrm{in}~\Omega' formula = Latex(f, pos=(0.55, 0.45, -.05), s=0.1) plot(u, formula, at=0, N=2, mode='mesh and arrows', scale=.03, wireframe=True, scalarbar=False, style=1) plot(p, at=1, text="pressure", cmap='rainbow')
# Read velocity from file timeseries_w.retrieve(w.vector(), t) # Solve variational problem for time step solve(F == 0, u) _u_1, _u_2, _u_3 = u.split() # Update previous solution u_n.assign(u) # Plot solution plot( _u_3, at=0, # draw on renderer nr.0 shape=(2, 1), # two rows, one column size='fullscreen', cmap='bone', scalarbar=False, bg='w', axes=0, zoom=2, interactive=False) plot(_u_2, at=1, cmap='bone', zoom=2, scalarbar=False, interactive=False) pb.print(t) plot()
[bc.apply(b2) for bc in bcp] solve(A2, p_.vector(), b2) # Step 3: Velocity correction step b3 = assemble(L3) solve(A3, u_.vector(), b3) # Update previous solution u_n.assign(u_) p_n.assign(p_) # Plot solution plot( u_, cmap='tab10', lw=0, isolines={ "n": 12, "lw": 1, "c": 'black', "alpha": 0.1 }, warpZfactor=0.8, text=__doc__, axes=7, #bottom ruler ztitle='', interactive=False) print('done.') plot()
def awefem(mesh, t, source_loc=None): # Function space V = FunctionSpace(mesh, "Lagrange", 1) # Boundary condition bc = DirichletBC(V, Constant(0), "on_boundary") # Trial and test functions u = TrialFunction(V) v = TestFunction(V) # Discretization c = 6 dt = t[1] - t[0] u0 = Function(V) # u0 = uN-1 u1 = Function(V) # u1 = uN1 # Variational formulation F = (u - 2 * u1 + u0) * v * dx + (dt * c)**2 * dot( grad(u + 2 * u1 + u0) / 4, grad(v)) * dx a, L = lhs(F), rhs(F) # Solver A, b = assemble_system(a, L) solver = LUSolver(A, "mumps") solver.parameters["symmetric"] = True bc.apply(A, b) # Solution u = Function(V) # uN+1 # Source if source_loc is None: mesh_center = np.mean(mesh.coordinates(), axis=0) source_loc = Point(mesh_center) else: source_loc = Point(source_loc) # Time stepping printc('~bomb Hit F1 to interrupt.', c='yellow') pb = ProgressBar(0, len(t)) for i, t_ in enumerate(t[1:]): pb.print() b = assemble(L) delta = PointSource(V, source_loc, ricker_source(t_) * dt**2) delta.apply(b) solver.solve(u.vector(), b) u0.assign(u1) u1.assign(u) if t_ > 0.03: plot( u, warpZfactor=20, # set elevation along z vmin=.0, # sets a minimum to the color scale vmax=0.003, cmap='rainbow', # the color map style alpha=1, # transparency of the mesh lw=0.1, # linewidth of mesh scalarbar=None, #lighting='plastic', #elevation=-.3, interactive=0) # continue execution interactive()
w = TrialFunction(V) v = TestFunction(V) u = Function(V) f = Constant(-6.0) # Compute solution solve(dot(grad(w), grad(v)) * dx == f * v * dx, u, bc) f = r'-\nabla^{2} u=f' ########################################################### vtkplotter from vtkplotter.dolfin import plot, Latex, clear, show l = Latex(f, s=0.2, c='w').addPos(.6, .6, .1) acts = plot(u, l, cmap='jet', scalarbar='h', returnActorsNoShow=True) actor = acts[0] solution = actor.getPointArray(0) print('ArrayNames', actor.getArrayNames()) print('min', 'mean', 'max:') print(np.min(solution), np.mean(solution), np.max(solution), len(solution)) assert np.isclose(np.min(solution), 1., atol=1e-03) assert np.isclose(np.mean(solution), 2.0625, atol=1e-03) assert np.isclose(np.max(solution), 4., atol=1e-03) assert len(solution) == 81 print('Test poisson PASSED')
solve(a == L, uh, [bc1, bc2]) uk1, uk2 = uh.split() un.assign(uh) # # plot(uk1, warpYfactor=.0) # exit() if not i % 4: plot( uk1, frame, at=0, shape=(2, 1), # plot on first of 2 renderers warpYfactor=2.0, # warp y-axis with solution uk1 lw=3, # line width lc='white', # line color ytitle="diplacement at T=%g" % (i * dt), scalarbar=False, bg='bb', interactive=False, ) plot( uk2, frame, at=1, # plot on second of 2 renderers warpYfactor=0.2, lw=3, lc='tomato', ytitle="velocity [a.u.]", scalarbar=False,
super().__init__(**kwargs) def eval(self, values, x): values[0] = self.u1(x) / self.u2(x) def value_shape(self): return () f0 = MyExpression(u1, u2, degree=1) plot( interpolate(f0, V), warpYfactor=0.5, # y-scaling of the solution lc='navy', # line color and width lw=3, xtitle="time [sec]", ytitle="velocity [a.u.]", bg='white', # background color axes={ 'xyGrid': True, 'xyPlaneColor': 'blue', 'xyGridColor': 'peru', 'xyAlpha': 0.1, 'yHighlightZero': True, }, scalarbar=False, zoom=1.2, ) #screenshot() # uncomment to take a screenshot
subdomain_0.mark(materials, 0) subdomain_1.mark(materials, 1) dx = Measure("dx", domain=mesh, subdomain_data=materials) A_z = Function(V) # magnetic vector potential v = TestFunction(V) J = 5.0e6 # anisotropic material parameters, reluctivity = 1/constants.mu_0 reluctivity = as_matrix( ((1 / (constants.mu_0 * 1000), 0), (0, 1 / (constants.mu_0 * 1)))) F = inner(reluctivity * curl2D(A_z), curl2D(v)) * dx - J * v * dx(0) solve(F == 0, A_z, bc) W = VectorFunctionSpace(mesh, "P", 1) Bx = A_z.dx(1) By = -A_z.dx(0) B = project(as_vector((Bx, By)), W) plot( B, mode='mesh and arrows', style=2, scale=0.01, lw=0, warpZfactor=-0.01, )
img = img[:,:,1] Nx, Ny = img.shape mesh = RectangleMesh(Point(0,0,0), Point(Ny*scale, Nx*scale,1), Ny, Nx) class FE_image(UserExpression): def eval_cell(self, value, x, ufc_cell): p = Cell(mesh, ufc_cell.index).midpoint() i, j = int(p[1]/scale), int(p[0]/scale) value[:] = img[-(i+1), j] def value_shape(self): return () y = FE_image() V = FunctionSpace(mesh, 'Lagrange', 1) u = Function(V) u.interpolate(y) cam = dict(pos=(10.6, 3.71, 22.7), focalPoint=(10.6, 3.71, -1.04e-3), viewup=(0, 1.00, 0), distance=22.7, clippingRange=(21.3, 24.6)) # press C to get this lines of code plot(u, text=__doc__, camera=cam, lw=0.1, cmap='Greens_r', size=(600,300) )
A = assemble(a) B = assemble(L) # Apply point sources: ptSrcLocation = Point(1 - DOLFIN_EPS, 1 - DOLFIN_EPS) # Vectorial point load: f = [0.01, 0.02] # Distinct point sources for x- and y-components ptSrc_x = PointSource(V.sub(0), ptSrcLocation, f[0]) ptSrc_y = PointSource(V.sub(1), ptSrcLocation, f[1]) ptSrcs = [ptSrc_x, ptSrc_y] # Apply to RHS of linear system: for ptSrc in ptSrcs: ptSrc.apply(B) # Apply BCs: for bc in [bc1, bc2]: bc.apply(A) bc.apply(B) # Solve: u = Function(V) solve(A, u.vector(), B) # Plot results: txt = Text2D(__doc__) plot(u, txt, mode="displacement")
# Create mesh and define function space mesh = UnitSquareMesh(8, 8) V = FunctionSpace(mesh, "P", 1) # Define boundary condition uD = Expression("1 + x[0]*x[0] + 2*x[1]*x[1]", degree=2) bc = DirichletBC(V, uD, "on_boundary") # Define variational problem w = TrialFunction(V) v = TestFunction(V) u = Function(V) f = Constant(-6.0) # Compute solution solve(dot(grad(w), grad(v)) * dx == f * v * dx, u, bc) f = r'-\nabla^{2} u=f' ########################################################### vtkplotter from vtkplotter.dolfin import plot, Latex, clear l = Latex(f, s=0.2, c='w').addPos(.6, .6, .1) plot(u, l, cmap='jet', scalarbar='h', text=__doc__) # Now show uD values on the boundary of a much finer mesh clear() bmesh = BoundaryMesh(UnitSquareMesh(80, 80), "exterior") plot(uD, bmesh, cmap='cool', ps=5, legend='boundary') # ps = point size
f = Constant((0, 0)) a = (inner(grad(u), grad(v)) - div(v)*p + q*div(u))*dx L = inner(f, v)*dx w = Function(W) solve(a == L, w, bcs) # Split the mixed solution using a shallow copy (u, p) = w.split() ##################################################################### vtkplotter f = r'-\nabla \cdot(\nabla u+p I)=f ~\mathrm{in}~\Omega' formula = Latex(f, pos=(0.55,0.45,-.05), s=0.1) plot(u, formula, at=0, N=2, mode='mesh and arrows', scale=.03, wireframe=True, scalarbar=False, style=1) plot(p, at=1, text="pressure", cmap='rainbow', interactive=False) ##################################################################### streamlines # A list of seed points (can be automatic: just comment out 'probes') ally = np.linspace(0,1, num=100) probes = np.c_[np.ones_like(ally), ally, np.zeros_like(ally)] plot(u, mode='mesh with streamlines', streamlines={'tol':0.02, # control density of streams 'lw':2, # line width 'direction':'forward', # direction of integration 'maxPropagation':1.2, # max length of propagation
# Set matrix operator solver.setOperators(A) # Compute solution solver.setMonitor(lambda ksp, its, rnorm: print( "Iteration: {}, rel. residual: {}".format(its, rnorm))) solver.solve(b, u.vector) #solver.view() ############################### Plot solution from vtkplotter.dolfin import plot plot(u, mode="displaced mesh", scalarbar=False, axes=1, bg='white', viewup='z', offscreen=1) ################################################################################# import numpy as np from vtkplotter import settings, screenshot actor = settings.plotter_instance.actors[0] solution = actor.scalars(0) screenshot('elasticbeam.png') print('ArrayNames', actor.getArrayNames()) print('min', 'mean', 'max, N:') print(np.min(solution), np.mean(solution), np.max(solution), len(solution))
""" Scale a mesh asymmetrically in one coordinate """ from dolfin import * from mshr import * domain = Rectangle(Point(0.0, 0.0), Point(5.0, 0.01)) mesh = generate_mesh(domain, 20) V = FunctionSpace(mesh, "CG", 2) e = Expression("sin(2*pi*(x[0]*x[0]+x[1]*x[1]))", degree=2) f = interpolate(e, V) #################################################### from vtkplotter.dolfin import plot plt = plot( f, warpZfactor=0.05, # add z elevation proportional to expression style=1, lw=0, xtitle='y-coord is scaled by factor 100', text=__doc__, interactive=False) plt.actors[0].scale([1, 100, 1]) # retrieve actor object and scale y plt.show(interactive=True) # refresh scene
from dolfin import * from mshr import Circle, generate_mesh from vtkplotter.dolfin import plot, printc, Latex # Credits: # https://github.com/pf4d/fenics_scripts/blob/master/pi_estimate.py domain = Circle(Point(0.0, 0.0), 1.0) for res in [2**k for k in range(7)]: mesh = generate_mesh(domain, res) A = assemble(Constant(1) * dx(domain=mesh)) printc("resolution = %i, \t A-pi = %.5e" % (res, A - pi)) printc('~pi is about', A, c='yellow') l = Latex(r'\mathrm{Area}(r)=\pi=\int\int_D 1 \cdot d(x,y)', s=0.3) l.crop(0.3, 0.3).z(0.1) # crop invisible top and bottom and set at z=0.1 plot(mesh, l, alpha=0.4, style=1, axes=3)
import numpy as np tol = 0.001 # avoid hitting points outside the domain y = np.linspace(-1 + tol, 1 - tol, 101) points = [(0, y_) for y_ in y] # 2D points w_line = np.array([w(point) for point in points]) p_line = np.array([p(point) for point in points]) ####################################################################### from vtkplotter.dolfin import plot from vtkplotter import Line, Latex pde = r'-T \nabla^{2} D=p, ~\Omega=\left\{(x, y) | x^{2}+y^{2} \leq R\right\}' tex = Latex(pde, pos=(0, 1.1, .1), s=0.2, c='w') wline = Line(y, w_line * 10, c='white', lw=4) pline = Line(y, p_line / 4, c='lightgreen', lw=4) plot(w, wline, tex, at=0, N=2, bg='bb', text='Deflection') plot(p, pline, at=1, text='Load') ####################################################################### #import matplotlib.pyplot as plt #plot(w) #plt.plot(y, 50*w_line, 'k', linewidth=2) # magnify w #plt.plot(y, p_line, 'b--', linewidth=2) #plt.grid(True) #plt.xlabel('$y$') #plt.legend(['Deflection ($\\times 50$)', 'Load'], loc='upper left') #plt.show()
# Measures # dx should be same for E and I (the form arguments are only from one mesh, # so the mesh is implicit), but define here just to be safe dx_i = Measure("dx")(domain=mesh_i) dx_e = Measure("dx")(domain=mesh_e) ds = Measure("ds")(domain=mesh_e, subdomain_data=boundaries) # dS not used (no integration over internal facets) # Normal vectors to facets ni = FacetNormal(mesh_i) ne = FacetNormal(mesh_e) LHS = inner(grad(Vi), grad(vi)) * dx_i # Poisson LHS += inner(grad(Ve), grad(ve)) * dx_e # Poisson # LHS += (inner(ni, grad(Vi)) * vi - inner(ne, grad(Ve)) * ve) * ds(INTERFACE) # continuous current # LHS += grad(Vi) * vi * ds # LHS += grad(Ve) * ve * ds soln = Function(IE) solve(LHS == 0, soln, [ DirichletBC(IE, 1.0, boundaries, LEFTEDGE), DirichletBC(IE, 2.0, boundaries, BOTTOMEDGE) ]) Vi, Ve = soln.sub(0), soln.sub(1) from vtkplotter.dolfin import plot plot(Ve) import ipdb ipdb.set_trace()
""" Interpolate functions between finite element spaces on non-matching meshes. """ # https://fenicsproject.org/docs/dolfin/2018.1.0/python/demos # /nonmatching-interpolation/demo_nonmatching-interpolation.py.html from dolfin import * mesh1 = UnitSquareMesh(16, 16) mesh3 = UnitSquareMesh(64, 64) P1 = FunctionSpace(mesh1, "Lagrange", 1) P3 = FunctionSpace(mesh3, "Lagrange", 3) v = Expression("sin(10*x[0])*sin(10*x[1])", degree=5) # Create function on P3 and interpolate v v3 = Function(P3) v3.interpolate(v) # Create function on P1 and interpolate v3 v1 = Function(P1) v1.interpolate(v3) ######################################### vtkplotter from vtkplotter.dolfin import plot # Plot v1 and v3 on 2 synced renderers plot(v1, at=0, N=2, text='coarse mesh') plot(v3, at=1, N=2, text='finer mesh', interactive=True)
# Step 1: Tentative velocity step b1 = assemble(L1) [bc.apply(b1) for bc in bcu] solve(A1, u_.vector(), b1) # Step 2: Pressure correction step b2 = assemble(L2) [bc.apply(b2) for bc in bcp] solve(A2, p_.vector(), b2) # Step 3: Velocity correction step b3 = assemble(L3) solve(A3, u_.vector(), b3) # Update previous solution u_n.assign(u_) p_n.assign(p_) # Plot solution plot( u_, cmap='plasma', scalarbar=False, bg='w', axes=7, # bottom ruler interactive=False, ) plot(u_, cmap='plasma', text=__doc__, interactive=True)