def amg_solve(N, method): # Elasticity parameters E = 1.0e9 nu = 0.3 mu = E / (2.0 * (1.0 + nu)) lmbda = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu)) # Stress computation def sigma(v): return 2.0 * mu * sym(grad(v)) + lmbda * tr(sym( grad(v))) * Identity(2) # Define problem mesh = UnitSquareMesh(MPI.comm_world, N, N) V = VectorFunctionSpace(mesh, 'Lagrange', 1) bc0 = Function(V) with bc0.vector().localForm() as bc_local: bc_local.set(0.0) def boundary(x, only_boundary): return [only_boundary] * x.shape(0) bc = DirichletBC(V.sub(0), bc0, boundary) u = TrialFunction(V) v = TestFunction(V) # Forms a, L = inner(sigma(u), grad(v)) * dx, dot(ufl.as_vector( (1.0, 1.0)), v) * dx # Assemble linear algebra objects A = assemble_matrix(a, [bc]) A.assemble() b = assemble_vector(L) apply_lifting(b, [a], [[bc]]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) set_bc(b, [bc]) # Create solution function u = Function(V) # Create near null space basis and orthonormalize null_space = build_nullspace(V, u.vector()) # Attached near-null space to matrix A.set_near_nullspace(null_space) # Test that basis is orthonormal assert null_space.is_orthonormal() # Create PETSC smoothed aggregation AMG preconditioner, and # create CG solver solver = PETScKrylovSolver("cg", method) # Set matrix operator solver.set_operator(A) # Compute solution and return number of iterations return solver.solve(u.vector(), b)
def pot(): # Define mesh and boundaries. mesh = RectangleMesh(0.0, 0.0, 0.4, 0.1, 120, 30, "left/right") V = VectorFunctionSpace(mesh, "CG", 2) Q = FunctionSpace(mesh, "CG", 1) class LeftBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] < GMSH_EPS left_boundary = LeftBoundary() class RightBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] > 0.4 - GMSH_EPS right_boundary = RightBoundary() class LowerBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] < GMSH_EPS lower_boundary = LowerBoundary() class UpperBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] > 0.1 - GMSH_EPS upper_boundary = UpperBoundary() # Boundary conditions for the velocity. u_bcs = [ DirichletBC(V, (0.0, 0.0), lower_boundary), DirichletBC(V.sub(1), 0.0, upper_boundary), DirichletBC(V.sub(0), 0.0, right_boundary), DirichletBC(V.sub(0), 0.0, left_boundary), ] p_bcs = [] return mesh, V, Q, u_bcs, p_bcs, [lower_boundary], [right_boundary, left_boundary]
def __init__(self, u, name="Assigned Vector Function"): self.u = u assert isinstance(u, ListTensor) V = u[0].function_space() mesh = V.mesh() family = V.ufl_element().family() degree = V.ufl_element().degree() constrained_domain = V.dofmap().constrained_domain Vv = VectorFunctionSpace(mesh, family, degree, constrained_domain=constrained_domain) Function.__init__(self, Vv, name=name) self.fa = [FunctionAssigner(Vv.sub(i), V) for i, _u in enumerate(u)]
def amg_solve(N, method): # Elasticity parameters E = 1.0e9 nu = 0.3 mu = E / (2.0 * (1.0 + nu)) lmbda = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu)) # Stress computation def sigma(v): return 2.0 * mu * sym(grad(v)) + lmbda * tr(sym( grad(v))) * Identity(2) # Define problem mesh = UnitSquareMesh(MPI.comm_world, N, N) V = VectorFunctionSpace(mesh, 'Lagrange', 1) bc0 = Function(V) bc = DirichletBC(V.sub(0), bc0, lambda x, on_boundary: on_boundary) u = TrialFunction(V) v = TestFunction(V) # Forms a, L = inner(sigma(u), grad(v)) * dx, dot(ufl.as_vector( (1.0, 1.0)), v) * dx # Assemble linear algebra objects A, b = assemble_system(a, L, bc) # Create solution function u = Function(V) # Create near null space basis and orthonormalize null_space = build_nullspace(V, u.vector()) # Attached near-null space to matrix A.set_near_nullspace(null_space) # Test that basis is orthonormal assert null_space.is_orthonormal() # Create PETSC smoothed aggregation AMG preconditioner, and # create CG solver solver = PETScKrylovSolver("cg", method) # Set matrix operator solver.set_operator(A) # Compute solution and return number of iterations return solver.solve(u.vector(), b)
class SNDiscretization(Discretization): def __init__(self, problem, SN_order, verbosity=0): super(SNDiscretization, self).__init__(problem, verbosity) if self.verb > 1: print0("Obtaining angular discretization data") t_ordinates = Timer("Angular discretization data") from transport_data import ordinates_ext_module, quadrature_file from common import check_sn_order self.angular_quad = ordinates_ext_module.OrdinatesData(SN_order, self.mesh.topology().dim(), quadrature_file) self.M = self.angular_quad.get_M() self.N = check_sn_order(SN_order) ord_mat = [self.angular_quad.get_xi().tolist(), self.angular_quad.get_eta().tolist()] if self.angular_quad.get_D() == 3: ord_mat.append(self.angular_quad.get_mu().tolist()) self.ordinates_matrix = as_matrix(ord_mat) if self.verb > 2: self.angular_quad.print_info() def init_solution_spaces(self, group_GS=False): if self.verb > 1: print0("Defining function spaces" ) self.t_spaces.start() self.Vpsi1 = VectorFunctionSpace(self.mesh, "CG", self.parameters["p"], self.M) if not group_GS: self.V = MixedFunctionSpace([self.Vpsi1]*self.G) else: # Alias the solution space as Vpsi1 self.V = self.Vpsi1 self.Vphi1 = FunctionSpace(self.mesh, "CG", self.parameters["p"]) self.ndof1 = self.Vpsi1.dim() self.ndof = self.V.dim() if self.verb > 1: print0(" {0} direction(s), {1} group(s), {2}".format(self.M, self.G, "group GS" if group_GS else "full system")) print0(" NDOF (solution): {0}".format(self.ndof) ) print0(" NDOF (1gr): {0}".format(self.ndof1) ) print0(" NDOF (1dir, 1gr): {0}".format(self.Vpsi1.sub(0).dim()) ) print0(" NDOF (XS): {0}".format(self.ndof0) )
def save_tstep_solution_h5(tstep, q_, u_, newfolder, tstepfiles, constrained_domain, output_timeseries_as_vector, u_components, scalar_components, NS_parameters): """Store solution on current timestep to XDMF file.""" timefolder = path.join(newfolder, 'Timeseries') if output_timeseries_as_vector: # project or store velocity to vector function space for comp, tstepfile in tstepfiles.iteritems(): if comp == "u": if not hasattr(tstepfile, 'uv'): # First time around only V = q_['u0'].function_space() Vv = VectorFunctionSpace(V.mesh(), V.ufl_element().family(), V.ufl_element().degree(), constrained_domain=constrained_domain) tstepfile.uv = Function(Vv) tstepfile.d = dict((ui, Vv.sub(i).dofmap().collapse(Vv.mesh())[1]) for i, ui in enumerate(u_components)) # The short but timeconsuming way: #tstepfile.uv.assign(project(u_, Vv)) # Or the faster, but more comprehensive way: for ui in u_components: q_[ui].update() vals = tstepfile.d[ui].values() keys = tstepfile.d[ui].keys() tstepfile.uv.vector()[vals] = q_[ui].vector()[keys] tstepfile << (tstepfile.uv, float(tstep)) elif comp in q_: tstepfile << (q_[comp], float(tstep)) else: tstepfile << (tstepfile.function, float(tstep)) else: for comp, tstepfile in tstepfiles.iteritems(): tstepfile << (q_[comp], float(tstep)) if MPI.rank(mpi_comm_world()) == 0: if not path.exists(path.join(timefolder, "params.dat")): f = open(path.join(timefolder, 'params.dat'), 'w') cPickle.dump(NS_parameters, f)
def save_tstep_solution_h5(tstep, q_, u_, newfolder, tstepfiles, constrained_domain, output_timeseries_as_vector, u_components, scalar_components, NS_parameters): """Store solution on current timestep to XDMF file.""" timefolder = path.join(newfolder, 'Timeseries') if output_timeseries_as_vector: # project or store velocity to vector function space for comp, tstepfile in tstepfiles.iteritems(): if comp == "u": V = q_['u0'].function_space() # First time around create vector function and assigners if not hasattr(tstepfile, 'uv'): Vv = VectorFunctionSpace(V.mesh(), V.ufl_element().family(), V.ufl_element().degree(), constrained_domain=constrained_domain) tstepfile.uv = Function(Vv) tstepfile.fa = [FunctionAssigner(Vv.sub(i), V) for i, ui in enumerate(u_components)] # Assign solution to vector for i, ui in enumerate(u_components): tstepfile.fa[i].assign(tstepfile.uv.sub(i), q_[ui]) # Store solution vector tstepfile << (tstepfile.uv, float(tstep)) elif comp in q_: tstepfile << (q_[comp], float(tstep)) else: tstepfile << (tstepfile.function, float(tstep)) else: for comp, tstepfile in tstepfiles.iteritems(): tstepfile << (q_[comp], float(tstep)) if MPI.rank(mpi_comm_world()) == 0: if not path.exists(path.join(timefolder, "params.dat")): f = open(path.join(timefolder, 'params.dat'), 'w') cPickle.dump(NS_parameters, f)
def m_linear(integrator_type, mesh, subdomains, boundaries, t_start, dt, T, solution0, \ alpha_0, K_0, mu_l_0, lmbda_l_0, Ks_0, \ alpha_1, K_1, mu_l_1, lmbda_l_1, Ks_1, \ alpha, K, mu_l, lmbda_l, Ks, \ cf_0, phi_0, rho_0, mu_0, k_0,\ cf_1, phi_1, rho_1, mu_1, k_1,\ cf, phi, rho, mu, k, \ pressure_freeze): # Create mesh and define function space parameters["ghost_mode"] = "shared_facet" # required by dS dx = Measure('dx', domain=mesh, subdomain_data=subdomains) ds = Measure('ds', domain=mesh, subdomain_data=boundaries) dS = Measure('dS', domain=mesh, subdomain_data=boundaries) C = VectorFunctionSpace(mesh, "CG", 2) C = BlockFunctionSpace([C]) TM = TensorFunctionSpace(mesh, 'DG', 0) PM = FunctionSpace(mesh, 'DG', 0) n = FacetNormal(mesh) vc = CellVolume(mesh) fc = FacetArea(mesh) h = vc/fc h_avg = (vc('+') + vc('-'))/(2*avg(fc)) monitor_dt = dt f_stress_x = Constant(-1.e3) f_stress_y = Constant(-20.0e6) f = Constant((0.0, 0.0)) #sink/source for displacement I = Identity(mesh.topology().dim()) # Define variational problem psiu, = BlockTestFunction(C) block_u = BlockTrialFunction(C) u, = block_split(block_u) w = BlockFunction(C) theta = -1.0 a_time = inner(-alpha*pressure_freeze*I,sym(grad(psiu)))*dx #quasi static a = inner(2*mu_l*strain(u)+lmbda_l*div(u)*I, sym(grad(psiu)))*dx rhs_a = inner(f,psiu)*dx \ + dot(f_stress_y*n,psiu)*ds(2) r_u = [a] #DirichletBC bcd1 = DirichletBC(C.sub(0).sub(0), 0.0, boundaries, 1) # No normal displacement for solid on left side bcd3 = DirichletBC(C.sub(0).sub(0), 0.0, boundaries, 3) # No normal displacement for solid on right side bcd4 = DirichletBC(C.sub(0).sub(1), 0.0, boundaries, 4) # No normal displacement for solid on bottom side bcs = BlockDirichletBC([bcd1,bcd3,bcd4]) AA = block_assemble([r_u]) FF = block_assemble([rhs_a - a_time]) bcs.apply(AA) bcs.apply(FF) block_solve(AA, w.block_vector(), FF, "mumps") export_solution = w return export_solution, T
def karman(): #mesh = Mesh('../meshes/2d/karman.xml') mesh = Mesh('../meshes/2d/karman-coarse2.xml') V = VectorFunctionSpace(mesh, 'CG', 2) Q = FunctionSpace(mesh, 'CG', 1) # Define mesh and boundaries. class LeftBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] < DOLFIN_EPS left_boundary = LeftBoundary() class RightBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] > 2.5 - DOLFIN_EPS class LowerBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] < DOLFIN_EPS lower_boundary = LowerBoundary() class UpperBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] > 0.4-DOLFIN_EPS upper_boundary = UpperBoundary() class ObstacleBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary \ and x[0] > DOLFIN_EPS and x[0] < 2.5-DOLFIN_EPS \ and x[1] > DOLFIN_EPS and x[1] < 0.4-DOLFIN_EPS obstacle_boundary = ObstacleBoundary() # Boundary conditions for the velocity. # Proper inflow and outflow conditions are a matter of voodoo. See for # example Gresho/Sani, or # # Boundary conditions for open boundaries # for the incompressible Navier-Stokes equation; # B.C.V. Johansson; # J. Comp. Phys. 105, 233-251 (1993). # # The latter in particularly suggest for the inflow: # # u = u0, # d^r v / dx^r = v_r, # div(u) = 0, # # where u and v are the velocities in normal and tangential directions, # respectively, and r\in{0,1,2}. The setting r=0 essentially means to set # (u,v) statically at the left boundary, r=1 means to set u and control # dv/dn, which is what we do here (namely implicitly by dv/dn=0). # At the outflow, # # d^j u / dx^j = 0, # d^q v / dx^q = 0, # p = p0, # # is suggested with j=q+1. Choosing q=0, j=1 means setting the tangential # component of the outflow to 0, and letting the normal component du/dn=0 # (again, this is achieved implicitly by the weak formulation). # inflow = Expression('100*x[1]*(0.4-x[1])', degree=2) u_bcs = [DirichletBC(V, (0.0, 0.0), upper_boundary), DirichletBC(V, (0.0, 0.0), lower_boundary), DirichletBC(V, (0.0, 0.0), obstacle_boundary), DirichletBC(V.sub(0), inflow, left_boundary), #DirichletBC(V.sub(1), 0.0, right_boundary), ] dudt_bcs = [DirichletBC(V, (0.0, 0.0), upper_boundary), DirichletBC(V, (0.0, 0.0), lower_boundary), DirichletBC(V, (0.0, 0.0), obstacle_boundary), DirichletBC(V.sub(0), 0.0, left_boundary), #DirichletBC(V.sub(1), 0.0, right_boundary), ] # If there is a penetration boundary (i.e., n.u!=0), then the pressure must # be set at the boundary to make sure that the Navier-Stokes problem # remains consistent. # It is not quite clear now where exactly to set the pressure to 0. Inlet, # outlet, some other place? The PPE system is consistent in all cases. # TODO find out more about it #p_bcs = [DirichletBC(Q, 0.0, right_boundary)] p_bcs = [] return mesh, V, Q, u_bcs, dudt_bcs, p_bcs
def crucible_without_coils(): base = '../meshes/2d/crucible' mesh = Mesh(base + '.xml') subdomains = MeshFunction('size_t', mesh, base+'_physical_region.xml') workpiece_index = 4 subdomain_materials = {1: 'SiC', 2: 'boron trioxide', 3: 'GaAs (solid)', 4: 'GaAs (liquid)'} submesh_workpiece = SubMesh(mesh, subdomains, workpiece_index) V = VectorFunctionSpace(submesh_workpiece, 'CG', 2) P = FunctionSpace(submesh_workpiece, 'CG', 1) Q = FunctionSpace(mesh, 'CG', 2) # Define mesh and boundaries. class LeftBoundary(SubDomain): def inside(self, x, on_boundary): # Be especially careful in the corners when defining the r=0 axis: # For the PPE to be consistent, we need to have n.u=0 *everywhere* # on the non-r=0 boundaries. return on_boundary \ and x[0] < GMSH_EPS and 0.366 + GMSH_EPS < x[1] \ and x[1] < 0.411 - GMSH_EPS left_boundary = LeftBoundary() class SurfaceBoundary(SubDomain): def inside(self, x, on_boundary): # Make sure to catch the entire surface, so don't be too # restrictive about x[0]. return on_boundary \ and x[1] > 0.38-GMSH_EPS \ and x[0] > 0.04-GMSH_EPS and x[0] < 0.07+GMSH_EPS class OtherBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary \ and not left_boundary.inside(x, on_boundary) # \ #and not surface_boundary.inside(x, on_boundary) other_boundary = OtherBoundary() # Boundary conditions for the velocity. u_bcs = [DirichletBC(V, (0.0, 0.0), other_boundary), DirichletBC(V.sub(0), 0.0, left_boundary), #DirichletBC(V.sub(1), 0.0, surface_boundary), ] #u_bcs = [DirichletBC(V, (0.0, 0.0), 'on_boundary')] p_bcs = [] class HeaterBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary \ and ((x[1] < 0.38 and GMSH_EPS < x[0] and x[0] < 0.075+GMSH_EPS) or x[0] < GMSH_EPS and x[1] < 0.365+GMSH_EPS) heater_boundary = HeaterBoundary() background_temp = 1400.0 # Heat with 1580K at r=0, 1590K at r=0.075. heater_bcs = [(heater_boundary, '1580.0 + 133.0 * x[0]')] return mesh, subdomains, subdomain_materials, workpiece_index, \ V, Q, P, u_bcs, p_bcs, background_temp, heater_bcs
def peter(): base = '../meshes/2d/peter' #base = '../meshes/2d/peter-fine' mesh = Mesh(base + '.xml') subdomains = MeshFunction('size_t', mesh, base+'_physical_region.xml') workpiece_index = 3 subdomain_materials = {1: 'SiC', 2: 'carbon steel', 3: 'GaAs (liquid)'} submesh_workpiece = SubMesh(mesh, subdomains, workpiece_index) W = VectorFunctionSpace(submesh_workpiece, 'CG', 2) Q = FunctionSpace(submesh_workpiece, 'CG', 2) # Define melt boundaries. class LeftBoundary(SubDomain): def inside(self, x, on_boundary): # Be especially careful in the corners when defining the r=0 axis: # For the PPE to be consistent, we need to have n.u=0 *everywhere* # on the non-(r=0) boundaries. return on_boundary \ and x[0] < GMSH_EPS \ and 0.005+GMSH_EPS < x[1] and x[1] < 0.050-GMSH_EPS class SurfaceBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary \ and 0.055-GMSH_EPS < x[1] \ and 0.030-GMSH_EPS < x[0] and x[0] < 0.075+GMSH_EPS class StampBoundary(SubDomain): def inside(self, x, on_boundary): # Well well. If we don't include the endpoints here, the PPE turns # out inconsistent. This is weird since the endpoints should be # picked up by RightBoundary and StampBoundary. return on_boundary \ and 0.050-GMSH_EPS < x[1] and x[1] < 0.055+GMSH_EPS \ and x[0] < 0.030+GMSH_EPS class LowerBoundary(SubDomain): def inside(self, x, on_boundary): # Danger, danger. # If the rightmost point (0.075, 0.010) is excluded, the PPE will # end up inconsistent. # This is actually weird since it should be picked up by # RightBoundary. return on_boundary \ and (x[1] < 0.005+GMSH_EPS or (x[0] > 0.070-GMSH_EPS and x[1] < 0.010+GMSH_EPS) ) class RightBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary \ and x[0] > 0.075-GMSH_EPS left_boundary = LeftBoundary() lower_boundary = LowerBoundary() right_boundary = RightBoundary() surface_boundary = SurfaceBoundary() stamp_boundary = StampBoundary() # Define workpiece boundaries. wp_boundaries = FacetFunction('size_t', submesh_workpiece) wp_boundaries.set_all(0) left_boundary.mark(wp_boundaries, 1) lower_boundary.mark(wp_boundaries, 2) right_boundary.mark(wp_boundaries, 3) surface_boundary.mark(wp_boundaries, 4) stamp_boundary.mark(wp_boundaries, 5) # For local use only: wp_boundary_indices = {'left': 1, 'lower': 2, 'right': 3, 'surface': 4, 'stamp': 5} # Boundary conditions for the velocity. u_bcs = [DirichletBC(W, (0.0, 0.0), stamp_boundary), DirichletBC(W, (0.0, 0.0), right_boundary), DirichletBC(W, (0.0, 0.0), lower_boundary), DirichletBC(W.sub(0), 0.0, left_boundary), DirichletBC(W.sub(1), 0.0, surface_boundary), ] p_bcs = [] # Boundary conditions for the heat equation. # Dirichlet theta_bcs_d = [] # Neumann theta_bcs_n = {} # Robin, i.e., # # -dtheta/dn = alpha (theta - theta0) # # (with alpha>0 to preserve coercivity of the scheme). # theta_bcs_r = { wp_boundary_indices['stamp']: (100.0, 1500.0), wp_boundary_indices['surface']: (100.0, 1550.0), wp_boundary_indices['right']: (300.0, Expression('200*x[0] + 1600', degree=1)), wp_boundary_indices['lower']: (300.0, Expression('-1200*x[1] + 1614', degree=1)), } return mesh, subdomains, subdomain_materials, workpiece_index, \ wp_boundaries, W, u_bcs, p_bcs, \ Q, theta_bcs_d, theta_bcs_n, theta_bcs_r
def karman(): # mesh = Mesh('../meshes/2d/karman.xml') mesh = Mesh("../meshes/2d/karman-coarse2.xml") V = VectorFunctionSpace(mesh, "CG", 2) Q = FunctionSpace(mesh, "CG", 1) # Define mesh and boundaries. class LeftBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] < DOLFIN_EPS left_boundary = LeftBoundary() class RightBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] > 2.5 - DOLFIN_EPS class LowerBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] < DOLFIN_EPS lower_boundary = LowerBoundary() class UpperBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] > 0.4 - DOLFIN_EPS upper_boundary = UpperBoundary() class ObstacleBoundary(SubDomain): def inside(self, x, on_boundary): return ( on_boundary and x[0] > DOLFIN_EPS and x[0] < 2.5 - DOLFIN_EPS and x[1] > DOLFIN_EPS and x[1] < 0.4 - DOLFIN_EPS ) obstacle_boundary = ObstacleBoundary() # Boundary conditions for the velocity. # Proper inflow and outflow conditions are a matter of voodoo. See for # example Gresho/Sani, or # # Boundary conditions for open boundaries # for the incompressible Navier-Stokes equation; # B.C.V. Johansson; # J. Comp. Phys. 105, 233-251 (1993). # # The latter in particularly suggest for the inflow: # # u = u0, # d^r v / dx^r = v_r, # div(u) = 0, # # where u and v are the velocities in normal and tangential directions, # respectively, and r\in{0,1,2}. The setting r=0 essentially means to set # (u,v) statically at the left boundary, r=1 means to set u and control # dv/dn, which is what we do here (namely implicitly by dv/dn=0). # At the outflow, # # d^j u / dx^j = 0, # d^q v / dx^q = 0, # p = p0, # # is suggested with j=q+1. Choosing q=0, j=1 means setting the tangential # component of the outflow to 0, and letting the normal component du/dn=0 # (again, this is achieved implicitly by the weak formulation). # inflow = Expression("100*x[1]*(0.4-x[1])", degree=2) u_bcs = [ DirichletBC(V, (0.0, 0.0), upper_boundary), DirichletBC(V, (0.0, 0.0), lower_boundary), DirichletBC(V, (0.0, 0.0), obstacle_boundary), DirichletBC(V.sub(0), inflow, left_boundary), # DirichletBC(V.sub(1), 0.0, right_boundary), ] dudt_bcs = [ DirichletBC(V, (0.0, 0.0), upper_boundary), DirichletBC(V, (0.0, 0.0), lower_boundary), DirichletBC(V, (0.0, 0.0), obstacle_boundary), DirichletBC(V.sub(0), 0.0, left_boundary), # DirichletBC(V.sub(1), 0.0, right_boundary), ] # If there is a penetration boundary (i.e., n.u!=0), then the pressure must # be set at the boundary to make sure that the Navier-Stokes problem # remains consistent. # It is not quite clear now where exactly to set the pressure to 0. Inlet, # outlet, some other place? The PPE system is consistent in all cases. # TODO find out more about it # p_bcs = [DirichletBC(Q, 0.0, right_boundary)] p_bcs = [] return mesh, V, Q, u_bcs, dudt_bcs, p_bcs
def peter(): base = "../meshes/2d/peter" # base = '../meshes/2d/peter-fine' mesh = Mesh(base + ".xml") subdomains = MeshFunction("size_t", mesh, base + "_physical_region.xml") workpiece_index = 3 subdomain_materials = {1: "SiC", 2: "carbon steel", 3: "GaAs (liquid)"} submesh_workpiece = SubMesh(mesh, subdomains, workpiece_index) W = VectorFunctionSpace(submesh_workpiece, "CG", 2) Q = FunctionSpace(submesh_workpiece, "CG", 2) # Define melt boundaries. class LeftBoundary(SubDomain): def inside(self, x, on_boundary): # Be especially careful in the corners when defining the r=0 axis: # For the PPE to be consistent, we need to have n.u=0 *everywhere* # on the non-(r=0) boundaries. return ( on_boundary and x[0] < GMSH_EPS and 0.005 + GMSH_EPS < x[1] and x[1] < 0.050 - GMSH_EPS ) class SurfaceBoundary(SubDomain): def inside(self, x, on_boundary): return ( on_boundary and 0.055 - GMSH_EPS < x[1] and 0.030 - GMSH_EPS < x[0] and x[0] < 0.075 + GMSH_EPS ) class StampBoundary(SubDomain): def inside(self, x, on_boundary): # Well well. If we don't include the endpoints here, the PPE turns # out inconsistent. This is weird since the endpoints should be # picked up by RightBoundary and StampBoundary. return ( on_boundary and 0.050 - GMSH_EPS < x[1] and x[1] < 0.055 + GMSH_EPS and x[0] < 0.030 + GMSH_EPS ) class LowerBoundary(SubDomain): def inside(self, x, on_boundary): # Danger, danger. # If the rightmost point (0.075, 0.010) is excluded, the PPE will # end up inconsistent. # This is actually weird since it should be picked up by # RightBoundary. return on_boundary and ( x[1] < 0.005 + GMSH_EPS or (x[0] > 0.070 - GMSH_EPS and x[1] < 0.010 + GMSH_EPS) ) class RightBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] > 0.075 - GMSH_EPS left_boundary = LeftBoundary() lower_boundary = LowerBoundary() right_boundary = RightBoundary() surface_boundary = SurfaceBoundary() stamp_boundary = StampBoundary() # Define workpiece boundaries. wp_boundaries = MeshFunction( "size_t", submesh_workpiece, self.submesh_workpiece.topology().dim() - 1 ) wp_boundaries.set_all(0) left_boundary.mark(wp_boundaries, 1) lower_boundary.mark(wp_boundaries, 2) right_boundary.mark(wp_boundaries, 3) surface_boundary.mark(wp_boundaries, 4) stamp_boundary.mark(wp_boundaries, 5) # For local use only: wp_boundary_indices = {"left": 1, "lower": 2, "right": 3, "surface": 4, "stamp": 5} # Boundary conditions for the velocity. u_bcs = [ DirichletBC(W, (0.0, 0.0), stamp_boundary), DirichletBC(W, (0.0, 0.0), right_boundary), DirichletBC(W, (0.0, 0.0), lower_boundary), DirichletBC(W.sub(0), 0.0, left_boundary), DirichletBC(W.sub(1), 0.0, surface_boundary), ] p_bcs = [] # Boundary conditions for the heat equation. # Dirichlet theta_bcs_d = [] # Neumann theta_bcs_n = {} # Robin, i.e., # # -dtheta/dn = alpha (theta - theta0) # # (with alpha>0 to preserve coercivity of the scheme). # theta_bcs_r = { wp_boundary_indices["stamp"]: (100.0, 1500.0), wp_boundary_indices["surface"]: (100.0, 1550.0), wp_boundary_indices["right"]: (300.0, Expression("200*x[0] + 1600", degree=1)), wp_boundary_indices["lower"]: ( 300.0, Expression("-1200*x[1] + 1614", degree=1), ), } return ( mesh, subdomains, subdomain_materials, workpiece_index, wp_boundaries, W, u_bcs, p_bcs, Q, theta_bcs_d, theta_bcs_n, theta_bcs_r, )
def crucible_without_coils(): base = "../meshes/2d/crucible" mesh = Mesh(base + ".xml") subdomains = MeshFunction("size_t", mesh, base + "_physical_region.xml") workpiece_index = 4 subdomain_materials = { 1: "SiC", 2: "boron trioxide", 3: "GaAs (solid)", 4: "GaAs (liquid)", } submesh_workpiece = SubMesh(mesh, subdomains, workpiece_index) V = VectorFunctionSpace(submesh_workpiece, "CG", 2) P = FunctionSpace(submesh_workpiece, "CG", 1) Q = FunctionSpace(mesh, "CG", 2) # Define mesh and boundaries. class LeftBoundary(SubDomain): def inside(self, x, on_boundary): # Be especially careful in the corners when defining the r=0 axis: # For the PPE to be consistent, we need to have n.u=0 *everywhere* # on the non-r=0 boundaries. return ( on_boundary and x[0] < GMSH_EPS and 0.366 + GMSH_EPS < x[1] and x[1] < 0.411 - GMSH_EPS ) left_boundary = LeftBoundary() class SurfaceBoundary(SubDomain): def inside(self, x, on_boundary): # Make sure to catch the entire surface, so don't be too # restrictive about x[0]. return ( on_boundary and x[1] > 0.38 - GMSH_EPS and x[0] > 0.04 - GMSH_EPS and x[0] < 0.07 + GMSH_EPS ) class OtherBoundary(SubDomain): def inside(self, x, on_boundary): return ( on_boundary and not left_boundary.inside(x, on_boundary) # and not surface_boundary.inside(x, on_boundary) ) other_boundary = OtherBoundary() # Boundary conditions for the velocity. u_bcs = [ DirichletBC(V, (0.0, 0.0), other_boundary), DirichletBC(V.sub(0), 0.0, left_boundary), # DirichletBC(V.sub(1), 0.0, surface_boundary), ] # u_bcs = [DirichletBC(V, (0.0, 0.0), 'on_boundary')] p_bcs = [] class HeaterBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and ( (x[1] < 0.38 and GMSH_EPS < x[0] and x[0] < 0.075 + GMSH_EPS) or x[0] < GMSH_EPS and x[1] < 0.365 + GMSH_EPS ) heater_boundary = HeaterBoundary() background_temp = 1400.0 # Heat with 1580K at r=0, 1590K at r=0.075. heater_bcs = [(heater_boundary, "1580.0 + 133.0 * x[0]")] return ( mesh, subdomains, subdomain_materials, workpiece_index, V, Q, P, u_bcs, p_bcs, background_temp, heater_bcs, )