def create(self, pc): self.diag = None kspNS = PETSc.KSP() kspNS.create(comm=PETSc.COMM_WORLD) pcNS = kspNS.getPC() kspNS.setType('gmres') pcNS.setType('python') pcNS.setPythonContext( NSprecond.PCDdirect( MixedFunctionSpace([self.Fspace[0], self.Fspace[1]]), self.Q, self.F, self.L)) kspNS.setTolerances(1e-3) kspNS.setFromOptions() self.kspNS = kspNS kspM = PETSc.KSP() kspM.create(comm=PETSc.COMM_WORLD) pcM = kspM.getPC() kspM.setType('gmres') pcM.setType('python') kspM.setTolerances(1e-3) pcM.setPythonContext( MP.Direct(MixedFunctionSpace([self.Fspace[2], self.Fspace[3]]))) kspM.setFromOptions() self.kspM = kspM
def ball_in_tube(): mesh = Mesh("../meshes/2d/ball-in-tube-cylindrical-coarse4.xml") V0 = FunctionSpace(mesh, "CG", 2) V1 = FunctionSpace(mesh, "B", 3) V = V0 + V1 W = MixedFunctionSpace([V, V]) P = FunctionSpace(mesh, "CG", 1) # Define mesh and boundaries. 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] > 1.0 - 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] > 5.0 - GMSH_EPS class CoilBoundary(SubDomain): def inside(self, x, on_boundary): # One has to pay a little bit of attention when defining the # coil boundary; it's easy to miss the edges closest to x[0]=0. return ( on_boundary and x[1] > 1.0 - GMSH_EPS and x[1] < 2.0 + GMSH_EPS and x[0] < 1.0 - GMSH_EPS ) coil_boundary = CoilBoundary() u_bcs = [ DirichletBC(W, (0.0, 0.0), right_boundary), DirichletBC(W.sub(0), 0.0, left_boundary), DirichletBC(W, (0.0, 0.0), lower_boundary), DirichletBC(W, (0.0, 0.0), coil_boundary), ] p_bcs = [] # p_bcs = [DirichletBC(Q, 0.0, upper_boundary)] return mesh, W, P, u_bcs, p_bcs
def rotating_lid(): mesh = UnitSquareMesh(20, 20, "left/right") # Define mesh and boundaries. class LeftBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] < GMSH_EPS class RightBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] > 1.0 - GMSH_EPS class LowerBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] < GMSH_EPS class UpperBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] > 1.0 - DOLFIN_EPS class RestrictedUpperBoundary(SubDomain): def inside(self, x, on_boundary): return ( on_boundary and x[1] > 1.0 - DOLFIN_EPS and DOLFIN_EPS < x[0] and x[0] < 0.5 - DOLFIN_EPS ) left = LeftBoundary() right = RightBoundary() lower = LowerBoundary() upper = UpperBoundary() restricted_upper = RestrictedUpperBoundary() V = FunctionSpace(mesh, "CG", 2) W = MixedFunctionSpace([V, V, V]) u_bcs = [ DirichletBC(W.sub(0), 0.0, left), DirichletBC(W.sub(2), 0.0, left), DirichletBC(W, Constant((0.0, 0.0, 0.0)), right), DirichletBC(W.sub(0), 0.0, upper), DirichletBC(W.sub(1), 0.0, upper), DirichletBC(W.sub(2), Expression("x[0]", degree=1), restricted_upper), DirichletBC(W, Constant((0.0, 0.0, 0.0)), lower), ] P = FunctionSpace(mesh, "CG", 1) p_bcs = [] return mesh, W, P, u_bcs, p_bcs
def increase_order(V): """ For a given function space, return the same space, but with a higher polynomial degree """ n = V.num_sub_spaces() if n > 0: spaces = [] for i in range(n): V_i = V.sub(i) element = V_i.ufl_element() # Handle VectorFunctionSpaces specially if isinstance(element, ufl.VectorElement): spaces += [ VectorFunctionSpace(V_i.mesh(), element.family(), element.degree() + 1, dim=element.num_sub_elements()) ] # Handle all else as MixedFunctionSpaces else: spaces += [increase_order(V_i)] return MixedFunctionSpace(spaces) if V.ufl_element().family() == "Real": return FunctionSpace(V.mesh(), "Real", 0) return FunctionSpace(V.mesh(), V.ufl_element().family(), V.ufl_element().degree() + 1)
def derivative(form, u, du=None, coefficient_derivatives=None): if du is None: # Get existing arguments from form and position the new one with the next argument number from ufl.algorithms import extract_arguments form_arguments = extract_arguments(form) number = max([-1] + [arg.number() for arg in form_arguments]) + 1 if any(arg.part() is not None for arg in form_arguments): cpp.dolfin_error( "formmanipulation.py", "compute derivative of form", "Cannot automatically create third argument using parts, please supply one" ) part = None if isinstance(u, Function): V = u.function_space() du = Argument(V, number, part) elif isinstance(u, (list, tuple)) and all( isinstance(w, Function) for w in u): V = MixedFunctionSpace([w.function_space() for w in u]) du = ufl.split(Argument(V, number, part)) else: cpp.dolfin_error( "formmanipulation.py", "compute derivative of form", "Cannot automatically create third argument, please supply one" ) return ufl.derivative(form, u, du, coefficient_derivatives)
def change_regularity(V, family): """ For a given function space, return the corresponding space with the finite elements specified by 'family'. Possible families are the families supported by the form compiler """ n = V.num_sub_spaces() if n > 0: return MixedFunctionSpace([change_regularity(V.sub(i), family) for i in range(n)]) element = V.ufl_element() shape = element.value_shape() if not shape: return FunctionSpace(V.mesh(), family, element.degree()) return MixedFunctionSpace([FunctionSpace(V.mesh(), family, element.degree()) for i in range(shape[0])])
def derivative(form, u, du=None): if du is None: if isinstance(u, Function): V = u.function_space() du = Argument(V) elif isinstance(u, (list, tuple)) and all( isinstance(w, Function) for w in u): V = MixedFunctionSpace([w.function_space() for w in u]) du = ufl.split(Argument(V)) else: cpp.dolfin_error( "formmanipulation.py", "compute derivative of form", "Cannot automatically create third argument, please supply one" ) return ufl.derivative(form, u, du)
def make_function_spaces(mesh, element): 'Create mixed function space on the mesh.' assert hasattr(element, 'V') and hasattr(element, 'Q') # Create velocity space n = len(element.V) assert n > 0 V = VectorFunctionSpace(mesh, *element.V[0]) for i in range(1, n): V += VectorFunctionSpace(mesh, *element.V[i]) # Create pressure space assert len(element.Q) == 1 Q = FunctionSpace(mesh, *element.Q[0]) M = MixedFunctionSpace([V, Q]) return V, Q, M
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 createMixedFSi(Vs): """ Create MixedFunctionSpace from V1 and V2 """ Vdim = Vs[0].dim() Vms = Vs[0].mesh().size(0) for V in Vs: assert Vdim == V.dim() assert Vms == V.mesh().size(0) try: V1V2 = MixedFunctionSpace(Vs) except: Vsfem = [] for V in Vs: Vsfem.append(V.ufl_element()) V1V2 = FunctionSpace(Vs[0].mesh(), MixedElement(Vsfem)) return V1V2
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 solve(A, b, u, P, IS, Fspace, IterType, OuterTol, InnerTol, Mass=0, L=0, F=0): # u = b.duplicate() if IterType == "Full": kspOuter = PETSc.KSP().create() kspOuter.setTolerances(OuterTol) kspOuter.setType('fgmres') reshist = {} def monitor(ksp, its, fgnorm): reshist[its] = fgnorm print "OUTER:", fgnorm kspOuter.setMonitor(monitor) pcOutter = kspOuter.getPC() pcOutter.setType(PETSc.PC.Type.KSP) kspOuter.setOperators(A) kspOuter.max_it = 500 kspInner = pcOutter.getKSP() kspInner.max_it = 100 reshist1 = {} def monitor(ksp, its, fgnorm): reshist1[its] = fgnorm print "INNER:", fgnorm # kspInner.setMonitor(monitor) kspInner.setType('gmres') kspInner.setTolerances(InnerTol) pcInner = kspInner.getPC() pcInner.setType(PETSc.PC.Type.PYTHON) pcInner.setPythonContext(MHDprecond.D(Fspace, P, Mass, F, L)) PP = PETSc.Mat().createPython([A.size[0], A.size[0]]) PP.setType('python') p = PrecondMulti.P(Fspace, P, Mass, L, F) PP.setPythonContext(p) kspInner.setOperators(PP) tic() scale = b.norm() b = b / scale print b.norm() kspOuter.solve(b, u) u = u * scale print toc() # print s.getvalue() NSits = kspOuter.its del kspOuter Mits = kspInner.its del kspInner # print u.array return u, NSits, Mits NS_is = IS[0] M_is = IS[1] kspNS = PETSc.KSP().create() kspM = PETSc.KSP().create() kspNS.setTolerances(OuterTol) kspNS.setOperators(A.getSubMatrix(NS_is, NS_is), P.getSubMatrix(NS_is, NS_is)) kspM.setOperators(A.getSubMatrix(M_is, M_is), P.getSubMatrix(M_is, M_is)) # print P.symmetric A.destroy() P.destroy() if IterType == "MD": kspNS.setType('gmres') kspNS.max_it = 500 pcNS = kspNS.getPC() pcNS.setType(PETSc.PC.Type.PYTHON) pcNS.setPythonContext( NSprecond.PCDdirect(MixedFunctionSpace([Fspace[0], Fspace[1]]), Mass, F, L)) elif IterType == "CD": kspNS.setType('minres') pcNS = kspNS.getPC() pcNS.setType(PETSc.PC.Type.PYTHON) pcNS.setPythonContext( StokesPrecond.Approx(MixedFunctionSpace([Fspace[0], Fspace[1]]))) reshist = {} def monitor(ksp, its, fgnorm): reshist[its] = fgnorm print fgnorm # kspNS.setMonitor(monitor) uNS = u.getSubVector(NS_is) bNS = b.getSubVector(NS_is) # print kspNS.view() scale = bNS.norm() bNS = bNS / scale print bNS.norm() kspNS.solve(bNS, uNS) uNS = uNS * scale NSits = kspNS.its kspNS.destroy() # for line in reshist.values(): # print line kspM.setFromOptions() kspM.setType(kspM.Type.MINRES) kspM.setTolerances(InnerTol) pcM = kspM.getPC() pcM.setType(PETSc.PC.Type.PYTHON) pcM.setPythonContext(MP.Direct(MixedFunctionSpace([Fspace[2], Fspace[3]]))) uM = u.getSubVector(M_is) bM = b.getSubVector(M_is) scale = bM.norm() bM = bM / scale print bM.norm() kspM.solve(bM, uM) uM = uM * scale Mits = kspM.its kspM.destroy() u = IO.arrayToVec(np.concatenate([uNS.array, uM.array])) return u, NSits, Mits
def __init__(self): import os from dolfin import Mesh, MeshFunction, SubMesh, SubDomain, \ FacetFunction, DirichletBC, dot, grad, FunctionSpace, \ MixedFunctionSpace, Expression, FacetNormal, pi, Function, \ Constant, TestFunction, MPI, mpi_comm_world, File import numpy import warnings from maelstrom import heat_cylindrical as cyl_heat from maelstrom import materials_database as md GMSH_EPS = 1.0e-15 current_path = os.path.dirname(os.path.realpath(__file__)) base = os.path.join( current_path, '../../meshes/2d/crucible-with-coils' ) self.mesh = Mesh(base + '.xml') self.subdomains = MeshFunction('size_t', self.mesh, base + '_physical_region.xml' ) self.subdomain_materials = { 1: md.get_material('porcelain'), 2: md.get_material('argon'), 3: md.get_material('GaAs (solid)'), 4: md.get_material('GaAs (liquid)'), 27: md.get_material('air') } # coils for k in range(5, 27): self.subdomain_materials[k] = md.get_material('graphite EK90') # Define the subdomains which together form a single coil. self.coil_domains = [ [5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19], [20, 21, 22, 23], [24, 25, 26] ] self.wpi = 4 # http://fenicsproject.org/qa/2026/submesh-workaround-for-parallel-computation submesh_parallel_bug_fixed = False if submesh_parallel_bug_fixed: submesh_workpiece = SubMesh(self.mesh, self.subdomains, self.wpi) else: # To get the mesh in parallel, we need to read it in from a file. # Writing out can only happen in serial mode, though. :/ base = os.path.join(current_path, '../../meshes/2d/crucible-with-coils-submesh' ) filename = base + '.xml' if not os.path.isfile(filename): warnings.warn( 'Submesh file \'%s\' does not exist. Creating... ' % filename ) if MPI.size(mpi_comm_world()) > 1: raise RuntimeError( 'Can only write submesh in serial mode.' ) submesh_workpiece = \ SubMesh(self.mesh, self.subdomains, self.wpi) output_stream = File(filename) output_stream << submesh_workpiece # Read the mesh submesh_workpiece = Mesh(base + '.xml') coords = submesh_workpiece.coordinates() ymin = min(coords[:, 1]) ymax = max(coords[:, 1]) # Find the top right point. k = numpy.argmax(numpy.sum(coords, 1)) topright = coords[k, :] # Initialize mesh function for boundary domains class Left(SubDomain): def inside(self, x, on_boundary): # Explicitly exclude the lowest and the highest point of the # symmetry axis. # It is necessary for the consistency of the pressure-Poisson # system in the Navier-Stokes solver that the velocity is # exactly 0 at the boundary r>0. Hence, at the corner points # (r=0, melt-crucible, melt-crystal) we must enforce u=0 # already and cannot have a component in z-direction. return on_boundary \ and x[0] < GMSH_EPS \ and x[1] < ymax - GMSH_EPS \ and x[1] > ymin + GMSH_EPS class Crucible(SubDomain): def inside(self, x, on_boundary): return on_boundary \ and ((x[0] > GMSH_EPS and x[1] < ymax - GMSH_EPS) or (x[0] > topright[0] - GMSH_EPS and x[1] > topright[1] - GMSH_EPS) or (x[0] < GMSH_EPS and x[1] < ymin + GMSH_EPS) ) # At the top right part (boundary melt--gas), slip is allowed, so only # n.u=0 is enforced. Very weirdly, the PPE is consistent if and only if # the end points of UpperRight are in UpperRight. This contrasts # Left(), where the end points must NOT belong to Left(). Judging from # the experiments, these settings do the right thing. # TODO try to better understand the PPE system/dolfin's boundary # settings class Upper(SubDomain): def inside(self, x, on_boundary): return on_boundary \ and x[1] > ymax - GMSH_EPS class UpperRight(SubDomain): def inside(self, x, on_boundary): return on_boundary \ and x[1] > ymax - GMSH_EPS \ and x[0] > 0.038 - GMSH_EPS # The crystal boundary is taken to reach up to 0.038 where the # Dirichlet boundary data is about the melting point of the crystal, # 1511K. This setting gives pretty acceptable results when there is no # convection except the one induced by buoyancy. Is there is any more # stirring going on, though, the end point of the crystal with its # fixed temperature of 1511K might be the hottest point globally. This # looks rather unphysical. # TODO check out alternatives class UpperLeft(SubDomain): def inside(self, x, on_boundary): return on_boundary \ and x[1] > ymax - GMSH_EPS \ and x[0] < 0.038 + GMSH_EPS left = Left() crucible = Crucible() upper_left = UpperLeft() upper_right = UpperRight() self.wp_boundaries = FacetFunction('size_t', submesh_workpiece) self.wp_boundaries.set_all(0) left.mark(self.wp_boundaries, 1) crucible.mark(self.wp_boundaries, 2) upper_right.mark(self.wp_boundaries, 3) upper_left.mark(self.wp_boundaries, 4) if DEBUG: from dolfin import plot, interactive plot(self.wp_boundaries, title='Boundaries') interactive() submesh_boundary_indices = { 'left': 1, 'crucible': 2, 'upper right': 3, 'upper left': 4 } # Boundary conditions for the velocity. # # [1] Incompressible flow and the finite element method; volume two; # Isothermal Laminar Flow; # P.M. Gresho, R.L. Sani; # # For the choice of function space, [1] says: # "In 2D, the triangular elements P_2^+P_1 and P_2^+P_{-1} are very # good [...]. [...] If you wish to avoid bubble functions on # triangular elements, P_2P_1 is not bad, and P_2(P_1+P_0) is even # better [...]." # # It turns out that adding the bubble space significantly hampers the # convergence of the Stokes solver and also considerably increases the # time it takes to construct the Jacobian matrix of the Navier--Stokes # problem if no optimization is applied. V = FunctionSpace(submesh_workpiece, 'CG', 2) with_bubbles = False if with_bubbles: V += FunctionSpace(submesh_workpiece, 'B', 3) self.W = MixedFunctionSpace([V, V, V]) self.u_bcs = [ DirichletBC(self.W, Expression( ('0.0', '0.0', '-2*pi*x[0] * 5.0/60.0'), degree=1 ), #(0.0, 0.0, 0.0), crucible), DirichletBC(self.W.sub(0), 0.0, left), DirichletBC(self.W.sub(2), 0.0, left), # Make sure that u[2] is 0 at r=0. DirichletBC(self.W, Expression( ('0.0', '0.0', '2*pi*x[0] * 5.0/60.0'), degree=1 ), upper_left), DirichletBC(self.W.sub(1), 0.0, upper_right), ] self.p_bcs = [] self.P = FunctionSpace(submesh_workpiece, 'CG', 1) # Boundary conditions for heat equation. self.Q = FunctionSpace(submesh_workpiece, 'CG', 2) # Dirichlet. # This is a bit of a tough call since the boundary conditions need to # be read from a Tecplot file here. import tecplot_reader filename = os.path.join( os.path.dirname(os.path.realpath(__file__)), 'data/crucible-boundary.dat' ) data = tecplot_reader.read(filename) RZ = numpy.c_[data['ZONE T']['node data']['r'], data['ZONE T']['node data']['z'] ] T_vals = data['ZONE T']['node data']['temp. [K]'] class TecplotDirichletBC(Expression): # TODO specify degree def eval(self, value, x): # Find on which edge x sits, and raise exception if it doesn't. edge_found = False for edge in data['ZONE T']['element data']: # Given a point X and an edge X0--X1, # # (1 - theta) X0 + theta X1, # # the minimum distance is assumed for # # argmin_theta ||(1-theta) X0 + theta X1 - X||^2 # = <X1 - X0, X - X0> / ||X1 - X0||^2. # # If the distance is 0 and 0<=theta<=1, we found the edge. # # Note that edges are 1-based in Tecplot. X0 = RZ[edge[0] - 1] X1 = RZ[edge[1] - 1] theta = numpy.dot(X1-X0, x-X0) / numpy.dot(X1-X0, X1-X0) diff = (1.0-theta)*X0 + theta*X1 - x if numpy.dot(diff, diff) < 1.0e-10 and \ 0.0 <= theta and theta <= 1.0: # Linear interpolation of the temperature value. value[0] = (1.0-theta) * T_vals[edge[0]-1] \ + theta * T_vals[edge[1]-1] edge_found = True break # This class is supposed to be used for Dirichlet boundary # conditions. For some reason, FEniCS also evaluates # DirichletBC objects at coordinates which do not sit on the # boundary, see # <http://fenicsproject.org/qa/1033/dirichletbc-expressions-evaluated-away-from-the-boundary>. # The assigned values have no meaning though, so not assigning # values[0] here is okay. # #from matplotlib import pyplot as pp #pp.plot(x[0], x[1], 'xg') if not edge_found: value[0] = 0.0 warnings.warn('Coordinate (%e, %e) doesn\'t sit on edge.' % (x[0], x[1])) #pp.plot(RZ[:, 0], RZ[:, 1], '.k') #pp.plot(x[0], x[1], 'xr') #pp.show() #raise RuntimeError('Input coordinate ' # '%r is not on boundary.' % x) return tecplot_dbc = TecplotDirichletBC() self.theta_bcs_d = [ DirichletBC(self.Q, tecplot_dbc, upper_left) ] theta_bcs_d_strict = [ DirichletBC(self.Q, tecplot_dbc, upper_right), DirichletBC(self.Q, tecplot_dbc, crucible), DirichletBC(self.Q, tecplot_dbc, upper_left) ] # Neumann dTdr_vals = data['ZONE T']['node data']['dTempdx [K/m]'] dTdz_vals = data['ZONE T']['node data']['dTempdz [K/m]'] class TecplotNeumannBC(Expression): # TODO specify degree def eval(self, value, x): # Same problem as above: This expression is not only evaluated # at boundaries. for edge in data['ZONE T']['element data']: X0 = RZ[edge[0] - 1] X1 = RZ[edge[1] - 1] theta = numpy.dot(X1-X0, x-X0) / numpy.dot(X1-X0, X1-X0) dist = numpy.linalg.norm((1-theta)*X0 + theta*X1 - x) if dist < 1.0e-5 and 0.0 <= theta and theta <= 1.0: value[0] = (1-theta) * dTdr_vals[edge[0]-1] \ + theta * dTdr_vals[edge[1]-1] value[1] = (1-theta) * dTdz_vals[edge[0]-1] \ + theta * dTdz_vals[edge[1]-1] break return def value_shape(self): return (2,) tecplot_nbc = TecplotNeumannBC() n = FacetNormal(self.Q.mesh()) self.theta_bcs_n = { submesh_boundary_indices['upper right']: dot(n, tecplot_nbc), submesh_boundary_indices['crucible']: dot(n, tecplot_nbc) } self.theta_bcs_r = {} # It seems that the boundary conditions from above are inconsistent in # that solving with Dirichlet overall and mixed Dirichlet-Neumann give # different results; the value *cannot* correspond to one solution. # From looking at the solutions, the pure Dirichlet setting appears # correct, so extract the Neumann values directly from that solution. zeta = TestFunction(self.Q) theta_reference = Function(self.Q, name='temperature (Dirichlet)') theta_reference.vector()[:] = 0.0 # Solve the *quasilinear* PDE (coefficients may depend on theta). # This is to avoid setting a fixed temperature for the coefficients. # Get material parameters wp_material = self.subdomain_materials[self.wpi] if isinstance(wp_material.specific_heat_capacity, float): cp = wp_material.specific_heat_capacity else: cp = wp_material.specific_heat_capacity(theta_reference) if isinstance(wp_material.density, float): rho = wp_material.density else: rho = wp_material.density(theta_reference) if isinstance(wp_material.thermal_conductivity, float): k = wp_material.thermal_conductivity else: k = wp_material.thermal_conductivity(theta_reference) reference_problem = cyl_heat.HeatCylindrical( self.Q, theta_reference, zeta, b=Constant((0.0, 0.0, 0.0)), kappa=k, rho=rho, cp=cp, source=Constant(0.0), dirichlet_bcs=theta_bcs_d_strict ) from dolfin import solve solve(reference_problem.F0 == 0, theta_reference, bcs=theta_bcs_d_strict ) # Create equivalent boundary conditions from theta_reference. This # makes sure that the potentially expensive Expression evaluation in # theta_bcs_* is replaced by something reasonably cheap. for k, bc in enumerate(self.theta_bcs_d): self.theta_bcs_d[k] = DirichletBC(bc.function_space(), theta_reference, bc.domain_args[0] ) # Adapt Neumann conditions. n = FacetNormal(self.Q.mesh()) for k in self.theta_bcs_n: self.theta_bcs_n[k] = dot(n, grad(theta_reference)) if DEBUG: # Solve the heat equation with the mixed Dirichlet-Neumann # boundary conditions and compare it to the Dirichlet-only # solution. theta_new = Function( self.Q, name='temperature (Neumann + Dirichlet)' ) from dolfin import Measure ds_workpiece = Measure('ds')[self.wp_boundaries] problem_new = cyl_heat.HeatCylindrical( self.Q, theta_new, zeta, b=Constant((0.0, 0.0, 0.0)), kappa=k, rho=rho, cp=cp, source=Constant(0.0), dirichlet_bcs=self.theta_bcs_d, neumann_bcs=self.theta_bcs_n, ds=ds_workpiece ) from dolfin import solve solve(problem_new.F0 == 0, theta_new, bcs=problem_new.dirichlet_bcs ) from dolfin import plot, interactive, errornorm print('||theta_new - theta_ref|| = %e' % errornorm(theta_new, theta_reference) ) plot(theta_reference) plot(theta_new) plot( theta_reference - theta_new, title='theta_ref - theta_new' ) interactive() #omega = 2 * pi * 10.0e3 self.omega = 2 * pi * 300.0 return
def solve(self, problem): self.problem = problem doSave = problem.doSave save_this_step = False onlyVel = problem.saveOnlyVel dt = self.metadata['dt'] nu = Constant(self.problem.nu) self.tc.init_watch('init', 'Initialization', True, count_to_percent=False) self.tc.init_watch('solve', 'Running nonlinear solver', True, count_to_percent=True) self.tc.init_watch('next', 'Next step assignments', True, count_to_percent=True) self.tc.init_watch('saveVel', 'Saved velocity', True) self.tc.start('init') mesh = self.problem.mesh # Define function spaces (P2-P1) self.V = VectorFunctionSpace(mesh, "Lagrange", 2) # velocity self.Q = FunctionSpace(mesh, "Lagrange", 1) # pressure self.W = MixedFunctionSpace([self.V, self.Q]) self.PS = FunctionSpace(mesh, "Lagrange", 2) # partial solution (must be same order as V) self.D = FunctionSpace(mesh, "Lagrange", 1) # velocity divergence space # to assign solution in space W.sub(0) to Function(V) we need FunctionAssigner (cannot be assigned directly) fa = FunctionAssigner(self.V, self.W.sub(0)) velSp = Function(self.V) problem.initialize(self.V, self.Q, self.PS, self.D) # Define unknown and test function(s) NS v, q = TestFunctions(self.W) w = Function(self.W) dw = TrialFunction(self.W) u, p = split(w) # Define fields n = FacetNormal(mesh) I = Identity(u.geometric_dimension()) theta = 0.5 # Crank-Nicholson k = Constant(self.metadata['dt']) # Initial conditions: u0 velocity at previous time step u1 velocity two time steps back p0 previous pressure [u0, p0] = self.problem.get_initial_conditions([{'type': 'v', 'time': 0.0}, {'type': 'p', 'time': 0.0}]) if doSave: problem.save_vel(False, u0, 0.0) # boundary conditions bcu, bcp = problem.get_boundary_conditions(self.bc == 'outflow', self.W.sub(0), self.W.sub(1)) # NT bcp is not used # Define steady part of the equation def T(u): return -p * I + 2.0 * nu * sym(grad(u)) def F(u, v, q): return (inner(T(u), grad(v)) - q * div(u)) * dx + inner(grad(u) * u, v) * dx # Define variational forms F_ns = (inner((u - u0), v) / k) * dx + (1.0 - theta) * F(u0, v, q) + theta * F(u, v, q) J_ns = derivative(F_ns, w, dw) # J_ns = derivative(F_ns, w) # did not work # NS_problem = NonlinearVariationalProblem(F_ns, w, bcu, J_ns, form_compiler_parameters=ffc_options) NS_problem = NonlinearVariationalProblem(F_ns, w, bcu, J_ns) # (var. formulation, unknown, Dir. BC, jacobian, optional) NS_solver = NonlinearVariationalSolver(NS_problem) prm = NS_solver.parameters prm['newton_solver']['absolute_tolerance'] = 1E-08 prm['newton_solver']['relative_tolerance'] = 1E-08 # prm['newton_solver']['maximum_iterations'] = 45 # prm['newton_solver']['relaxation_parameter'] = 1.0 prm['newton_solver']['linear_solver'] = 'mumps' info(NS_solver.parameters, True) self.tc.end('init') # Time-stepping info("Running of direct method") ttime = self.metadata['time'] t = dt step = 1 while t < (ttime + dt/2.0): info("t = %f" % t) self.problem.update_time(t, step) if self.MPI_rank == 0: problem.write_status_file(t) if doSave: save_this_step = problem.save_this_step # Compute begin("Solving NS ....") try: self.tc.start('solve') NS_solver.solve() self.tc.end('solve') except RuntimeError as inst: problem.report_fail(t) return 1 end() # Extract solutions: (u, p) = w.split() fa.assign(velSp, u) # we are assigning twice (now and inside save_vel), but it works with one method save_vel for direct and # projection (we could split save_vel to save one assign) if save_this_step: self.tc.start('saveVel') problem.save_vel(False, velSp, t) self.tc.end('saveVel') if save_this_step and not onlyVel: problem.save_div(False, u) problem.compute_err(False, u, t) problem.compute_div(False, u) # foo = Function(self.Q) # foo.assign(p) # problem.averaging_pressure(foo) # if save_this_step and not onlyVel: # problem.save_pressure(False, foo) if save_this_step and not onlyVel: problem.save_pressure(False, p) # compute functionals (e. g. forces) problem.compute_functionals(u, p, t) # Move to next time step self.tc.start('next') u0.assign(velSp) t = round(t + dt, 6) # round time step to 0.000001 step += 1 self.tc.end('next') info("Finished: direct method") problem.report() return 0
class Solver(gs.GeneralSolver): def __init__(self, args, tc, metadata): gs.GeneralSolver.__init__(self, args, tc, metadata) self.metadata['hasTentativeV'] = False self.solver_vel_tent = None self.solver_vel_cor = None self.solver_p = None self.solver_rot = None self.null_space = None # input parameters self.bc = args.bc self.forceOutflow = args.fo self.useLaplace = args.laplace self.use_full_SUPG = args.cs self.bcv = 'NOT' if self.useLaplace else args.bcv if self.bcv == 'CDN': info('Using classical do nothing condition (Tn=0).') if self.bcv == 'DDN': info('Using directional do nothing condition (Tn=0.5*negative(u.n)u).') if self.bcv == 'LAP': info('Using laplace neutral condition (grad(u)n=0).') self.stabCoef = args.stab self.stabilize = (args.stab > DOLFIN_EPS) if self.stabilize: if self.use_full_SUPG: info('Used consistent streamline-diffusion stabilization with coef.: %f' % args.stab) else: info('Used non-consistent streamline-diffusion stabilization with coef.: %f' % args.stab) else: info('No stabilization used.') self.solvers = args.solvers self.useRotationScheme = args.r self.metadata['hasTentativeP'] = self.useRotationScheme self.B = args.B self.use_ema = args.ema self.cbcDelta = args.cbcDelta self.prec_v = args.precV self.prec_p = args.precP self.precision_rel_v_tent = args.prv1 self.precision_abs_v_tent = args.pav1 self.precision_p = args.pp def __str__(self): return 'ipcs1 - incremental pressure correction scheme with nonlinearity treated by Adam-Bashword + ' \ 'Crank-Nicolson and viscosity term treated semi-explicitly (Crank-Nicholson)' @staticmethod def setup_parser_options(parser): gs.GeneralSolver.setup_parser_options(parser) parser.add_argument('-s', '--solvers', help='Solvers', choices=['direct', 'krylov'], default='krylov') parser.add_argument('--prv1', help='relative tentative velocity Krylov solver precision', type=int, default=6) parser.add_argument('--pav1', help='absolute tentative velocity Krylov solver precision', type=int, default=10) parser.add_argument('--pp', help='pressure Krylov solver precision', type=int, default=10) parser.add_argument('-b', '--bc', help='Pressure boundary condition mode', choices=['outflow', 'nullspace', 'nullspace_s', 'lagrange'], default='outflow') parser.add_argument('--precV', help='Preconditioner for tentative velocity solver', type=str, default='ilu') parser.add_argument('--precP', help='Preconditioner for pressure solver', choices=['hypre_amg', 'ilu'], default='hypre_amg') parser.add_argument('-r', help='Use rotation scheme', action='store_true') parser.add_argument('-B', help='Use no BC in correction step', action='store_true') parser.add_argument('--fo', help='Force Neumann outflow boundary for pressure', action='store_true') parser.add_argument('--laplace', help='Use laplace(u) instead of div(symgrad(u))', action='store_true') parser.add_argument('--stab', help='Use stabilization (positive constant)', type=float, default=0.) parser.add_argument('--bcv', help='Oufflow BC for velocity (with stress formulation)', choices=['CDN', 'DDN', 'LAP'], default='CDN') parser.add_argument('--ema', help='Use EMA conserving scheme for convection term', action='store_true') # described in Charnyi, Heister, Olshanskii, Rebholz: # "On conservation laws of Navier-Stokes Galerkin discretizations" (2016) parser.add_argument('--cs', help='Use consistent SUPG stabilisation.', action='store_true') parser.add_argument('--cbcDelta', help='Use simpler cbcflow parameter for SUPG', action='store_true') def solve(self, problem): self.problem = problem doSave = problem.doSave save_this_step = False onlyVel = problem.saveOnlyVel dt = self.metadata['dt'] nu = Constant(self.problem.nu) self.tc.init_watch('init', 'Initialization', True, count_to_percent=False) self.tc.init_watch('solve', 'Running nonlinear solver', True, count_to_percent=True) self.tc.init_watch('next', 'Next step assignments', True, count_to_percent=True) self.tc.init_watch('saveVel', 'Saved velocity', True) self.tc.start('init') mesh = self.problem.mesh # Define function spaces (P2-P1) self.V = VectorFunctionSpace(mesh, "Lagrange", 2) # velocity self.Q = FunctionSpace(mesh, "Lagrange", 1) # pressure self.W = MixedFunctionSpace([self.V, self.Q]) self.PS = FunctionSpace(mesh, "Lagrange", 2) # partial solution (must be same order as V) self.D = FunctionSpace(mesh, "Lagrange", 1) # velocity divergence space # to assign solution in space W.sub(0) to Function(V) we need FunctionAssigner (cannot be assigned directly) fa = FunctionAssigner(self.V, self.W.sub(0)) velSp = Function(self.V) problem.initialize(self.V, self.Q, self.PS, self.D) # Define unknown and test function(s) NS v, q = TestFunctions(self.W) w = Function(self.W) dw = TrialFunction(self.W) u, p = split(w) # Define fields n = FacetNormal(mesh) I = Identity(u.geometric_dimension()) theta = 0.5 # Crank-Nicholson k = Constant(self.metadata['dt']) # Initial conditions: u0 velocity at previous time step u1 velocity two time steps back p0 previous pressure [u0, p0] = self.problem.get_initial_conditions([{'type': 'v', 'time': 0.0}, {'type': 'p', 'time': 0.0}]) if doSave: problem.save_vel(False, u0, 0.0) # boundary conditions bcu, bcp = problem.get_boundary_conditions(self.bc == 'outflow', self.W.sub(0), self.W.sub(1)) # NT bcp is not used # Define steady part of the equation def T(u): return -p * I + 2.0 * nu * sym(grad(u)) def F(u, v, q): return (inner(T(u), grad(v)) - q * div(u)) * dx + inner(grad(u) * u, v) * dx # Define variational forms F_ns = (inner((u - u0), v) / k) * dx + (1.0 - theta) * F(u0, v, q) + theta * F(u, v, q) J_ns = derivative(F_ns, w, dw) # J_ns = derivative(F_ns, w) # did not work # NS_problem = NonlinearVariationalProblem(F_ns, w, bcu, J_ns, form_compiler_parameters=ffc_options) NS_problem = NonlinearVariationalProblem(F_ns, w, bcu, J_ns) # (var. formulation, unknown, Dir. BC, jacobian, optional) NS_solver = NonlinearVariationalSolver(NS_problem) prm = NS_solver.parameters prm['newton_solver']['absolute_tolerance'] = 1E-08 prm['newton_solver']['relative_tolerance'] = 1E-08 # prm['newton_solver']['maximum_iterations'] = 45 # prm['newton_solver']['relaxation_parameter'] = 1.0 prm['newton_solver']['linear_solver'] = 'mumps' info(NS_solver.parameters, True) self.tc.end('init') # Time-stepping info("Running of direct method") ttime = self.metadata['time'] t = dt step = 1 while t < (ttime + dt/2.0): info("t = %f" % t) self.problem.update_time(t, step) if self.MPI_rank == 0: problem.write_status_file(t) if doSave: save_this_step = problem.save_this_step # Compute begin("Solving NS ....") try: self.tc.start('solve') NS_solver.solve() self.tc.end('solve') except RuntimeError as inst: problem.report_fail(t) return 1 end() # Extract solutions: (u, p) = w.split() fa.assign(velSp, u) # we are assigning twice (now and inside save_vel), but it works with one method save_vel for direct and # projection (we could split save_vel to save one assign) if save_this_step: self.tc.start('saveVel') problem.save_vel(False, velSp, t) self.tc.end('saveVel') if save_this_step and not onlyVel: problem.save_div(False, u) problem.compute_err(False, u, t) problem.compute_div(False, u) # foo = Function(self.Q) # foo.assign(p) # problem.averaging_pressure(foo) # if save_this_step and not onlyVel: # problem.save_pressure(False, foo) if save_this_step and not onlyVel: problem.save_pressure(False, p) # compute functionals (e. g. forces) problem.compute_functionals(u, p, t) # Move to next time step self.tc.start('next') u0.assign(velSp) t = round(t + dt, 6) # round time step to 0.000001 step += 1 self.tc.end('next') info("Finished: direct method") problem.report() return 0
def solve(A,b,u,IS,Fspace,IterType,OuterTol,InnerTol,HiptmairMatrices,KSPlinearfluids,kspF,Fp,MatrixLinearFluids,kspFp): if IterType == "Full": kspOuter = PETSc.KSP().create() kspOuter.setTolerances(OuterTol) kspOuter.setType('fgmres') u_is = PETSc.IS().createGeneral(range(Fspace[0].dim())) p_is = PETSc.IS().createGeneral(range(Fspace[0].dim(),Fspace[0].dim()+Fspace[1].dim())) Bt = A.getSubMatrix(u_is,p_is) reshist = {} def monitor(ksp, its, fgnorm): reshist[its] = fgnorm print "OUTER:", fgnorm kspOuter.setMonitor(monitor) pcOutter = kspOuter.getPC() pcOutter.setType(PETSc.PC.Type.KSP) kspOuter.setOperators(A,A) kspOuter.max_it = 500 kspInner = pcOutter.getKSP() kspInner.max_it = 100 kspInner.max_it = 100 reshist1 = {} def monitor(ksp, its, fgnorm): reshist1[its] = fgnorm print "INNER:", fgnorm # kspInner.setMonitor(monitor) kspInner.setType('gmres') kspInner.setTolerances(InnerTol) pcInner = kspInner.getPC() pcInner.setType(PETSc.PC.Type.PYTHON) pcInner.setPythonContext(MHDstabPrecond.InnerOuterWITHOUT(Fspace,kspF, KSPlinearfluids[0], KSPlinearfluids[1],Fp, HiptmairMatrices[3], HiptmairMatrices[4], HiptmairMatrices[2], HiptmairMatrices[0], HiptmairMatrices[1], HiptmairMatrices[6],1e-6,A)) PP = PETSc.Mat().createPython([A.size[0], A.size[0]]) PP.setType('python') p = PrecondMulti.MultiApply(Fspace,A,HiptmairMatrices[6],MatrixLinearFluids[1],MatrixLinearFluids[0],kspFp, HiptmairMatrices[3]) PP.setPythonContext(p) kspInner.setOperators(PP) tic() scale = b.norm() b = b/scale print b.norm() kspOuter.solve(b, u) u = u*scale print toc() # print s.getvalue() NSits = kspOuter.its del kspOuter Mits = kspInner.its del kspInner # print u.array return u,NSits,Mits NS_is = IS[0] M_is = IS[1] kspNS = PETSc.KSP().create() kspM = PETSc.KSP().create() kspNS.setTolerances(OuterTol) kspNS.setOperators(A.getSubMatrix(NS_is,NS_is)) kspM.setOperators(A.getSubMatrix(M_is,M_is)) del A uNS = u.getSubVector(NS_is) bNS = b.getSubVector(NS_is) kspNS.setType('gmres') pcNS = kspNS.getPC() kspNS.setTolerances(OuterTol) pcNS.setType(PETSc.PC.Type.PYTHON) if IterType == "MD": pcNS.setPythonContext(NSpreconditioner.NSPCD(MixedFunctionSpace([Fspace[0],Fspace[1]]), kspF, KSPlinearfluids[0], KSPlinearfluids[1],Fp)) else: pcNS.setPythonContext(StokesPrecond.MHDApprox(MixedFunctionSpace([Fspace[0],Fspace[1]]), kspF, KSPlinearfluids[1])) scale = bNS.norm() bNS = bNS/scale start_time = time.time() kspNS.solve(bNS, uNS) print ("{:25}").format("NS, time: "), " ==> ",("{:4f}").format(time.time() - start_time),("{:9}").format(" Its: "), ("{:4}").format(kspNS.its), ("{:9}").format(" time: "), ("{:4}").format(time.strftime('%X %x %Z')[0:5]) uNS = scale*uNS NSits = kspNS.its # kspNS.destroy() # for line in reshist.values(): # print line kspM.setFromOptions() kspM.setType(kspM.Type.MINRES) kspM.setTolerances(InnerTol) pcM = kspM.getPC() pcM.setType(PETSc.PC.Type.PYTHON) pcM.setPythonContext(MP.Hiptmair(MixedFunctionSpace([Fspace[2],Fspace[3]]), HiptmairMatrices[3], HiptmairMatrices[4], HiptmairMatrices[2], HiptmairMatrices[0], HiptmairMatrices[1], HiptmairMatrices[6],1e-6)) # x = x*scale uM = u.getSubVector(M_is) bM = b.getSubVector(M_is) scale = bM.norm() bM = bM/scale start_time = time.time() kspM.solve(bM, uM) print ("{:25}").format("Maxwell solve, time: "), " ==> ",("{:4f}").format(time.time() - start_time),("{:9}").format(" Its: "), ("{:4}").format(kspM.its), ("{:9}").format(" time: "), ("{:4}").format(time.strftime('%X %x %Z')[0:5]) uM = uM*scale Mits = kspM.its kspM.destroy() u = IO.arrayToVec(np.concatenate([uNS.array, uM.array])) return u,NSits,Mits
def solve(W, P, mu, u_bcs, p_bcs, f, verbose=True, tol=1.0e-10 ): # Some initial sanity checks. assert mu > 0.0 WP = MixedFunctionSpace([W, P]) # Translate the boundary conditions into the product space. # This conditional loop is able to deal with conditions of the kind # # DirichletBC(W.sub(1), 0.0, right_boundary) # new_bcs = [] for k, bcs in enumerate([u_bcs, p_bcs]): for bc in bcs: space = bc.function_space() C = space.component() if len(C) == 0: new_bcs.append(DirichletBC(WP.sub(k), bc.value(), bc.domain_args[0])) elif len(C) == 1: new_bcs.append(DirichletBC(WP.sub(k).sub(int(C[0])), bc.value(), bc.domain_args[0])) else: raise RuntimeError('Illegal number of subspace components.') # Define variational problem (u, p) = TrialFunctions(WP) (v, q) = TestFunctions(WP) # Build system. # The sign of the div(u)-term is somewhat arbitrary since the right-hand # side is 0 here. We can either make the system symmetric or positive- # definite. # On a second note, we have # # \int grad(p).v = - \int p * div(v) + \int_\Gamma p n.v. # # Since, we have either p=0 or n.v=0 on the boundary, we could as well # replace the term dot(grad(p), v) by -p*div(v). # a = mu * inner(grad(u), grad(v))*dx \ - p * div(v) * dx \ - q * div(u) * dx #a = mu * inner(grad(u), grad(v))*dx + dot(grad(p), v) * dx \ # - div(u) * q * dx L = dot(f, v)*dx A, b = assemble_system(a, L, new_bcs) if has_petsc(): # For an assortment of preconditioners, see # # Performance and analysis of saddle point preconditioners # for the discrete steady-state Navier-Stokes equations; # H.C. Elman, D.J. Silvester, A.J. Wathen; # Numer. Math. (2002) 90: 665-688; # <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.145.3554>. # # Set up field split. W = SubSpace(WP, 0) P = SubSpace(WP, 1) u_dofs = W.dofmap().dofs() p_dofs = P.dofmap().dofs() prec = PETScPreconditioner() prec.set_fieldsplit([u_dofs, p_dofs], ['u', 'p']) PETScOptions.set('pc_type', 'fieldsplit') PETScOptions.set('pc_fieldsplit_type', 'additive') PETScOptions.set('fieldsplit_u_pc_type', 'lu') PETScOptions.set('fieldsplit_p_pc_type', 'jacobi') ## <http://scicomp.stackexchange.com/questions/7288/which-preconditioners-and-solver-in-petsc-for-indefinite-symmetric-systems-sho> #PETScOptions.set('pc_type', 'fieldsplit') ##PETScOptions.set('pc_fieldsplit_type', 'schur') ##PETScOptions.set('pc_fieldsplit_schur_fact_type', 'upper') #PETScOptions.set('pc_fieldsplit_detect_saddle_point') ##PETScOptions.set('fieldsplit_u_pc_type', 'lsc') ##PETScOptions.set('fieldsplit_u_ksp_type', 'preonly') #PETScOptions.set('pc_type', 'fieldsplit') #PETScOptions.set('fieldsplit_u_pc_type', 'hypre') #PETScOptions.set('fieldsplit_u_ksp_type', 'preonly') #PETScOptions.set('fieldsplit_p_pc_type', 'jacobi') #PETScOptions.set('fieldsplit_p_ksp_type', 'preonly') ## From PETSc/src/ksp/ksp/examples/tutorials/ex42-fsschur.opts: #PETScOptions.set('pc_type', 'fieldsplit') #PETScOptions.set('pc_fieldsplit_type', 'SCHUR') #PETScOptions.set('pc_fieldsplit_schur_fact_type', 'UPPER') #PETScOptions.set('fieldsplit_p_ksp_type', 'preonly') #PETScOptions.set('fieldsplit_u_pc_type', 'bjacobi') ## From ## ## Composable Linear Solvers for Multiphysics; ## J. Brown, M. Knepley, D.A. May, L.C. McInnes, B. Smith; ## <http://www.computer.org/csdl/proceedings/ispdc/2012/4805/00/4805a055-abs.html>; ## <http://www.mcs.anl.gov/uploads/cels/papers/P2017-0112.pdf>. ## #PETScOptions.set('pc_type', 'fieldsplit') #PETScOptions.set('pc_fieldsplit_type', 'schur') #PETScOptions.set('pc_fieldsplit_schur_factorization_type', 'upper') ## #PETScOptions.set('fieldsplit_u_ksp_type', 'cg') #PETScOptions.set('fieldsplit_u_ksp_rtol', 1.0e-6) #PETScOptions.set('fieldsplit_u_pc_type', 'bjacobi') #PETScOptions.set('fieldsplit_u_sub_pc_type', 'cholesky') ## #PETScOptions.set('fieldsplit_p_ksp_type', 'fgmres') #PETScOptions.set('fieldsplit_p_ksp_constant_null_space') #PETScOptions.set('fieldsplit_p_pc_type', 'lsc') ## #PETScOptions.set('fieldsplit_p_lsc_ksp_type', 'cg') #PETScOptions.set('fieldsplit_p_lsc_ksp_rtol', 1.0e-2) #PETScOptions.set('fieldsplit_p_lsc_ksp_constant_null_space') ##PETScOptions.set('fieldsplit_p_lsc_ksp_converged_reason') #PETScOptions.set('fieldsplit_p_lsc_pc_type', 'bjacobi') #PETScOptions.set('fieldsplit_p_lsc_sub_pc_type', 'icc') # Create Krylov solver with custom preconditioner. solver = PETScKrylovSolver('gmres', prec) solver.set_operator(A) else: # Use the preconditioner as recommended in # <http://fenicsproject.org/documentation/dolfin/dev/python/demo/pde/stokes-iterative/python/documentation.html>, # # prec = inner(grad(u), grad(v))*dx - p*q*dx # # although it doesn't seem to be too efficient. # The sign on the last term doesn't matter. prec = mu * inner(grad(u), grad(v))*dx \ - p*q*dx M, _ = assemble_system(prec, L, new_bcs) #solver = KrylovSolver('tfqmr', 'amg') solver = KrylovSolver('gmres', 'amg') solver.set_operators(A, M) solver.parameters['monitor_convergence'] = verbose solver.parameters['report'] = verbose solver.parameters['absolute_tolerance'] = 0.0 solver.parameters['relative_tolerance'] = tol solver.parameters['maximum_iterations'] = 500 # Solve up = Function(WP) solver.solve(up.vector(), b) # Get sub-functions u, p = up.split() return u, p
def RunJob(Tb, mu_value, path): runtimeInit = clock() tfile = File(path + '/t6t.pvd') mufile = File(path + "/mu.pvd") ufile = File(path + '/velocity.pvd') gradpfile = File(path + '/gradp.pvd') pfile = File(path + '/pstar.pvd') parameters = open(path + '/parameters', 'w', 0) vmeltfile = File(path + '/vmelt.pvd') rhofile = File(path + '/rhosolid.pvd') for name in dir(): ev = str(eval(name)) if name[0] != '_' and ev[0] != '<': parameters.write(name + ' = ' + ev + '\n') temp_values = [27. + 273, Tb + 273, 1300. + 273, 1305. + 273] dTemp = temp_values[3] - temp_values[0] temp_values = [x / dTemp for x in temp_values] # non dimensionalising temp mu_a = mu_value # this was taken from the blankenbach paper, can change.. Ep = b / dTemp mu_bot = exp(-Ep * (temp_values[3] * dTemp - 1573) + cc) * mu_a Ra = rho_0 * alpha * g * dTemp * h**3 / (kappa_0 * mu_a) w0 = rho_0 * alpha * g * dTemp * h**2 / mu_a tau = h / w0 p0 = mu_a * w0 / h print(mu_a, mu_bot, Ra, w0, p0) vslipx = 1.6e-09 / w0 vslip = Constant((vslipx, 0.0)) # nondimensional noslip = Constant((0.0, 0.0)) dt = 3.E11 / tau tEnd = 3.E13 / tau # non-dimensionalising times class PeriodicBoundary(SubDomain): def inside(self, x, on_boundary): return left(x, on_boundary) def map(self, x, y): y[0] = x[0] - MeshWidth y[1] = x[1] pbc = PeriodicBoundary() class TempExp(Expression): def eval(self, value, x): if x[1] >= LAB(x): value[0] = temp_values[0] + (temp_values[1] - temp_values[0] ) * (MeshHeight - x[1]) / (MeshHeight - LAB(x)) else: value[0] = temp_values[3] - ( temp_values[3] - temp_values[2]) * (x[1]) / (LAB(x)) class FluidTemp(Expression): def eval(self, value, x): if value[0] < 1295: value[0] = 1295 mesh = RectangleMesh(Point(0.0, 0.0), Point(MeshWidth, MeshHeight), nx, ny) Svel = VectorFunctionSpace(mesh, 'CG', 2, constrained_domain=pbc) Spre = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc) Stemp = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc) Smu = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc) Sgradp = VectorFunctionSpace(mesh, 'CG', 2, constrained_domain=pbc) Srho = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc) S0 = MixedFunctionSpace([Svel, Spre, Stemp]) u = Function(S0) v, p, T = split(u) v_t, p_t, T_t = TestFunctions(S0) T0 = interpolate(TempExp(), Stemp) muExp = Expression( 'exp(-Ep * (T_val * dTemp - 1573) + cc * x[2] / meshHeight)', Smu.ufl_element(), Ep=Ep, dTemp=dTemp, cc=cc, meshHeight=MeshHeight, T_val=T0) mu = interpolate(muExp, Smu) rhosolid = Function(Srho) deltarho = Function(Srho) v0 = Function(Svel) vmelt = Function(Svel) v_theta = (1. - theta) * v0 + theta * v T_theta = (1. - theta) * T + theta * T0 r_v = (inner(sym(grad(v_t)), 2.*mu*sym(grad(v))) \ - div(v_t)*p \ - T*v_t[1] )*dx r_p = p_t * div(v) * dx r_T = (T_t*((T - T0) \ + dt*inner(v_theta, grad(T_theta))) \ + (dt/Ra)*inner(grad(T_t), grad(T_theta)) )*dx # + k_s*(Tf-T_theta)*dt Tf = T0.interpolate(FluidTemp()) # Tf = T0.interpolate(Expression('value[0] >= 1295.0 ? value[0] : 1295.0')) # Tf.interpolate(Expression('value[0] >= 1295 ? value[0] : 1295')) # project(Expression('value[0] >= 1295 ? value[0] : 1295'), Tf) # Alex, a question for you: # can you see if there is a way to set Tf = T in regions where T >=1295 celsius # # 1295 celsius is my arbitrary choice for the LAB isotherm. In regions # where T < 1295 C, set Tf to be some constant for now, such as 1295 C. # Once we do this, then we can add in a term like that last line above where # it will only be non-zero when the solid temperature, T, is cooler than 1295 # can you do this? After this is done, we will then worry about a calculation # where we solve for Tf as a function of time in the regions cooler than 1295 C # Makes sense? If not, we can skype soon -- email me with questions # 3/19/16 r = r_v + r_p + r_T bcv0 = DirichletBC(S0.sub(0), noslip, top) bcv1 = DirichletBC(S0.sub(0), vslip, bottom) bcp0 = DirichletBC(S0.sub(1), Constant(0.0), bottom) bct0 = DirichletBC(S0.sub(2), Constant(temp_values[0]), top) bct1 = DirichletBC(S0.sub(2), Constant(temp_values[3]), bottom) bcs = [bcv0, bcv1, bcp0, bct0, bct1] t = 0 count = 0 while (t < tEnd): solve(r == 0, u, bcs) t += dt nV, nP, nT = u.split() gp = grad(nP) rhosolid = rho_0 * (1 - alpha * (nT * dTemp - 1573)) deltarho = rhosolid - rhomelt yvec = Constant((0.0, 1.0)) vmelt = nV * w0 - darcy * (gp * p0 / h - deltarho * yvec * g) if (count % 100 == 0): pfile << nP ufile << nV tfile << nT mufile << mu gradpfile << project(grad(nP), Sgradp) mufile << project(mu * mu_a, Smu) rhofile << project(rhosolid, Srho) vmeltfile << project(vmelt, Svel) count += 1 assign(T0, nT) assign(v0, nV) mu.interpolate(muExp) print('Case mu=%g, Tb=%g complete.' % (mu_a, Tb), ' Run time =', clock() - runtimeInit, 's')
def lid_driven_cavity(): n = 40 mesh = RectangleMesh(0.0, 0.0, 1.0, 1.0, n, n, "crossed") # Define mesh and boundaries. class LeftBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] < DOLFIN_EPS class RightBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] > 1.0 - DOLFIN_EPS class LowerBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] < DOLFIN_EPS class UpperBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] > 1.0 - DOLFIN_EPS class RestrictedUpperBoundary(SubDomain): def inside(self, x, on_boundary): return ( on_boundary and x[1] > 1.0 - DOLFIN_EPS and DOLFIN_EPS < x[0] and x[0] < 0.5 - DOLFIN_EPS ) left = LeftBoundary() right = RightBoundary() lower = LowerBoundary() upper = UpperBoundary() # restricted_upper = RestrictedUpperBoundary() V = FunctionSpace(mesh, "CG", 2) # Be particularly careful with the boundary conditions. # The main problem here is that the PPE system is consistent if and only # if # # \int_\Omega div(u) = \int_\Gamma n.u = 0. # # This is exactly and even pointwise fulfilled for the continuous problem. # In the discrete case, we can have to make sure that n.u is 0 all along # the boundary. # In the lid-driven cavity problem, of particular interest are the corner # points at the lid. One has to assert that the z-component of u is 0 all # across the lid, and the x-component of u is 0 everywhere but the lid. # Since u is L2-"continuous", the lid condition on u_x must not be enforced # in the corner points. The u_y component must be enforced all over the # lid, including the end points. W = MixedFunctionSpace([V, V]) u_bcs = [ DirichletBC(W, (0.0, 0.0), left), DirichletBC(W, (0.0, 0.0), right), # DirichletBC(W.sub(0), Expression('x[0]'), restricted_upper), DirichletBC(W, (0.0, 0.0), lower), DirichletBC(W.sub(0), Constant("1.0"), upper), DirichletBC(W.sub(1), 0.0, upper), # DirichletBC(W.sub(0), Constant('-1.0'), lower), # DirichletBC(W.sub(1), 0.0, lower), # DirichletBC(W.sub(1), Constant('1.0'), left), # DirichletBC(W.sub(0), 0.0, left), # DirichletBC(W.sub(1), Constant('-1.0'), right), # DirichletBC(W.sub(0), 0.0, right), ] P = FunctionSpace(mesh, "CG", 1) p_bcs = [] return mesh, W, P, u_bcs, p_bcs
def solve(self, problem): self.problem = problem doSave = problem.doSave save_this_step = False onlyVel = problem.saveOnlyVel dt = self.metadata['dt'] nu = Constant(self.problem.nu) self.tc.init_watch('init', 'Initialization', True, count_to_percent=False) self.tc.init_watch('solve', 'Running nonlinear solver', True, count_to_percent=True) self.tc.init_watch('next', 'Next step assignments', True, count_to_percent=True) self.tc.init_watch('saveVel', 'Saved velocity', True) self.tc.start('init') mesh = self.problem.mesh # Define function spaces (P2-P1) self.V = VectorFunctionSpace(mesh, "Lagrange", 2) # velocity self.Q = FunctionSpace(mesh, "Lagrange", 1) # pressure self.W = MixedFunctionSpace([self.V, self.Q]) self.PS = FunctionSpace( mesh, "Lagrange", 2) # partial solution (must be same order as V) self.D = FunctionSpace(mesh, "Lagrange", 1) # velocity divergence space # to assign solution in space W.sub(0) to Function(V) we need FunctionAssigner (cannot be assigned directly) fa = FunctionAssigner(self.V, self.W.sub(0)) velSp = Function(self.V) problem.initialize(self.V, self.Q, self.PS, self.D) # Define unknown and test function(s) NS v, q = TestFunctions(self.W) w = Function(self.W) dw = TrialFunction(self.W) u, p = split(w) # Define fields n = FacetNormal(mesh) I = Identity(u.geometric_dimension()) theta = 0.5 # Crank-Nicholson k = Constant(self.metadata['dt']) # Initial conditions: u0 velocity at previous time step u1 velocity two time steps back p0 previous pressure [u0, p0] = self.problem.get_initial_conditions([{ 'type': 'v', 'time': 0.0 }, { 'type': 'p', 'time': 0.0 }]) if doSave: problem.save_vel(False, u0) # boundary conditions bcu, bcp = problem.get_boundary_conditions(False, self.W.sub(0), self.W.sub(1)) # Define steady part of the equation def T(u): return -p * I + 2.0 * nu * sym(grad(u)) def F(u, v, q): return (inner(T(u), grad(v)) - q * div(u)) * dx + inner( grad(u) * u, v) * dx # Define variational forms F_ns = (inner( (u - u0), v) / k) * dx + (1.0 - theta) * F(u0, v, q) + theta * F( u, v, q) J_ns = derivative(F_ns, w, dw) # J_ns = derivative(F_ns, w) # did not work # NS_problem = NonlinearVariationalProblem(F_ns, w, bcu, J_ns, form_compiler_parameters=ffc_options) NS_problem = NonlinearVariationalProblem(F_ns, w, bcu, J_ns) # (var. formulation, unknown, Dir. BC, jacobian, optional) NS_solver = NonlinearVariationalSolver(NS_problem) prm = NS_solver.parameters prm['newton_solver']['absolute_tolerance'] = 1E-08 prm['newton_solver']['relative_tolerance'] = 1E-08 # prm['newton_solver']['maximum_iterations'] = 45 # prm['newton_solver']['relaxation_parameter'] = 1.0 prm['newton_solver']['linear_solver'] = 'mumps' # prm['newton_solver']['lu_solver']['same_nonzero_pattern'] = True info(NS_solver.parameters, True) self.tc.end('init') # Time-stepping info("Running of direct method") ttime = self.metadata['time'] t = dt step = 1 while t < (ttime + dt / 2.0): self.problem.update_time(t, step) if self.MPI_rank == 0: problem.write_status_file(t) if doSave: save_this_step = problem.save_this_step # Compute begin("Solving NS ....") try: self.tc.start('solve') NS_solver.solve() self.tc.end('solve') except RuntimeError as inst: problem.report_fail(t) return 1 end() # Extract solutions: (u, p) = w.split() fa.assign(velSp, u) # we are assigning twice (now and inside save_vel), but it works with one method save_vel for direct and # projection (we could split save_vel to save one assign) if save_this_step: self.tc.start('saveVel') problem.save_vel(False, velSp) self.tc.end('saveVel') if save_this_step and not onlyVel: problem.save_div(False, u) problem.compute_err(False, u, t) problem.compute_div(False, u) # foo = Function(self.Q) # foo.assign(p) # problem.averaging_pressure(foo) # if save_this_step and not onlyVel: # problem.save_pressure(False, foo) if save_this_step and not onlyVel: problem.save_pressure(False, p) # compute functionals (e. g. forces) problem.compute_functionals(u, p, t, step) # Move to next time step self.tc.start('next') u0.assign(velSp) t = round(t + dt, 6) # round time step to 0.000001 step += 1 self.tc.end('next') info("Finished: direct method") problem.report() return 0
def lid_driven_cavity(): n = 40 mesh = RectangleMesh(0.0, 0.0, 1.0, 1.0, n, n, 'crossed') # Define mesh and boundaries. class LeftBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] < DOLFIN_EPS class RightBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[0] > 1.0-DOLFIN_EPS class LowerBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] < DOLFIN_EPS class UpperBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] > 1.0-DOLFIN_EPS class RestrictedUpperBoundary(SubDomain): def inside(self, x, on_boundary): return on_boundary and x[1] > 1.0-DOLFIN_EPS \ and DOLFIN_EPS < x[0] and x[0] < 0.5-DOLFIN_EPS left = LeftBoundary() right = RightBoundary() lower = LowerBoundary() upper = UpperBoundary() # restricted_upper = RestrictedUpperBoundary() V = FunctionSpace(mesh, 'CG', 2) # Be particularly careful with the boundary conditions. # The main problem here is that the PPE system is consistent if and only # if # # \int_\Omega div(u) = \int_\Gamma n.u = 0. # # This is exactly and even pointwise fulfilled for the continuous problem. # In the discrete case, we can have to make sure that n.u is 0 all along # the boundary. # In the lid-driven cavity problem, of particular interest are the corner # points at the lid. One has to assert that the z-component of u is 0 all # across the lid, and the x-component of u is 0 everywhere but the lid. # Since u is L2-"continuous", the lid condition on u_x must not be enforced # in the corner points. The u_y component must be enforced all over the # lid, including the end points. W = MixedFunctionSpace([V, V]) u_bcs = [ DirichletBC(W, (0.0, 0.0), left), DirichletBC(W, (0.0, 0.0), right), #DirichletBC(W.sub(0), Expression('x[0]'), restricted_upper), DirichletBC(W, (0.0, 0.0), lower), DirichletBC(W.sub(0), Constant('1.0'), upper), DirichletBC(W.sub(1), 0.0, upper), #DirichletBC(W.sub(0), Constant('-1.0'), lower), #DirichletBC(W.sub(1), 0.0, lower), #DirichletBC(W.sub(1), Constant('1.0'), left), #DirichletBC(W.sub(0), 0.0, left), #DirichletBC(W.sub(1), Constant('-1.0'), right), #DirichletBC(W.sub(0), 0.0, right), ] P = FunctionSpace(mesh, 'CG', 1) p_bcs = [] return mesh, W, P, u_bcs, p_bcs
v1 = Constant((1.0, 0.0)) v2 = Constant((-1.0, 0.0)) def left(x, on_boundary): return on_boundary and near(x[0], 0.0) def right(x, on_boundary): return on_boundary and near(x[0], 1.0) mesh = RectangleMesh(Point(0.0, 0.0), Point(1.0, 1.0), 50, 50) dt = 0.01 S = FunctionSpace(mesh, 'CG', 1) W = MixedFunctionSpace([S, S]) u = Function(W) T, Tf = split(u) # T, Tf = TrialFunctions(W) T_t, Tf_t = TestFunctions(W) T0 = interpolate(Expression('1.0 / (10.0 * x[0] + 1.0)'), S) Tf0 = interpolate(Expression('1.0 / (10.0 * (1.0 - x[0]) + 1.0)'), S) heat_transfer = 10.0 * (Tf - T) * dt r_1 = T_t * ( (T - T0) + dt * dot(v1, grad(T)) - heat_transfer) * dx
def run_with_params(Tb, mu_value, k_s, path): run_time_init = clock() temperature_vals = [27.0 + 273, Tb + 273, 1300.0 + 273, 1305.0 + 273] temp_prof = TemperatureProfile(temperature_vals) mu_a = mu_value # this was taken from the Blankenbach paper, can change Ep = b / temp_prof.delta mu_bot = exp(-Ep * (temp_prof.bottom * temp_prof.delta - 1573.0) + cc) * mu_a Ra = rho_0 * alpha * g * temp_prof.delta * h**3 / (kappa_0 * mu_a) w0 = rho_0 * alpha * g * temp_prof.delta * h**2 / mu_a tau = h / w0 p0 = mu_a * w0 / h log(mu_a, mu_bot, Ra, w0, p0) vslipx = 1.6e-09 / w0 vslip = Constant((vslipx, 0.0)) # Non-dimensional noslip = Constant((0.0, 0.0)) time_step = 3.0E11 / tau / 10.0 dt = Constant(time_step) tEnd = 3.0E15 / tau / 5.0 # Non-dimensionalising times mesh = RectangleMesh(Point(0.0, 0.0), Point(mesh_width, mesh_height), nx, ny) pbc = PeriodicBoundary() W = VectorFunctionSpace(mesh, 'CG', 2, constrained_domain=pbc) S = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc) WSSS = MixedFunctionSpace([W, S, S, S]) # WSSS -> W u = Function(WSSS) # Instead of TrialFunctions, we use split(u) for our non-linear problem v, p, T, Tf = split(u) v_t, p_t, T_t, Tf_t = TestFunctions(WSSS) T0 = interpolate(temp_prof, S) FluidTemp = Expression('max(T0, 1.031)', T0=T0) muExp = Expression( 'exp(-Ep * (T_val * dTemp - 1573.0) + cc * x[1] / mesh_height)', Ep=Ep, dTemp=temp_prof.delta, cc=cc, mesh_height=mesh_height, T_val=T0) Tf0 = interpolate(temp_prof, S) mu = Function(S) v0 = Function(W) v_theta = (1.0 - theta) * v0 + theta * v T_theta = (1.0 - theta) * T0 + theta * T Tf_theta = (1.0 - theta) * Tf0 + theta * Tf r_v = (inner(sym(grad(v_t)), 2.0 * mu * sym(grad(v))) - div(v_t) * p - T * v_t[1]) * dx r_p = p_t * div(v) * dx heat_transfer = k_s * (Tf_theta - T_theta) * dt r_T = (T_t * ((T - T0) + dt * inner(v_theta, grad(T_theta))) + (dt / Ra) * inner(grad(T_t), grad(T_theta)) - T_t * heat_transfer) * dx # yvec = Constant((0.0, 1.0)) # rhosolid = rho_0 * (1.0 - alpha * (T_theta * temp_prof.delta - 1573.0)) # deltarho = rhosolid - rhomelt # v_f = v_theta - darcy * (grad(p) * p0 / h - deltarho * yvec * g) / w0 v_melt = Function(W) yvec = Constant((0.0, 1.0)) # TODO: inner -> dot, take out Tf_t r_Tf = (Tf_t * ((Tf - Tf0) + dt * dot(v_melt, grad(Tf_theta))) + Tf_t * heat_transfer) * dx r = r_v + r_p + r_T + r_Tf bcv0 = DirichletBC(WSSS.sub(0), noslip, top) bcv1 = DirichletBC(WSSS.sub(0), vslip, bottom) bcp0 = DirichletBC(WSSS.sub(1), Constant(0.0), bottom) bct0 = DirichletBC(WSSS.sub(2), Constant(temp_prof.surface), top) bct1 = DirichletBC(WSSS.sub(2), Constant(temp_prof.bottom), bottom) bctf1 = DirichletBC(WSSS.sub(3), Constant(temp_prof.bottom), bottom) bcs = [bcv0, bcv1, bcp0, bct0, bct1, bctf1] t = 0 count = 0 files = DefaultDictByKey(partial(create_xdmf, path)) while t < tEnd: mu.interpolate(muExp) rhosolid = rho_0 * (1.0 - alpha * (T0 * temp_prof.delta - 1573.0)) deltarho = rhosolid - rhomelt assign( v_melt, project(v0 - darcy * (grad(p) * p0 / h - deltarho * yvec * g) / w0, W)) # use nP after to avoid projection? # pdb.set_trace() solve(r == 0, u, bcs) nV, nP, nT, nTf = u.split() if count % output_every == 0: time_left(count, tEnd / time_step, run_time_init) # TODO: Make sure all writes are to the same function for each time step files['T_fluid'].write(nTf) files['p'].write(nP) files['v_solid'].write(nV) files['T_solid'].write(nT) files['mu'].write(mu) files['v_melt'].write(v_melt) files['gradp'].write(project(grad(nP), W)) files['rho'].write(project(rhosolid, S)) files['Tf_grad'].write(project(grad(Tf), W)) files['advect'].write(project(dt * dot(v_melt, grad(nTf)))) files['ht'].write(project(heat_transfer, S)) assign(T0, nT) assign(v0, nV) assign(Tf0, nTf) t += time_step count += 1 log('Case mu=%g, Tb=%g complete. Run time = %g s' % (mu_a, Tb, clock() - run_time_init))
def solve(A, b, u, params, Fspace, SolveType, IterType, OuterTol, InnerTol, HiptmairMatrices, Hiptmairtol, KSPlinearfluids, Fp, kspF): if SolveType == "Direct": ksp = PETSc.KSP() ksp.create(comm=PETSc.COMM_WORLD) pc = ksp.getPC() ksp.setType('preonly') pc.setType('lu') OptDB = PETSc.Options() OptDB['pc_factor_mat_solver_package'] = "mumps" OptDB['pc_factor_mat_ordering_type'] = "rcm" ksp.setFromOptions() scale = b.norm() b = b / scale ksp.setOperators(A, A) del A ksp.solve(b, u) # Mits +=dodim u = u * scale MO.PrintStr("Number iterations = " + str(ksp.its), 60, "+", "\n\n", "\n\n") return u, ksp.its, 0 elif SolveType == "Direct-class": ksp = PETSc.KSP() ksp.create(comm=PETSc.COMM_WORLD) pc = ksp.getPC() ksp.setType('gmres') pc.setType('none') ksp.setFromOptions() scale = b.norm() b = b / scale ksp.setOperators(A, A) del A ksp.solve(b, u) # Mits +=dodim u = u * scale MO.PrintStr("Number iterations = " + str(ksp.its), 60, "+", "\n\n", "\n\n") return u, ksp.its, 0 else: # u = b.duplicate() if IterType == "Full": ksp = PETSc.KSP() ksp.create(comm=PETSc.COMM_WORLD) pc = ksp.getPC() ksp.setType('fgmres') pc.setType('python') OptDB = PETSc.Options() OptDB['ksp_gmres_restart'] = 200 # FSpace = [Velocity,Magnetic,Pressure,Lagrange] reshist = {} def monitor(ksp, its, fgnorm): reshist[its] = fgnorm print its, " OUTER:", fgnorm # ksp.setMonitor(monitor) ksp.max_it = 1000 W = Fspace FFSS = [W.sub(0), W.sub(1), W.sub(2), W.sub(3)] pc.setPythonContext( MHDprec.InnerOuterMAGNETICapprox( FFSS, kspF, KSPlinearfluids[0], KSPlinearfluids[1], Fp, HiptmairMatrices[3], HiptmairMatrices[4], HiptmairMatrices[2], HiptmairMatrices[0], HiptmairMatrices[1], HiptmairMatrices[6], Hiptmairtol)) #OptDB = PETSc.Options() # OptDB['pc_factor_mat_solver_package'] = "mumps" # OptDB['pc_factor_mat_ordering_type'] = "rcm" # ksp.setFromOptions() scale = b.norm() b = b / scale ksp.setOperators(A, A) del A ksp.solve(b, u) # Mits +=dodim u = u * scale MO.PrintStr("Number iterations = " + str(ksp.its), 60, "+", "\n\n", "\n\n") return u, ksp.its, 0 IS = MO.IndexSet(Fspace, '2by2') M_is = IS[1] NS_is = IS[0] kspNS = PETSc.KSP().create() kspM = PETSc.KSP().create() kspNS.setTolerances(OuterTol) kspNS.setOperators(A[0]) kspM.setOperators(A[1]) # print P.symmetric if IterType == "MD": kspNS.setType('gmres') kspNS.max_it = 500 pcNS = kspNS.getPC() pcNS.setType(PETSc.PC.Type.PYTHON) pcNS.setPythonContext( NSpreconditioner.NSPCD( MixedFunctionSpace([Fspace.sub(0), Fspace.sub(1)]), kspF, KSPlinearfluids[0], KSPlinearfluids[1], Fp)) elif IterType == "CD": kspNS.setType('minres') pcNS = kspNS.getPC() pcNS.setType(PETSc.PC.Type.PYTHON) Q = KSPlinearfluids[1].getOperators()[0] Q = 1. / params[2] * Q KSPlinearfluids[1].setOperators(Q, Q) pcNS.setPythonContext( StokesPrecond.MHDApprox( MixedFunctionSpace([Fspace.sub(0), Fspace.sub(1)]), kspF, KSPlinearfluids[1])) reshist = {} def monitor(ksp, its, fgnorm): reshist[its] = fgnorm print fgnorm # kspNS.setMonitor(monitor) uNS = u.getSubVector(NS_is) bNS = b.getSubVector(NS_is) # print kspNS.view() scale = bNS.norm() bNS = bNS / scale print bNS.norm() kspNS.solve(bNS, uNS) uNS = uNS * scale NSits = kspNS.its kspNS.destroy() # for line in reshist.values(): # print line kspM.setFromOptions() kspM.setType(kspM.Type.MINRES) kspM.setTolerances(InnerTol) pcM = kspM.getPC() pcM.setType(PETSc.PC.Type.PYTHON) pcM.setPythonContext( MP.Hiptmair(MixedFunctionSpace([Fspace.sub(2), Fspace.sub(3)]), HiptmairMatrices[3], HiptmairMatrices[4], HiptmairMatrices[2], HiptmairMatrices[0], HiptmairMatrices[1], HiptmairMatrices[6], Hiptmairtol)) uM = u.getSubVector(M_is) bM = b.getSubVector(M_is) scale = bM.norm() bM = bM / scale print bM.norm() kspM.solve(bM, uM) uM = uM * scale Mits = kspM.its kspM.destroy() u = IO.arrayToVec(np.concatenate([uNS.array, uM.array])) MO.PrintStr("Number of M iterations = " + str(Mits), 60, "+", "\n\n", "\n\n") MO.PrintStr("Number of NS/S iterations = " + str(NSits), 60, "+", "\n\n", "\n\n") return u, NSits, Mits
def RunJob(Tb, mu_value, path): runtimeInit = clock() tfile = File(path + '/t6t.pvd') mufile = File(path + "/mu.pvd") ufile = File(path + '/velocity.pvd') gradpfile = File(path + '/gradp.pvd') pfile = File(path + '/pstar.pvd') parameters = open(path + '/parameters', 'w', 0) vmeltfile = File(path + '/vmelt.pvd') rhofile = File(path + '/rhosolid.pvd') for name in dir(): ev = str(eval(name)) if name[0] != '_' and ev[0] != '<': parameters.write(name + ' = ' + ev + '\n') temp_values = [27. + 273, Tb + 273, 1300. + 273, 1305. + 273] dTemp = temp_values[3] - temp_values[0] temp_values = [x / dTemp for x in temp_values] # non dimensionalising temp mu_a = mu_value # this was taken from the blankenbach paper, can change.. Ep = b / dTemp mu_bot = exp(-Ep * (temp_values[3] * dTemp - 1573) + cc) * mu_a Ra = rho_0 * alpha * g * dTemp * h**3 / (kappa_0 * mu_a) w0 = rho_0 * alpha * g * dTemp * h**2 / mu_a tau = h / w0 p0 = mu_a * w0 / h print(mu_a, mu_bot, Ra, w0, p0) vslipx = 1.6e-09 / w0 vslip = Constant((vslipx, 0.0)) # nondimensional noslip = Constant((0.0, 0.0)) dt = 3.E11 / tau tEnd = 3.E13 / tau # non-dimensionalising times class PeriodicBoundary(SubDomain): def inside(self, x, on_boundary): return left(x, on_boundary) def map(self, x, y): y[0] = x[0] - MeshWidth y[1] = x[1] pbc = PeriodicBoundary() class TempExp(Expression): def eval(self, value, x): if x[1] >= LAB(x): value[0] = temp_values[0] + (temp_values[1] - temp_values[0]) * (MeshHeight - x[1]) / (MeshHeight - LAB(x)) else: value[0] = temp_values[3] - (temp_values[3] - temp_values[2]) * (x[1]) / (LAB(x)) class FluidTemp(Expression): def eval(self, value, x): if value[0] < 1295: value[0] = 1295 mesh = RectangleMesh(Point(0.0, 0.0), Point(MeshWidth, MeshHeight), nx, ny) Svel = VectorFunctionSpace(mesh, 'CG', 2, constrained_domain=pbc) Spre = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc) Stemp = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc) Smu = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc) Sgradp = VectorFunctionSpace(mesh, 'CG', 2, constrained_domain=pbc) Srho = FunctionSpace(mesh, 'CG', 1, constrained_domain=pbc) S0 = MixedFunctionSpace([Svel, Spre, Stemp]) u = Function(S0) v, p, T = split(u) v_t, p_t, T_t = TestFunctions(S0) T0 = interpolate(TempExp(), Stemp) muExp = Expression('exp(-Ep * (T_val * dTemp - 1573) + cc * x[2] / meshHeight)', Smu.ufl_element(), Ep=Ep, dTemp=dTemp, cc=cc, meshHeight=MeshHeight, T_val=T0) mu = interpolate(muExp, Smu) rhosolid = Function(Srho) deltarho = Function(Srho) v0 = Function(Svel) vmelt = Function(Svel) v_theta = (1. - theta)*v0 + theta*v T_theta = (1. - theta)*T + theta*T0 r_v = (inner(sym(grad(v_t)), 2.*mu*sym(grad(v))) \ - div(v_t)*p \ - T*v_t[1] )*dx r_p = p_t*div(v)*dx r_T = (T_t*((T - T0) \ + dt*inner(v_theta, grad(T_theta))) \ + (dt/Ra)*inner(grad(T_t), grad(T_theta)) )*dx # + k_s*(Tf-T_theta)*dt Tf = T0.interpolate(FluidTemp()) # Tf = T0.interpolate(Expression('value[0] >= 1295.0 ? value[0] : 1295.0')) # Tf.interpolate(Expression('value[0] >= 1295 ? value[0] : 1295')) # project(Expression('value[0] >= 1295 ? value[0] : 1295'), Tf) # Alex, a question for you: # can you see if there is a way to set Tf = T in regions where T >=1295 celsius # # 1295 celsius is my arbitrary choice for the LAB isotherm. In regions # where T < 1295 C, set Tf to be some constant for now, such as 1295 C. # Once we do this, then we can add in a term like that last line above where # it will only be non-zero when the solid temperature, T, is cooler than 1295 # can you do this? After this is done, we will then worry about a calculation # where we solve for Tf as a function of time in the regions cooler than 1295 C # Makes sense? If not, we can skype soon -- email me with questions # 3/19/16 r = r_v + r_p + r_T bcv0 = DirichletBC(S0.sub(0), noslip, top) bcv1 = DirichletBC(S0.sub(0), vslip, bottom) bcp0 = DirichletBC(S0.sub(1), Constant(0.0), bottom) bct0 = DirichletBC(S0.sub(2), Constant(temp_values[0]), top) bct1 = DirichletBC(S0.sub(2), Constant(temp_values[3]), bottom) bcs = [bcv0, bcv1, bcp0, bct0, bct1] t = 0 count = 0 while (t < tEnd): solve(r == 0, u, bcs) t += dt nV, nP, nT = u.split() gp = grad(nP) rhosolid = rho_0 * (1 - alpha * (nT * dTemp - 1573)) deltarho = rhosolid - rhomelt yvec = Constant((0.0, 1.0)) vmelt = nV * w0 - darcy * (gp * p0 / h - deltarho * yvec * g) if (count % 100 == 0): pfile << nP ufile << nV tfile << nT mufile << mu gradpfile << project(grad(nP), Sgradp) mufile << project(mu * mu_a, Smu) rhofile << project(rhosolid, Srho) vmeltfile << project(vmelt, Svel) count += 1 assign(T0, nT) assign(v0, nV) mu.interpolate(muExp) print('Case mu=%g, Tb=%g complete.' % (mu_a, Tb), ' Run time =', clock() - runtimeInit, 's')