def __init__(self, *args, **kwargs): "Create Dirichlet boundary condition" # Copy constructor if len(args) == 1: if not isinstance(args[0], cpp.DirichletBC): cpp.dolfin_error("bcs.py", "create DirichletBC", "Expecting a DirichleBC as only argument"\ " for copy constructor") # Initialize base class cpp.DirichletBC.__init__(self, args[0]) return # Special case for value specified as float, tuple or similar if len(args) >= 2 and not isinstance(args[1], cpp.GenericFunction): if isinstance(args[1], ufl.classes.Expr): expr = project(args[1], args[0]) else: expr = Constant(args[1]) # let Constant handle all problems args = args[:1] + (expr,) + args[2:] # Special case for sub domain specified as a function if len(args) >= 3 and isinstance(args[2], types.FunctionType): sub_domain = AutoSubDomain(args[2]) args = args[:2] + (sub_domain,) + args[3:] # Special case for sub domain specified as a string if len(args) >= 3 and isinstance(args[2], str): sub_domain = compile_subdomains(args[2]) args = args[:2] + (sub_domain,) + args[3:] # Store Expression to avoid scoping issue with SWIG directors if isinstance(args[1], cpp.Expression): self.function_arg = args[1] # Store SubDomain to avoid scoping issue with SWIG directors self.domain_args = args[2:] # FIXME: Handling of multiple default arguments does not # really work between Python and C++ when C++ requires them to # be ordered and cannot accept the latter without the # former... # Add keyword arguments (in correct order...) allowed_kwargs = ["method", "check_midpoint"] for key in allowed_kwargs: if key in kwargs: args = tuple(list(args) + [kwargs[key]]) # Check for other keyword arguments for key in kwargs: if not key in allowed_kwargs: cpp.dolfin_error("bcs.py", "create boundary condition", "Unknown keyword argument \"%s\"" % key) # Initialize base class cpp.DirichletBC.__init__(self, *args)
def __init__(self, *args, **kwargs): "Create Dirichlet boundary condition" # Copy constructor if len(args) == 1: if not isinstance(args[0], cpp.DirichletBC): cpp.dolfin_error("bcs.py", "create DirichletBC", "Expecting a DirichleBC as only argument"\ " for copy constructor") # Initialize base class cpp.DirichletBC.__init__(self, args[0]) self.domain_args = args[0].domain_args return # Special case for value specified as float, tuple or similar if len(args) >= 2 and not isinstance(args[1], cpp.GenericFunction): if isinstance(args[1], ufl.classes.Expr): expr = project(args[1], args[0]) else: expr = Constant(args[1]) # let Constant handle all problems args = args[:1] + (expr, ) + args[2:] # Special case for sub domain specified as a function if len(args) >= 3 and isinstance(args[2], types.FunctionType): sub_domain = AutoSubDomain(args[2]) args = args[:2] + (sub_domain, ) + args[3:] # Special case for sub domain specified as a string if len(args) >= 3 and isinstance(args[2], str): sub_domain = CompiledSubDomain(args[2]) args = args[:2] + (sub_domain, ) + args[3:] # Store Expression to avoid scoping issue with SWIG directors if isinstance(args[1], cpp.Expression): self.function_arg = args[1] # Store SubDomain to avoid scoping issue with SWIG directors self.domain_args = args[2:] # FIXME: Handling of multiple default arguments does not # really work between Python and C++ when C++ requires them to # be ordered and cannot accept the latter without the # former... # Add keyword arguments (in correct order...) allowed_kwargs = ["method", "check_midpoint"] for key in allowed_kwargs: if key in kwargs: args = tuple(list(args) + [kwargs[key]]) # Check for other keyword arguments for key in kwargs: if not key in allowed_kwargs: cpp.dolfin_error("bcs.py", "create boundary condition", "Unknown keyword argument \"%s\"" % key) # Initialize base class cpp.DirichletBC.__init__(self, *args)
def compute_projection_error(mesh_resolution=20, p_order=1): # Define domain and mesh a, b = 0, 1 mesh = IntervalMesh(mesh_resolution, a, b) # Define finite element function space V = FunctionSpace(mesh, "CG", p_order) # Extract vertices of the mesh x = V.tabulate_dof_coordinates() # Note: Not the same as x = mesh.coordinates() (apparently has been re-ordered) # Express the analytical function u = Expression("1 + 4 * x[0] * x[0] - 5 * x[0] * x[0] * x[0]", degree=5) # Project u onto V and extract the values in the mesh nodes Pu = project(u, V) Pua = Pu.vector().array() # Create a function in the finite element function space V Eu = Function(V) Eua = Eu.vector().array() # Evaluate function in the mesh nodes for i in range(len(x)): Eua[i] = 1 + 4 * x[i]**2 - 5 * x[i]**3 # Compute sum of projection error in the nodes e = Eua - Pua error = 0 for i in range(len(e)): error += abs(e[i]) return error
def compute_projection_error(mesh_resolution=20, p_order=1): # Define domain and mesh a, b = 0, 1 mesh = IntervalMesh(mesh_resolution, a, b) # Define finite element function space V = FunctionSpace(mesh, "CG", p_order) # Extract vertices of the mesh x = V.dofmap().tabulate_all_coordinates(mesh) indices = np.argsort(x) # Express the analytical function u = Expression("1 + 4 * x[0] * x[0] - 5 * x[0] * x[0] * x[0]", degree=5) # Project u onto V and extract the values in the mesh nodes Pu = project(u, V) Pua = Pu.vector().array() # Create a function in the finite element function space V Eu = Function(V) Eua = Eu.vector().array() # Evaluate function in the mesh nodes for j in indices: Eua[j] = 1 + 4 * x[j] * x[j] - 5 * x[j] * x[j] * x[j] # Compute sum of projection error in the nodes e = Eua - Pua error = 0 for i in range(len(e)): error += abs(e[i]) return error
def compare_errors(p_order=1): # Express the analytical function u = Expression("1 + sin(10*x[0])", degree=5) mesh_resolutions = [10, 50, 100, 200] projection_errors = [] interpolation_errors = [] for mesh_resolution in mesh_resolutions: # Define mesh mesh = UnitIntervalMesh(mesh_resolution) # Define finite element function space V = FunctionSpace(mesh, "CG", p_order) # Compute projection up = project(u, V) # Compute interpolation ui = interpolate(u, V) # Compute errors projection_errors.append(compute_error(u, up)) interpolation_errors.append(compute_error(u, ui)) print(projection_errors) print(interpolation_errors)
def computeError4level(self, meanApprox4lvl, lastSpace, meanExact = None): if meanExact == None: solMesh = lastSpace.mesh() solFamily = lastSpace.ufl_element().family() solDegree = lastSpace.ufl_element().degree() refSpace = FunctionSpace(refine(refine(solMesh)), solFamily, solDegree) meanExact = self.solveMean(refSpace) refSpace = meanExact.function_space() error4lvl = list( np.sqrt(assemble( (project(meanApprox, refSpace) - interpolate(meanExact, refSpace)) ** 2 * dx )) for meanApprox in meanApprox4lvl) return error4lvl
def __init__(self, *args, **kwargs): "Create Dirichlet boundary condition" # Copy constructor if len(args) == 1: if not isinstance(args[0], cpp.DirichletBC): cpp.dolfin_error("bcs.py", "create DirichletBC", "Expecting a DirichleBC as only argument"\ " for copy constructor") # Initialize base class cpp.DirichletBC.__init__(self, args[0]) return # Special case for value specified as float, tuple or similar if len(args) >= 2 and not isinstance(args[1], cpp.GenericFunction): if isinstance(args[1], ufl.classes.Expr): expr = project(args[1], args[0]) else: expr = Constant(args[1]) # let Constant handle all problems args = args[:1] + (expr,) + args[2:] # Special case for sub domain specified as a function if len(args) >= 3 and isinstance(args[2], types.FunctionType): sub_domain = AutoSubDomain(args[2]) args = args[:2] + (sub_domain,) + args[3:] # Special case for sub domain specified as a string if len(args) >= 3 and isinstance(args[2], str): sub_domain = compile_subdomains(args[2]) args = args[:2] + (sub_domain,) + args[3:] # Store Expression to avoid scoping issue with SWIG directors if isinstance(args[1], cpp.Expression): self.function_arg = args[1] # Store SubDomain to avoid scoping issue with SWIG directors self.domain_args = args[2:] # Add method argument if it's given if "method" in kwargs: args = tuple(list(args) + [kwargs["method"]]) # Initialize base class cpp.DirichletBC.__init__(self, *args)
def plot(object, *args, **kwargs): """ Plot given object. *Arguments* object a :py:class:`Mesh <dolfin.cpp.Mesh>`, a :py:class:`MeshFunction <dolfin.cpp.MeshFunction>`, a :py:class:`Function <dolfin.functions.function.Function>`, a :py:class:`Expression` <dolfin.cpp.Expression>, a :py:class:`DirichletBC` <dolfin.cpp.DirichletBC> or a :py:class:`FiniteElement <ufl.FiniteElement>`. *Examples of usage* In the simplest case, to plot only e.g. a mesh, simply use .. code-block:: python mesh = UnitSquare(4,4) plot(mesh) Use the ``title`` argument to specify title of the plot .. code-block:: python plot(mesh, tite="Finite element mesh") It is also possible to plot an element .. code-block:: python element = FiniteElement("BDM", tetrahedron, 3) plot(element) Vector valued functions can be visualized with an alternative mode .. code-block:: python plot(u, mode = "glyphs") A more advanced example .. code-block:: python plot(u, wireframe = True, # use wireframe rendering interactive = False, # do not hold plot on screen scalarbar = False, # hide the color mapping bar hardcopy_prefix = "myplot", # default plotfile name scale = 2.0 # scale the warping/glyphs title = "Fancy plot" # Set your own title ) """ # Plot element if isinstance(object, ufl.FiniteElementBase): if os.environ.get("DOLFIN_NOPLOT", "0") != "0": return import ffc return ffc.plot(object, *args, **kwargs) # Get mesh from explicit mesh kwarg, only positional arg, or via object mesh = kwargs.pop('mesh', None) if isinstance(object, cpp.Mesh): if mesh is not None and mesh.id() != object.id(): cpp.dolfin_error( "plotting.py", "plot mesh", "Got different mesh in plot object and keyword argument") mesh = object if mesh is None: if isinstance(object, cpp.Function): mesh = object.function_space().mesh() elif hasattr(object, "mesh"): mesh = object.mesh() # Expressions do not carry their own mesh if isinstance(object, cpp.Expression) and mesh is None: cpp.dolfin_error("plotting.py", "plot expression", "Expecting a mesh as keyword argument") # Try to project if object is not a standard plottable type if not isinstance(object, _plottable_types): from dolfin.fem.projection import project try: cpp.info("Object cannot be plotted directly, projecting to"\ " piecewise linears.") object = project(object, mesh=mesh) except Exception as e: msg = "Don't know how to plot given object:\n %s\n" \ "and projection failed:\n %s" % (str(object), str(e)) cpp.dolfin_error("plotting.py", "plot object", msg) # Select backend backend = cpp.parameters["plotting_backend"] if backend == "vtk": return _plot_cpp(object, mesh, kwargs) elif backend == "matplotlib": return _plot_matplotlib(object, mesh, kwargs)
### pvdFileU = File(outputFolder+"/u.pvd", "compressed") pvdFileV = File(outputFolder+"/v.pvd", "compressed") pvdFileStress = File(outputFolder+"/stress.pvd", "compressed") ## Save sub domains to VTK files #bndFile = File(outputFolder+"/subdomains.pvd") #bndFile << neumannSubdomains ### ### Solver ### # Class representing the initial conditions u0 = project(physics.u0, V) v0 = project(physics.v0, V) # Initial condition tk = physics.t0 u = u0 v = v0 # Source physics.f.t = tk timef = False fk = assemble(inner(physics.f, w)*dx) if isinstance(physics.f, Expression): if 't' in physics.f.user_parameters: timef = True # Neumann boundary condition
def solve_navier_stokes_equation(interior_circle=True, num_mesh_refinements=0): """ Solve the Navier-Stokes equation on a hard-coded mesh with hard-coded initial and boundary conditions """ mesh, om, im, nm, ymax, sub_domains = setup_geometry( interior_circle, num_mesh_refinements) dsi = Measure("ds", domain=mesh, subdomain_data=sub_domains) # Setup FEM function spaces # Function space for the velocity V = VectorFunctionSpace(mesh, "CG", 1) # Function space for the pressure Q = FunctionSpace(mesh, "CG", 1) # Mixed function space for velocity and pressure W = V * Q # Setup FEM functions v, q = TestFunctions(W) w = Function(W) (u, p) = (as_vector((w[0], w[1])), w[2]) u0 = Function(V) # Inlet velocity uin = Expression(("4*(x[1]*(YMAX-x[1]))/(YMAX*YMAX)", "0."), YMAX=ymax, degree=1) # Viscosity and stabilization parameters nu = 1e-6 h = CellSize(mesh) d = 0.2 * h**(3.0 / 2.0) # Time parameters time_step = 0.1 t_start, t_end = 0.0, 10.0 # Penalty parameter gamma = 10 / h # Time stepping t = t_start step = 0 while t < t_end: # Time discretization (Crank–Nicolson method) um = 0.5 * u + 0.5 * u0 # Navier-Stokes equations in weak residual form (stabilized FEM) # Basic residual r = (inner((u - u0) / time_step + grad(p) + grad(um) * um, v) + nu * inner(grad(um), grad(v)) + div(um) * q) * dx # Weak boundary conditions r += gamma * (om * p * q + im * inner(u - uin, v) + nm * inner(u, v)) * ds # Stabilization r += d * (inner(grad(p) + grad(um) * um, grad(q) + grad(um) * v) + inner(div(um), div(v))) * dx # Solve the Navier-Stokes equation (one time step) solve(r == 0, w) if step % 5 == 0: # Plot norm of velocity at current time step nov = project(sqrt(inner(u, u)), Q) fig = plt.figure() plot(nov, fig=fig) plt.show() # Compute drag force on circle n = FacetNormal(mesh) drag_force_measure = p * n[0] * dsi(1) # Drag (only pressure) drag_force = assemble(drag_force_measure) print("Drag force = " + str(drag_force)) # Shift to next time step t += time_step step += 1 u0 = project(u, V)
def plot(object, *args, **kwargs): """ Plot given object. *Arguments* object a :py:class:`Mesh <dolfin.cpp.Mesh>`, a :py:class:`MeshFunction <dolfin.cpp.MeshFunction>`, a :py:class:`Function <dolfin.functions.function.Function>`, a :py:class:`Expression` <dolfin.cpp.Expression>, a :py:class:`DirichletBC` <dolfin.cpp.DirichletBC>, a :py:class:`FiniteElement <ufl.FiniteElement>`. *Examples of usage* In the simplest case, to plot only e.g. a mesh, simply use .. code-block:: python mesh = UnitSquare(4, 4) plot(mesh) Use the ``title`` argument to specify title of the plot .. code-block:: python plot(mesh, tite="Finite element mesh") It is also possible to plot an element .. code-block:: python element = FiniteElement("BDM", tetrahedron, 3) plot(element) Vector valued functions can be visualized with an alternative mode .. code-block:: python plot(u, mode = "glyphs") A more advanced example .. code-block:: python plot(u, wireframe = True, # use wireframe rendering interactive = False, # do not hold plot on screen scalarbar = False, # hide the color mapping bar hardcopy_prefix = "myplot", # default plotfile name scale = 2.0, # scale the warping/glyphs title = "Fancy plot", # set your own title ) """ # Return if plotting is disables if os.environ.get("DOLFIN_NOPLOT", "0") != "0": return # Return if Matplotlib is not available if not _has_matplotlib(): cpp.log.info("Matplotlib is required to plot from Python.") return # Plot element if isinstance(object, ufl.FiniteElementBase): import ffc return ffc.plot(object, *args, **kwargs) # For dolfin.function.Function, extract cpp_object if hasattr(object, "cpp_object"): object = object.cpp_object() # Get mesh from explicit mesh kwarg, only positional arg, or via # object mesh = kwargs.pop('mesh', None) if isinstance(object, cpp.mesh.Mesh): if mesh is not None and mesh.id() != object.id(): raise RuntimeError( "Got different mesh in plot object and keyword argument") mesh = object if mesh is None: if isinstance(object, cpp.function.Function): mesh = object.function_space().mesh() elif hasattr(object, "mesh"): mesh = object.mesh() # Expressions do not carry their own mesh if isinstance(object, cpp.function.Expression) and mesh is None: raise RuntimeError("Expecting a mesh as keyword argument") backend = kwargs.pop("backend", "matplotlib") if backend not in ("matplotlib", "x3dom"): raise RuntimeError("Plotting backend %s not recognised" % backend) # Try to project if object is not a standard plottable type if not isinstance(object, _all_plottable_types): from dolfin.fem.projection import project try: cpp.log.info("Object cannot be plotted directly, projecting to " "piecewise linears.") object = project(object, mesh=mesh) mesh = object.function_space().mesh() object = object._cpp_object except Exception as e: msg = "Don't know how to plot given object:\n %s\n" \ "and projection failed:\n %s" % (str(object), str(e)) raise RuntimeError(msg) # Plot if backend == "matplotlib": return _plot_matplotlib(object, mesh, kwargs) elif backend == "x3dom": return _plot_x3dom(object, kwargs) else: assert False, "This code should not be reached."
def solve_heat_equation(k, time_stepping_method): """ Solve the heat equation on a hard-coded mesh with a hard-coded initial and boundary conditions :param k: Thermal conductivity :param time_stepping_method: Time stepping method. Can be one of ["forward_euler", "backward_euler", "trapezoidal"] """ mesh, boundary = setup_geometry() # Exact solution (Gauss curve) ue = Expression("exp(-(x[0]*x[0]+x[1]*x[1])/(4*a*t))/(4*pi*a*t)", a=k, t=1e-7, domain=mesh, degree=1) # Polynomial degree r = 1 # Setup FEM function space V = FunctionSpace(mesh, "CG", r) # Create boundary condition bc = DirichletBC(V, ue, boundary) # Setup FEM functions v = TestFunction(V) u = Function(V) # Time parameters time_step = 0.001 t_start, t_end = 0.0, 20.0 # Time stepping t = t_start if time_stepping_method == "forward_euler": theta = 0.0 if time_stepping_method == "backward_euler": theta = 1.0 if time_stepping_method == "trapezoidal": theta = 0.5 u0 = ue step = 0 while t < t_end: # Intermediate value for u (depending on the chosen time stepping method) um = (1.0 - theta) * u0 + theta * u # Weak form of the heat equation a = (u - u0) / time_step * v * dx + k * inner(grad(um), grad(v)) * dx # Solve the heat equation (one time step) solve(a == 0, u, bc) # Advance time in exact solution t += time_step ue.t = t if step % 100 == 0: # Compute error in L2 norm error_L2 = errornorm(ue, u, 'L2') # or equivalently # sqrt(assemble((ue - u) * (ue - u) * dx)) # Compute norm of exact solution nue = norm(ue) # Print relative error print("Relative error = {}".format(error_L2 / nue)) # Shift to next time step u0 = project(u, V) step += 1
def plot(object, *args, **kwargs): """ Plot given object. *Arguments* object a :py:class:`Mesh <dolfin.cpp.Mesh>`, a :py:class:`MeshFunction <dolfin.cpp.MeshFunction>`, a :py:class:`Function <dolfin.functions.function.Function>`, a :py:class:`Expression` <dolfin.cpp.Expression>, a :py:class:`DirichletBC` <dolfin.cpp.DirichletBC> or a :py:class:`FiniteElement <ufl.FiniteElement>`. *Examples of usage* In the simplest case, to plot only e.g. a mesh, simply use .. code-block:: python mesh = UnitSquare(4,4) plot(mesh) Use the ``title`` argument to specify title of the plot .. code-block:: python plot(mesh, tite="Finite element mesh") It is also possible to plot an element .. code-block:: python element = FiniteElement("BDM", tetrahedron, 3) plot(element) Vector valued functions can be visualized with an alternative mode .. code-block:: python plot(u, mode = "glyphs") A more advanced example .. code-block:: python plot(u, wireframe = True, # use wireframe rendering interactive = False, # do not hold plot on screen scalarbar = False, # hide the color mapping bar hardcopy_prefix = "myplot", # default plotfile name scale = 2.0 # scale the warping/glyphs title = "Fancy plot" # Set your own title ) """ mesh = kwargs.get('mesh') p = cpp.Parameters() for key in kwargs: # If there is a "mesh" kwarg it should not be added to the parameters if key != "mesh": try: p.add(key, kwargs[key]) except TypeError: cpp.warning("Incompatible type for keyword argument \"%s\". Ignoring." % key) # Plot element if isinstance(object, ufl.FiniteElementBase): if os.environ.get("DOLFIN_NOPLOT", "0") != "0": return import ffc return ffc.plot(object, *args, **kwargs) if mesh is None and len(args) == 1 and isinstance(args[0], cpp.Mesh): mesh = args[0] # Plot expression if isinstance(object, cpp.Expression): if mesh is None: raise TypeError, "expected a mesh when plotting an expression." return cpp.plot(object, mesh, p) # Try to project if object is not a standard plottable type if not isinstance(object, (cpp.Function, cpp.Expression, cpp.Mesh, cpp.DirichletBC, cpp.MeshFunction, cpp.MeshFunctionBool, cpp.MeshFunctionInt, cpp.MeshFunctionDouble, cpp.MeshFunctionSizet, cpp.DirichletBC, cpp.CSGGeometry)): from dolfin.fem.projection import project try: cpp.info("Object cannot be plotted directly, projecting to"\ " piecewise linears.") object = project(object, mesh=mesh) except Exception as e: msg = ("Don't know how to plot given object:\n %s\n"\ "and projection failed:\n %s") % (str(object), str(e)) #raise RuntimeError(msg) raise plot_object = cpp.plot(object, p) plot_object.write_ps = _VTKPlotter_write_ps # Avoid premature deletion of plotted objects if they go out of scope # before the plot window is closed. The plotter itself is safe, since it's # created in the plot() C++ function, not directly from Python. But the # Python plotter proxy may disappear, so we can't store the references # there. global _objects_referenced_from_plot_windows _objects_referenced_from_plot_windows[plot_object.key()] = (object, mesh, p) return plot_object
for i in range(nPsi) ] ### ### Solver ### # Timestep dt = (timeInterval.tf - physics.t0) / timeInterval.nt # Dirichlet boundary condition dirichletBC = {} if 'dirichletBC' in dir(physics): for i in physics.dirichletBC: physics.dirichletBC[i].t = physics.t0 ug = project(physics.dirichletBC[i], V) dirichletBC[i] = DirichletBC(V, ug, globalBndSubdomains, i) dirichletBC[i].apply(M) dirichletBC[i].apply(R) # Preparing solvers solverM = LUSolver(M) solverMdtR = LUSolver(M + newmark.beta * dt * dt * R) solverM.parameters['reuse_factorization'] = True solverMdtR.parameters['reuse_factorization'] = True # Psi loop for iPsi in range(nPsi): if verbose: print("Psi: ", iPsi)
def __init__(self, *args, **kwargs): if len(args) == 1: if not isinstance(args[0], cpp.fem.MultiMeshDirichletBC): raise RuntimeError( "Expecting a MultiMeshDirichletBC as only argument for copy constructor" ) cpp.fem.MultiMeshDirichletBC.__init__(self, args[0]) return if not isinstance(args[0], (MultiMeshFunctionSpace, MultiMeshSubSpace)): raise RuntimeError( "Expecting MultiMeshFunctionSpace or MultiMeshSubSpace as first argument" ) if len(args) >= 2: # Check if we have an UFL-expression or a concrete type if not hasattr(args[1], "_cpp_object"): if isinstance(args[1], ufl.classes.Expr): expr = project(args[1], args[0]) # Should be interpolation else: expr = Constant(args[1]) args = args[:1] + (expr, 1) + args[2:] if isinstance(args[1], (float, int)): u = cpp.function.Constant(float(args[1])) elif isinstance(args[1], ufl.Coefficient): u = args[1]._cpp_object elif isinstance(args[1], cpp.function.GenericFunction): u = args[1] else: raise RuntimeError( "Second argument must be convertiable to a GenericFucntion") if isinstance(args[0], MultiMeshSubSpace): args = args[:1] + (u, ) + args[2:] else: args = args[:1] + (u, ) + args[2:] args = (args[0]._cpp_object, ) + args[1:] if len(args) >= 3 and isinstance(args[2], types.FunctionType): raise NotImplementedError( "User-specified subdomains not implemented") if isinstance(args[2], cpp.mesh.SubDomain): self.sub_domain = args[2] args = args[:2] + (self.sub_domain, ) + args[3:] elif isinstance(args[2], str): raise NotImplementedError( "User-specified subdomains not implemented") elif isinstance(args[2], cpp.mesh.MeshFunctionSizet): pass else: raise RuntimeError("Invalid argument") # Add kwargs if isinstance(args[-1], str): method = args[-1] else: method = kwargs.pop("method", "topological") args += (method, ) check_midpoint = kwargs.pop("check_midpoint", None) if check_midpoint is not None: args += (check_midpoint, ) if (len(kwargs) > 0): raise RuntimeError("Invalid keyword arguments", kwargs) super().__init__(*args)
def solve_wave_equation(a, symmetric=True): """ Solve the wave equation on a hard-coded mesh with a hard-coded initial and boundary conditions :param a: Wave propagation factor :param symmetric: Whether or not the problem is symmetric """ mesh, boundary = setup_geometry() # Exact solution if symmetric: ue = Expression( "(1-pow(a*t-x[0],2))*exp(-pow(a*t-x[0],2)) + (1-pow(a*t+x[0],2))*exp(-pow(a*t+x[0],2))", a=a, t=0, domain=mesh, degree=2) ve = Expression( "2*a*(a*t-x[0])*(pow(a*t-x[0],2)-2)*exp(-pow(a*t-x[0],2))" "+ 2*a*(a*t+x[0])*(pow(a*t+x[0],2)-2)*exp(-pow(a*t+x[0],2))", a=a, t=0, domain=mesh, degree=2) else: ue = Expression("(1-pow(a*t+x[0],2))*exp(-pow(a*t+x[0],2))", a=a, t=0, domain=mesh, degree=2) ve = Expression( "2*a*(a*t+x[0])*(pow(a*t+x[0],2)-2)*exp(-pow(a*t+x[0],2))", a=a, t=0, domain=mesh, degree=2) # Polynomial degree r = 1 # Setup FEM function spaces Q = FunctionSpace(mesh, "CG", r) W = VectorFunctionSpace(mesh, "CG", r, dim=2) # Create boundary conditions bcu = DirichletBC(W.sub(0), ue, boundary) bcv = DirichletBC(W.sub(1), ve, boundary) bcs = [bcu, bcv] # Setup FEM functions p, q = TestFunctions(W) w = Function(W) u, v = w[0], w[1] # Time parameters time_step = 0.05 t_start, t_end = 0.0, 5.0 # Time stepping t = t_start u0 = ue v0 = ve step = 0 while t < t_end: # Weak form of the wave equation um = 0.5 * (u + u0) vm = 0.5 * (v + v0) a1 = (u - u0) / time_step * p * dx - vm * p * dx a2 = (v - v0) / time_step * q * dx + a**2 * inner(grad(um), grad(q)) * dx # Solve the wave equation (one time step) solve(a1 + a2 == 0, w, bcs) # Advance time in exact solution t += time_step ue.t = t ve.t = t if step % 10 == 0: # Plot solution at current time step fig = plt.figure() plot(u, fig=fig) plt.show() # Compute max error at vertices vertex_values_ue = ue.compute_vertex_values(mesh) vertex_values_w = w.compute_vertex_values(mesh) vertex_values_u = np.split(vertex_values_w, 2)[0] error_max = np.max(np.abs(vertex_values_ue - vertex_values_u)) # Print error print(error_max) # Shift to next time step u0 = project(u, Q) v0 = project(v, Q) step += 1
def plot(object, *args, **kwargs): """ Plot given object. *Arguments* object a :py:class:`Mesh <dolfin.cpp.Mesh>`, a :py:class:`MeshFunction <dolfin.cpp.MeshFunction>`, a :py:class:`Function <dolfin.functions.function.Function>`, a :py:class:`Expression` <dolfin.cpp.Expression>, a :py:class:`DirichletBC` <dolfin.cpp.DirichletBC> or a :py:class:`FiniteElement <ufl.FiniteElement>`. *Examples of usage* In the simplest case, to plot only e.g. a mesh, simply use .. code-block:: python mesh = UnitSquare(4,4) plot(mesh) Use the ``title`` argument to specify title of the plot .. code-block:: python plot(mesh, tite="Finite element mesh") It is also possible to plot an element .. code-block:: python element = FiniteElement("BDM", tetrahedron, 3) plot(element) Vector valued functions can be visualized with an alternative mode .. code-block:: python plot(u, mode = "glyphs") A more advanced example .. code-block:: python plot(u, wireframe = True, # use wireframe rendering interactive = False, # do not hold plot on screen scalarbar = False, # hide the color mapping bar hardcopy_prefix = "myplot", # default plotfile name scale = 2.0 # scale the warping/glyphs title = "Fancy plot" # Set your own title ) """ mesh = kwargs.get('mesh') p = cpp.Parameters() for key in kwargs: # If there is a "mesh" kwarg it should not be added to the parameters if key != "mesh": try: p.add(key, kwargs[key]) except TypeError: cpp.warning( "Incompatible type for keyword argument \"%s\". Ignoring." % key) # Plot element if isinstance(object, ufl.FiniteElementBase): if os.environ.get("DOLFIN_NOPLOT", "0") != "0": return import ffc return ffc.plot(object, *args, **kwargs) if mesh is None and len(args) == 1 and isinstance(args[0], cpp.Mesh): mesh = args[0] # Plot expression if isinstance(object, cpp.Expression): if mesh is None: raise TypeError, "expected a mesh when plotting an expression." return cpp.plot(object, mesh, p) # Try to project if object is not a standard plottable type if not isinstance( object, (cpp.Function, cpp.Expression, cpp.Mesh, cpp.DirichletBC, cpp.MeshFunction, cpp.MeshFunctionBool, cpp.MeshFunctionInt, cpp.MeshFunctionDouble, cpp.MeshFunctionSizet, cpp.DirichletBC, cpp.CSGGeometry)): from dolfin.fem.projection import project try: cpp.info("Object cannot be plotted directly, projecting to"\ " piecewise linears.") object = project(object, mesh=mesh) except Exception as e: msg = ("Don't know how to plot given object:\n %s\n"\ "and projection failed:\n %s") % (str(object), str(e)) #raise RuntimeError(msg) raise plot_object = cpp.plot(object, p) plot_object.write_ps = _VTKPlotter_write_ps # Avoid premature deletion of plotted objects if they go out of scope # before the plot window is closed. The plotter itself is safe, since it's # created in the plot() C++ function, not directly from Python. But the # Python plotter proxy may disappear, so we can't store the references # there. global _objects_referenced_from_plot_windows _objects_referenced_from_plot_windows[plot_object.key()] = (object, mesh, p) return plot_object
def __init__(self, *args, **kwargs): # FIXME: the logic in this function is really messy and # unclear # Copy constructor if len(args) == 1: if not isinstance(args[0], cpp.fem.DirichletBC): raise RuntimeError("Expecting a DirichleBC as only argument for copy constructor") # Initialize base class cpp.fem.DirichletBC.__init__(self, args[0]) return # Get FunctionSpace if not isinstance(args[0], FunctionSpace): raise RuntimeError("First argument must be of type FunctionSpace") # FIXME: correct the below comment # Case: boundary value specified as float, tuple or similar # if len(args) >= 2 and not isinstance(args[1], (cpp.function.GenericFunction): if len(args) >= 2: # Check if we have a UFL expression or a concrete type if not hasattr(args[1], "_cpp_object"): if isinstance(args[1], ufl.classes.Expr): expr = project(args[1], args[0]) # FIXME: This should really be interpolaton (project is expensive) else: expr = Constant(args[1]) args = args[:1] + (expr,) + args[2:] # Get boundary condition field (the condition that is applied) if isinstance(args[1], float) or isinstance(args[1], int): u = cpp.function.Constant(float(args[1])) elif isinstance(args[1], ufl.Coefficient): u = args[1].cpp_object() elif isinstance(args[1], cpp.function.GenericFunction): u = args[1] else: raise RuntimeError("Second argument must be convertiable to a GenericFunction: ", args[1], type(args[1])) args = args[:1] + (u,) + args[2:] args = (args[0]._cpp_object,) + args[1:] # Case: Special sub domain 'inside' function provided as a # function if len(args) >= 3 and isinstance(args[2], types.FunctionType): # Note: using self below to avoid a problem where the user # function attached to AutoSubDomain get prematurely # destroyed. Maybe a pybind11 bug? Was the same with SWIG... self.sub_domain = AutoSubDomain(args[2]) args = args[:2] + (self.sub_domain,) + args[3:] # FIXME: for clarity, can the user provided function case be # handled here too? # Create SubDomain object if isinstance(args[2], cpp.mesh.SubDomain): self.sub_domain = args[2] args = args[:2] + (self.sub_domain,) + args[3:] elif isinstance(args[2], str): self.sub_domain = CompiledSubDomain(args[2], mpi_comm=args[0].mesh().mpi_comm()) args = args[:2] + (self.sub_domain,) + args[3:] elif isinstance(args[2], cpp.mesh.MeshFunctionSizet): self.domain_args = args[2:] else: raise RuntimeError("Invalid argument") # Add kwargs if isinstance(args[-1], str): method = args[-1] else: method = kwargs.pop("method", "topological") args += (method,) check_midpoint = kwargs.pop("check_midpoint", None) if check_midpoint is not None: args += (check_midpoint,) if (len(kwargs) > 0): raise RuntimeError("Invalid keyword arguments", kwargs) super().__init__(*args)
def plot(object, *args, **kwargs): """ Plot given object. *Arguments* object a :py:class:`Mesh <dolfin.cpp.Mesh>`, a :py:class:`MeshFunction <dolfin.cpp.MeshFunction>`, a :py:class:`Function <dolfin.functions.function.Function>`, a :py:class:`Expression` <dolfin.cpp.Expression>, a :py:class:`DirichletBC` <dolfin.cpp.DirichletBC> or a :py:class:`FiniteElement <ufl.FiniteElement>`. *Examples of usage* In the simplest case, to plot only e.g. a mesh, simply use .. code-block:: python mesh = UnitSquare(4,4) plot(mesh) Use the ``title`` argument to specify title of the plot .. code-block:: python plot(mesh, tite="Finite element mesh") It is also possible to plot an element .. code-block:: python element = FiniteElement("BDM", tetrahedron, 3) plot(element) Vector valued functions can be visualized with an alternative mode .. code-block:: python plot(u, mode = "glyphs") A more advanced example .. code-block:: python plot(u, wireframe = True, # use wireframe rendering interactive = False, # do not hold plot on screen scalarbar = False, # hide the color mapping bar hardcopy_prefix = "myplot", # default plotfile name scale = 2.0 # scale the warping/glyphs title = "Fancy plot" # Set your own title ) """ # Plot element if isinstance(object, ufl.FiniteElementBase): if os.environ.get("DOLFIN_NOPLOT", "0") != "0": return import ffc return ffc.plot(object, *args, **kwargs) # Get mesh from explicit mesh kwarg, only positional arg, or via object mesh = kwargs.pop('mesh', None) if isinstance(object, cpp.Mesh): if mesh is not None and mesh.id() != object.id(): cpp.dolfin_error("plotting.py", "plot mesh", "Got different mesh in plot object and keyword argument") mesh = object if mesh is None: if isinstance(object, cpp.Function): mesh = object.function_space().mesh() elif hasattr(object, "mesh"): mesh = object.mesh() # Expressions do not carry their own mesh if isinstance(object, cpp.Expression) and mesh is None: cpp.dolfin_error("plotting.py", "plot expression", "Expecting a mesh as keyword argument") # Try to project if object is not a standard plottable type if not isinstance(object, _plottable_types): from dolfin.fem.projection import project try: cpp.info("Object cannot be plotted directly, projecting to"\ " piecewise linears.") object = project(object, mesh=mesh) except Exception as e: msg = "Don't know how to plot given object:\n %s\n" \ "and projection failed:\n %s" % (str(object), str(e)) cpp.dolfin_error("plotting.py", "plot object", msg) # Select backend backend = cpp.parameters["plotting_backend"] if backend == "vtk": return _plot_cpp(object, mesh, kwargs) elif backend == "matplotlib": return _plot_matplotlib(object, mesh, kwargs)
def plot(object, *args, **kwargs): """ Plot given object. *Arguments* object a :py:class:`Mesh <dolfin.cpp.Mesh>`, a :py:class:`MeshFunction <dolfin.cpp.MeshFunction>`, a :py:class:`Function <dolfin.functions.function.Function>`, a :py:class:`Expression` <dolfin.cpp.Expression>, a :py:class:`DirichletBC` <dolfin.cpp.DirichletBC>, a :py:class:`FiniteElement <ufl.FiniteElement>`. *Examples of usage* In the simplest case, to plot only e.g. a mesh, simply use .. code-block:: python mesh = UnitSquare(4, 4) plot(mesh) Use the ``title`` argument to specify title of the plot .. code-block:: python plot(mesh, tite="Finite element mesh") It is also possible to plot an element .. code-block:: python element = FiniteElement("BDM", tetrahedron, 3) plot(element) Vector valued functions can be visualized with an alternative mode .. code-block:: python plot(u, mode = "glyphs") A more advanced example .. code-block:: python plot(u, wireframe = True, # use wireframe rendering interactive = False, # do not hold plot on screen scalarbar = False, # hide the color mapping bar hardcopy_prefix = "myplot", # default plotfile name scale = 2.0, # scale the warping/glyphs title = "Fancy plot", # set your own title ) """ # Return if plotting is disables if os.environ.get("DOLFIN_NOPLOT", "0") != "0": return # Return if Matplotlib is not available if not _has_matplotlib(): cpp.log.info("Matplotlib is required to plot from Python.") return # Plot element if isinstance(object, ufl.FiniteElementBase): import ffc return ffc.plot(object, *args, **kwargs) # For dolfin.function.Function, extract cpp_object if hasattr(object, "cpp_object"): object = object.cpp_object() # Get mesh from explicit mesh kwarg, only positional arg, or via # object mesh = kwargs.pop('mesh', None) if isinstance(object, cpp.mesh.Mesh): if mesh is not None and mesh.id() != object.id(): raise RuntimeError("Got different mesh in plot object and keyword argument") mesh = object if mesh is None: if isinstance(object, cpp.function.Function): mesh = object.function_space().mesh() elif hasattr(object, "mesh"): mesh = object.mesh() # Expressions do not carry their own mesh if isinstance(object, cpp.function.Expression) and mesh is None: raise RuntimeError("Expecting a mesh as keyword argument") backend = kwargs.pop("backend", "matplotlib") if backend not in ("matplotlib", "x3dom"): raise RuntimeError("Plotting backend %s not recognised" % backend) # Try to project if object is not a standard plottable type if not isinstance(object, _all_plottable_types): from dolfin.fem.projection import project try: cpp.log.info("Object cannot be plotted directly, projecting to " "piecewise linears.") object = project(object, mesh=mesh) mesh = object.function_space().mesh() object = object._cpp_object except Exception as e: msg = "Don't know how to plot given object:\n %s\n" \ "and projection failed:\n %s" % (str(object), str(e)) raise RuntimeError(msg) # Plot if backend == "matplotlib": return _plot_matplotlib(object, mesh, kwargs) elif backend == "x3dom": return _plot_x3dom(object, kwargs) else: assert False, "This code should not be reached."
def __init__(self, *args, **kwargs): # FIXME: the logic in this function is really messy and # unclear # Copy constructor if len(args) == 1: if not isinstance(args[0], cpp.fem.DirichletBC): raise RuntimeError( "Expecting a DirichleBC as only argument for copy constructor" ) # Initialize base class cpp.fem.DirichletBC.__init__(self, args[0]) return # Get FunctionSpace if not isinstance(args[0], FunctionSpace): raise RuntimeError("First argument must be of type FunctionSpace") # FIXME: correct the below comment # Case: boundary value specified as float, tuple or similar # if len(args) >= 2 and not isinstance(args[1], (cpp.function.GenericFunction): if len(args) >= 2: # Check if we have a UFL expression or a concrete type if not hasattr(args[1], "_cpp_object"): if isinstance(args[1], ufl.classes.Expr): expr = project( args[1], args[0] ) # FIXME: This should really be interpolaton (project is expensive) else: expr = Constant(args[1]) args = args[:1] + (expr, ) + args[2:] # Get boundary condition field (the condition that is applied) if isinstance(args[1], float) or isinstance(args[1], int): u = cpp.function.Constant(float(args[1])) elif isinstance(args[1], ufl.Coefficient): u = args[1].cpp_object() elif isinstance(args[1], cpp.function.GenericFunction): u = args[1] else: raise RuntimeError( "Second argument must be convertiable to a GenericFunction: ", args[1], type(args[1])) args = args[:1] + (u, ) + args[2:] args = (args[0]._cpp_object, ) + args[1:] # Case: Special sub domain 'inside' function provided as a # function if len(args) >= 3 and isinstance(args[2], types.FunctionType): # Note: using self below to avoid a problem where the user # function attached to AutoSubDomain get prematurely # destroyed. Maybe a pybind11 bug? Was the same with SWIG... self.sub_domain = AutoSubDomain(args[2]) args = args[:2] + (self.sub_domain, ) + args[3:] # FIXME: for clarity, can the user provided function case be # handled here too? # Create SubDomain object if isinstance(args[2], cpp.mesh.SubDomain): self.sub_domain = args[2] args = args[:2] + (self.sub_domain, ) + args[3:] elif isinstance(args[2], str): self.sub_domain = CompiledSubDomain( args[2], mpi_comm=args[0].mesh().mpi_comm()) args = args[:2] + (self.sub_domain, ) + args[3:] elif isinstance(args[2], cpp.mesh.MeshFunctionSizet): self.domain_args = args[2:] else: raise RuntimeError("Invalid argument") # Add kwargs if isinstance(args[-1], str): method = args[-1] else: method = kwargs.pop("method", "topological") args += (method, ) check_midpoint = kwargs.pop("check_midpoint", None) if check_midpoint is not None: args += (check_midpoint, ) if (len(kwargs) > 0): raise RuntimeError("Invalid keyword arguments", kwargs) super().__init__(*args)
def solve_heat_equation(k): """ Solve the heat equation on a hard-coded mesh with a hard-coded initial and boundary conditions :param k: Thermal conductivity """ mesh, boundary = setup_geometry() # Exact solution (Gauss curve) ue = Expression("exp(-(x[0]*x[0]+x[1]*x[1])/(4*a*t))/(4*pi*a*t)", a=k, t=1e-7, domain=mesh, degree=2) # Polynomial degree r = 1 # Setup FEM function space V = FunctionSpace(mesh, "CG", r) # Create boundary condition bc = DirichletBC(V, ue, boundary) # Setup FEM functions v = TestFunction(V) u = Function(V) # Time parameters time_step = 0.5 t_start, t_end = 0.0, 20.0 # Time stepping t = t_start u0 = ue step = 0 while t < t_end: # Weak form of the heat equation a = (u - u0) / time_step * v * dx + k * inner(grad(u), grad(v)) * dx # Solve the heat equation (one time step) solve(a == 0, u, bc) # Advance time in exact solution t += time_step ue.t = t if step % 5 == 0: # Plot solution at current time step fig = plt.figure() plot(u, fig=fig) plt.show() # Compute error in L2 norm error_L2 = errornorm(ue, u, 'L2') # or equivalently # sqrt(assemble((ue - u) * (ue - u) * dx)) # Print error print(error_L2) # Shift to next time step u0 = project(u, V) step += 1