def matrix_assembly(self, size=32, degree=1, dim=2, fs='scalar'): with self.timed_region('mesh'): mesh = make_mesh[dim](size) with self.timed_region('setup'): FS = {'scalar': FunctionSpace, 'vector': VectorFunctionSpace}[fs] V = FS(mesh, "Lagrange", degree) # Define boundary condition bc = DirichletBC(V, 0.0, [3, 4]) # Define variational problem u = TrialFunction(V) v = TestFunction(V) a = inner(grad(u), grad(v))*dx with self.timed_region('assembly'): A = assemble(a) A.M with self.timed_region('reassembly'): A = assemble(a, tensor=A) A.M # Clear sparsity cache A.M.sparsity.dsets[0].set._cache.clear() with self.timed_region('assembly bcs'): A = assemble(a, bcs=bc) A.M with self.timed_region('reassembly bcs'): A = assemble(a, tensor=A, bcs=bc) A.M for task, timer in get_timers(reset=True).items(): self.register_timing(task, timer.total)
def explosive_source(self, T=0.01, h=2.5, explicit=True): self.series['h'] = h self.series['T'] = T self.series['explicit'] = explicit self.explosive_source_lf4(T=T, h=h, explicit=explicit, output=False) for task, timer in get_timers(reset=True).items(): self.register_timing(task, timer.total)
def assembly(self, size=32, degree=1, dim=2, fs='scalar'): with self.timed_region('mesh'): mesh = make_mesh[dim](size) with self.timed_region('setup'): FS = {'scalar': FunctionSpace, 'vector': VectorFunctionSpace}[fs] V = FS(mesh, 'CG', degree) Q = FunctionSpace(mesh, 'CG', degree) # Define variational problem u = TrialFunction(V) v = TestFunction(V) mass = inner(u, v) laplace = inner(grad(u), grad(v)) f = Function(Q).assign(1.0) g = Function(Q).assign(1.0) h = Function(Q).assign(1.0) A = assemble(mass * dx) with self.timed_region('mass premult 0'): assemble(mass * dx, tensor=A) A.M with self.timed_region('mass premult 1'): assemble(f * mass * dx, tensor=A) A.M with self.timed_region('mass premult 2'): assemble(g * f * mass * dx, tensor=A) A.M with self.timed_region('mass premult 3'): assemble(h * g * f * mass * dx, tensor=A) A.M with self.timed_region('laplace premult 0'): assemble(laplace * dx, tensor=A) A.M with self.timed_region('laplace premult 1'): assemble(f * laplace * dx, tensor=A) A.M with self.timed_region('laplace premult 2'): assemble(g * f * laplace * dx, tensor=A) A.M with self.timed_region('laplace premult 3'): assemble(h * g * f * laplace * dx, tensor=A) A.M with self.timed_region('helmholtz premult 0'): assemble((mass + laplace) * dx, tensor=A) A.M with self.timed_region('helmholtz premult 1'): assemble(f * (mass + laplace) * dx, tensor=A) A.M with self.timed_region('helmholtz premult 2'): assemble(g * f * (mass + laplace) * dx, tensor=A) A.M with self.timed_region('helmholtz premult 3'): assemble(h * g * f * (mass + laplace) * dx, tensor=A) A.M for task, timer in get_timers(reset=True).items(): self.register_timing(task, timer.total)
def assembly(self, size=32, degree=1, dim=2, fs='scalar'): with self.timed_region('mesh'): mesh = make_mesh[dim](size) with self.timed_region('setup'): FS = {'scalar': FunctionSpace, 'vector': VectorFunctionSpace}[fs] V = FS(mesh, 'CG', degree) Q = FunctionSpace(mesh, 'CG', degree) # Define variational problem u = TrialFunction(V) v = TestFunction(V) mass = inner(u, v) laplace = inner(grad(u), grad(v)) f = Function(Q).assign(1.0) g = Function(Q).assign(1.0) h = Function(Q).assign(1.0) A = assemble(mass*dx) with self.timed_region('mass premult 0'): assemble(mass*dx, tensor=A) A.M with self.timed_region('mass premult 1'): assemble(f*mass*dx, tensor=A) A.M with self.timed_region('mass premult 2'): assemble(g*f*mass*dx, tensor=A) A.M with self.timed_region('mass premult 3'): assemble(h*g*f*mass*dx, tensor=A) A.M with self.timed_region('laplace premult 0'): assemble(laplace*dx, tensor=A) A.M with self.timed_region('laplace premult 1'): assemble(f*laplace*dx, tensor=A) A.M with self.timed_region('laplace premult 2'): assemble(g*f*laplace*dx, tensor=A) A.M with self.timed_region('laplace premult 3'): assemble(h*g*f*laplace*dx, tensor=A) A.M with self.timed_region('helmholtz premult 0'): assemble((mass+laplace)*dx, tensor=A) A.M with self.timed_region('helmholtz premult 1'): assemble(f*(mass+laplace)*dx, tensor=A) A.M with self.timed_region('helmholtz premult 2'): assemble(g*f*(mass+laplace)*dx, tensor=A) A.M with self.timed_region('helmholtz premult 3'): assemble(h*g*f*(mass+laplace)*dx, tensor=A) A.M for task, timer in get_timers(reset=True).items(): self.register_timing(task, timer.total)
def forms(self, q=1, p=1, dim=3, max_nf=3, form='mass', dump_kernel=False): mesh = meshes[dim] A = assemble(eval(form)(q, p, dim, mesh)) for nf in range(max_nf + 1): f = eval(form)(q, p, dim, mesh, nf) with self.timed_region('nf %d' % nf): assemble(f, tensor=A) A.M if dump_kernel: for i, k in enumerate(f._kernels): with open('kernels/f_%s%d_q%d_p%d_dim%d_nf%d.c' % (form, i, q, p, dim, nf), 'w') as fil: fil.write(k[-1].code) t = get_timers(reset=True) task = 'Assemble cells' self.register_timing(task, t[task].total)
def eigenmode(self, dim=3, N=3, degree=1, dt=0.125, T=2.0, solver='explicit', opt=2): self.series['np'] = op2.MPI.comm.size self.series['dim'] = dim self.series['size'] = N self.series['T'] = T self.series['solver'] = solver self.series['opt'] = opt self.series['degree'] = degree # If dt is supressed (<0) Infer it based on Courant number if dt < 0: # Courant number of 0.5: (dx*C)/Vp dt = 0.5 * (1.0 / N) / (2.0**(degree - 1)) self.series['dt'] = dt parameters["coffee"]["O3"] = opt >= 3 parameters["coffee"]["O4"] = opt >= 4 if dim == 2: eigen = Eigenmode2DLF4(N, degree, dt, solver=solver, output=False) u1, s1 = eigen.eigenmode2d(T=T) elif dim == 3: eigen = Eigenmode3DLF4(N, degree, dt, solver=solver, output=False) u1, s1 = eigen.eigenmode3d(T=T) for task, timer in get_timers(reset=True).items(): self.register_timing(task, timer.total) self.meta['dofs'] = op2.MPI.comm.allreduce(eigen.elastic.S.dof_count, op=mpi4py.MPI.SUM) try: with self.timed_region('compute_error'): u_error, s_error = eigen.eigenmode_error(u1, s1) self.meta['u_error'] = u_error self.meta['s_error'] = s_error except RuntimeError: print "WARNING: Couldn't establish error norm" self.meta['u_error'] = 'NaN' self.meta['s_error'] = 'NaN'
def forms(self, q=1, p=1, dim=3, max_nf=3, form='mass', dump_kernel=False): mesh = meshes[dim] A = assemble(eval(form)(q, p, dim, mesh)) for nf in range(max_nf + 1): f = eval(form)(q, p, dim, mesh, nf) with self.timed_region('nf %d' % nf): assemble(f, tensor=A) A.M if dump_kernel: for i, k in enumerate(f._kernels): with open( 'kernels/f_%s%d_q%d_p%d_dim%d_nf%d.c' % (form, i, q, p, dim, nf), 'w') as fil: fil.write(k[-1].code) t = get_timers(reset=True) task = 'Assemble cells' self.register_timing(task, t[task].total)
def poisson(self, size=32, degree=1, dim=3, preassemble=True, weak=False, print_norm=True, verbose=False, measure_overhead=False, pc='hypre', strong_threshold=0.75, agg_nl=2, max_levels=25): if weak: self.series['weak'] = size size = int((size * op2.MPI.comm.size)**(1. / dim)) self.meta['size'] = size else: self.series['size'] = size self.series['degree'] = degree self.meta['cells'] = 6 * size**dim self.meta['vertices'] = (size + 1)**dim params = { 'ksp_type': 'cg', 'pc_type': pc, 'pc_hypre_type': 'boomeramg', 'pc_hypre_boomeramg_strong_threshold': strong_threshold, 'pc_hypre_boomeramg_agg_nl': agg_nl, 'pc_hypre_boomeramg_max_levels': max_levels, 'ksp_rtol': 1e-6, 'ksp_atol': 1e-15 } if verbose: params['pc_hypre_boomeramg_print_statistics'] = True params['ksp_view'] = True params['ksp_monitor'] = True t_, mesh = self.make_mesh(size, dim) self.register_timing('mesh', t_) with self.timed_region('setup'): V = FunctionSpace(mesh, "Lagrange", degree) if verbose: print '[%d]' % op2.MPI.comm.rank, 'DOFs:', V.dof_dset.size # Define boundary condition bc = DirichletBC(V, 0.0, [3, 4]) # Define variational problem u = TrialFunction(V) v = TestFunction(V) f = Function(V).interpolate(Expression(initial[dim])) f.dat.data_ro a = inner(grad(u), grad(v)) * dx L = f * v * dx # Compute solution u = Function(V) if measure_overhead: print "Matrix assembly overhead:", self.lhs_ffc_overhead(a, bc) print "RHS assembly overhead:", self.rhs_ffc_overhead(L, bc) return if preassemble: with self.timed_region('matrix assembly'): A = assemble(a, bcs=bc) A.M self.meta['dofs'] = A.M.handle.sizes[0][1] with self.timed_region('rhs assembly'): b = assemble(L) bc.apply(b) b.dat.data_ro with self.timed_region('solve'): solve(A, u, b, solver_parameters=params) u.dat.data_ro else: with self.timed_region('solve'): solve(a == L, u, bcs=[bc], solver_parameters=params) u.dat.data_ro # Analytical solution a = Function(V).interpolate(Expression(analytical[dim])) l2 = sqrt(assemble(dot(u - a, u - a) * dx)) if print_norm and op2.MPI.comm.rank == 0: print 'L2 error norm:', l2 for task, timer in get_timers(reset=True).items(): self.register_timing(task, timer.total)
def wave(self, scale=1.0, lump_mass=True, N=100, save=False, weak=False, verbose=False, measure_overhead=False): if weak: self.series['weak'] = scale scale = round(scale/sqrt(op2.MPI.comm.size), 3) self.meta['scale'] = scale else: self.series['scale'] = scale self.meta['cells'] = cells[scale] self.meta['vertices'] = vertices[scale] if measure_overhead: mesh = UnitSquareMesh(1, 1) else: t_, mesh = self.make_mesh(scale) self.register_timing('mesh', t_) with self.timed_region('setup'): V = FunctionSpace(mesh, 'Lagrange', 1) total_dofs = np.zeros(1, dtype=int) op2.MPI.comm.Allreduce(np.array([V.dof_dset.size], dtype=int), total_dofs) self.meta['dofs'] = total_dofs[0] if verbose: print '[%d]' % op2.MPI.comm.rank, 'DOFs:', V.dof_dset.size p = Function(V) phi = Function(V, name="phi") u = TrialFunction(V) v = TestFunction(V) bcval = Constant(0.0) bc = DirichletBC(V, bcval, 1) if lump_mass: Ml = assemble(1.0 / assemble(v*dx)) dt = 0.001 * scale dtc = Constant(dt) t = 0.0 rhs = inner(grad(v), grad(phi)) * dx if save: outfile = File("vtk/firedrake_wave_%s.pvd" % scale) outfile << phi b = assemble(rhs) dphi = 0.5 * dtc * p dp = dtc * Ml * b if measure_overhead: repeats = 1000 tic('phi') for _ in range(repeats): phi -= dphi phi.dat.data_ro phi_overhead = N*toc('phi')/repeats print "phi overhead:", phi_overhead tic('p') for _ in range(repeats): bcval.assign(sin(2*pi*5*_*dt)) assemble(rhs, tensor=b) p += dp bc.apply(p) p.dat.data_ro p_overhead = N*toc('p')/repeats print "p overhead:", p_overhead return phi_overhead, p_overhead with self.timed_region('timestepping'): while t < N*dt: bcval.assign(sin(2*pi*5*t)) with self.timed_region('phi'): phi -= dphi phi.dat.data_ro with self.timed_region('p'): if lump_mass: assemble(rhs, tensor=b) p += dp bc.apply(p) p.dat.data_ro else: solve(u * v * dx == v * p * dx + dtc * rhs, p, bcs=bc, solver_parameters={'ksp_type': 'cg', 'pc_type': 'sor', 'pc_sor_symmetric': True}) with self.timed_region('phi'): phi -= dphi phi.dat.data_ro t += dt if save: outfile << phi for task, timer in get_timers(reset=True).items(): self.register_timing(task, timer.total)
def advection_diffusion(self, size=64, degree=1, dim=2, verbose=False, dt=0.0001, T=0.01, Tend=0.011, diffusivity=0.1, advection=True, diffusion=True, weak=False, print_norm=False, preassemble=True, pc='hypre', strong_threshold=0.25, agg_nl=2, max_levels=25): if weak: size = int((1e4*op2.MPI.comm.size)**(1./dim)) self.meta['size'] = size else: self.series['size'] = size self.meta['cells'] = (2 if dim == 2 else 6)*size**dim self.meta['dofs'] = (size+1)**dim adv_params = {'ksp_type': 'cg', 'pc_type': 'jacobi', 'ksp_rtol': 1e-6, 'ksp_atol': 1e-15} diff_params = {'ksp_type': 'cg', 'pc_type': pc, 'pc_hypre_type': 'boomeramg', 'pc_hypre_boomeramg_strong_threshold': strong_threshold, 'pc_hypre_boomeramg_agg_nl': agg_nl, 'pc_hypre_boomeramg_max_levels': max_levels, 'ksp_rtol': 1e-6, 'ksp_atol': 1e-15} if verbose: diff_params['pc_hypre_boomeramg_print_statistics'] = True diff_params['ksp_view'] = True diff_params['ksp_monitor'] = True adv_params['ksp_view'] = True adv_params['ksp_monitor'] = True t_, mesh = self.make_mesh(size, dim) self.register_timing('mesh', t_) with self.timed_region('setup'): V = FunctionSpace(mesh, "CG", degree) if verbose: print '[%d]' % op2.MPI.comm.rank, 'DOFs:', V.dof_dset.size U = VectorFunctionSpace(mesh, "CG", degree) p = TrialFunction(V) q = TestFunction(V) t = Function(V) u = Function(U) adv = p * q * dx adv_rhs = (q * t + dt * dot(grad(q), u) * t) * dx d = -dt * diffusivity * dot(grad(q), grad(p)) * dx diff = adv - 0.5 * d diff_rhs = action(adv + 0.5 * d, t) # Set initial condition: # A*(e^(-r^2/(4*D*T)) / (4*pi*D*T)) # with normalisation A = 0.1, diffusivity D = 0.1 r2 = "(pow(x[0]-(0.45+%(T)f), 2.0) + pow(x[1]-0.5, 2.0))" fexpr = "0.1 * (exp(-" + r2 + "/(0.4*%(T)f)) / (0.4*pi*%(T)f))" t.interpolate(Expression(fexpr % {'T': T})) u.interpolate(Expression((1.0, 0.0))) t.dat.data_ro u.dat.data_ro if preassemble: if advection: with self.timed_region('advection matrix'): A = assemble(adv) A.M if diffusion: with self.timed_region('diffusion matrix'): D = assemble(diff) D.M with self.timed_region('timestepping'): while T < Tend: # Advection if advection: if preassemble: with self.timed_region('advection RHS'): b = assemble(adv_rhs) b.dat.data_ro with self.timed_region('advection solve'): solve(A, t, b, solver_parameters=adv_params) else: solve(adv == adv_rhs, t, solver_parameters=adv_params) # Diffusion if diffusion: if preassemble: with self.timed_region('diffusion RHS'): b = assemble(diff_rhs) b.dat.data_ro with self.timed_region('diffusion solve'): solve(D, t, b, solver_parameters=diff_params) else: solve(diff == diff_rhs, t, solver_parameters=diff_params) T = T + dt # Analytical solution a = Function(V).interpolate(Expression(fexpr % {'T': T})) l2 = sqrt(assemble(dot(t - a, t - a) * dx)) if print_norm and op2.MPI.comm.rank == 0: print 'L2 error norm:', l2 for task, timer in get_timers(reset=True).items(): self.register_timing(task, timer.total)
def navier_stokes(self, scale=1.0, T=0.1, preassemble=True, save=False, weak=False, compute_norms=False): if weak: self.series['weak'] = scale scale = round(scale / sqrt(op2.MPI.comm.size), 3) self.meta['scale'] = scale else: self.series['scale'] = scale self.meta['cells'] = cells[scale] self.meta['vertices'] = vertices[scale] t_, mesh = self.make_mesh(scale) self.register_timing('mesh', t_) with self.timed_region('setup'): # Define function spaces (P2-P1) V = VectorFunctionSpace(mesh, "Lagrange", 2) Q = FunctionSpace(mesh, "Lagrange", 1) # Define trial and test functions u = TrialFunction(V) p = TrialFunction(Q) v = TestFunction(V) q = TestFunction(Q) # Set parameter values dt = 0.01 nu = 0.01 # Define time-dependent pressure boundary condition p_in = Constant(0.0) # Define boundary conditions noslip = DirichletBC(V, Constant((0.0, 0.0)), (1, 3, 4, 6)) inflow = DirichletBC(Q, p_in, 5) outflow = DirichletBC(Q, 0, 2) bcu = [noslip] bcp = [inflow, outflow] # Create functions u0 = Function(V) u1 = Function(V) p1 = Function(Q) # Define coefficients k = Constant(dt) f = Constant((0, 0)) # Tentative velocity step F1 = (1/k)*inner(u - u0, v)*dx + inner(grad(u0)*u0, v)*dx + \ nu*inner(grad(u), grad(v))*dx - inner(f, v)*dx a1 = lhs(F1) L1 = rhs(F1) # Pressure update a2 = inner(grad(p), grad(q)) * dx L2 = -(1 / k) * div(u1) * q * dx # Velocity update a3 = inner(u, v) * dx L3 = inner(u1, v) * dx - k * inner(grad(p1), v) * dx if preassemble: with self.timed_region('matrix assembly'): # Assemble matrices A1 = assemble(a1, bcs=bcu) A2 = assemble(a2, bcs=bcp) A3 = assemble(a3, bcs=bcu) A1.M A2.M A3.M if save: # Create files for storing solution ufile = File("vtk/firedrake_velocity.pvd") pfile = File("vtk/firedrake_pressure.pvd") vparams = { 'ksp_type': 'gmres', 'pc_type': 'bjacobi', 'sub_pc_type': 'ilu', 'ksp_rtol': 1e-6, 'ksp_atol': 1e-15 } pparams = { 'ksp_type': 'cg', 'pc_type': 'bjacobi', 'sub_pc_type': 'ilu', 'ksp_rtol': 1e-6, 'ksp_atol': 1e-15 } with self.timed_region('timestepping'): # Time-stepping t = dt while t < T + 1e-14: # Update pressure boundary condition p_in.assign(sin(3.0 * t)) # Compute tentative velocity step info("Computing tentative velocity") if preassemble: with self.timed_region('tentative velocity RHS'): b1 = assemble(L1) [bc.apply(A1, b1) for bc in bcu] b1.dat.data_ro with self.timed_region('tentative velocity solve'): solve(A1, u1, b1, solver_parameters=vparams) u1.dat.data_ro else: with self.timed_region('tentative velocity solve'): solve(a1 == L1, u1, bcs=bcu, solver_parameters=vparams) u1.dat.data_ro # Pressure correction info("Computing pressure correction") if preassemble: with self.timed_region('pressure correction RHS'): b2 = assemble(L2) [bc.apply(A2, b2) for bc in bcp] b2.dat.data_ro with self.timed_region('pressure correction solve'): solve(A2, p1, b2, solver_parameters=pparams) p1.dat.data_ro else: with self.timed_region('pressure correction solve'): solve(a2 == L2, p1, bcs=bcp, solver_parameters=pparams) p1.dat.data_ro # Velocity correction info("Computing velocity correction") if preassemble: with self.timed_region('velocity correction RHS'): b3 = assemble(L3) [bc.apply(A3, b3) for bc in bcu] b3.dat.data_ro with self.timed_region('velocity correction solve'): solve(A3, u1, b3, solver_parameters=vparams) u1.dat.data_ro else: with self.timed_region('velocity correction solve'): solve(a3 == L3, u1, bcs=bcu, solver_parameters=vparams) u1.dat.data_ro if save: # Save to file ufile << u1 pfile << p1 if compute_norms: nu1, np1 = norm(u1), norm(p1) if op2.MPI.comm.rank == 0: print t, 'u1:', nu1, 'p1:', np1 # Move to next time step u0.assign(u1) t += dt for task, timer in get_timers(reset=True).items(): self.register_timing(task, timer.total)
def test_reset_timers(self): tic('test_reset') toc('test_reset') reset_timers() assert get_timers().keys() == []
def test_create(self): tic('create') toc('create') assert 'create' in get_timers().keys()
def poisson(self, size=32, degree=1, dim=3, preassemble=True, weak=False, print_norm=True, verbose=False, measure_overhead=False, pc='hypre', strong_threshold=0.75, agg_nl=2, max_levels=25): if weak: self.series['weak'] = size size = int((size*op2.MPI.comm.size)**(1./dim)) self.meta['size'] = size else: self.series['size'] = size self.series['degree'] = degree self.meta['cells'] = 6*size**dim self.meta['vertices'] = (size+1)**dim params = {'ksp_type': 'cg', 'pc_type': pc, 'pc_hypre_type': 'boomeramg', 'pc_hypre_boomeramg_strong_threshold': strong_threshold, 'pc_hypre_boomeramg_agg_nl': agg_nl, 'pc_hypre_boomeramg_max_levels': max_levels, 'ksp_rtol': 1e-6, 'ksp_atol': 1e-15} if verbose: params['pc_hypre_boomeramg_print_statistics'] = True params['ksp_view'] = True params['ksp_monitor'] = True t_, mesh = self.make_mesh(size, dim) self.register_timing('mesh', t_) with self.timed_region('setup'): V = FunctionSpace(mesh, "Lagrange", degree) if verbose: print '[%d]' % op2.MPI.comm.rank, 'DOFs:', V.dof_dset.size # Define boundary condition bc = DirichletBC(V, 0.0, [3, 4]) # Define variational problem u = TrialFunction(V) v = TestFunction(V) f = Function(V).interpolate(Expression(initial[dim])) f.dat.data_ro a = inner(grad(u), grad(v))*dx L = f*v*dx # Compute solution u = Function(V) if measure_overhead: print "Matrix assembly overhead:", self.lhs_ffc_overhead(a, bc) print "RHS assembly overhead:", self.rhs_ffc_overhead(L, bc) return if preassemble: with self.timed_region('matrix assembly'): A = assemble(a, bcs=bc) A.M self.meta['dofs'] = A.M.handle.sizes[0][1] with self.timed_region('rhs assembly'): b = assemble(L) bc.apply(b) b.dat.data_ro with self.timed_region('solve'): solve(A, u, b, solver_parameters=params) u.dat.data_ro else: with self.timed_region('solve'): solve(a == L, u, bcs=[bc], solver_parameters=params) u.dat.data_ro # Analytical solution a = Function(V).interpolate(Expression(analytical[dim])) l2 = sqrt(assemble(dot(u - a, u - a) * dx)) if print_norm and op2.MPI.comm.rank == 0: print 'L2 error norm:', l2 for task, timer in get_timers(reset=True).items(): self.register_timing(task, timer.total)
def navier_stokes(self, scale=1.0, T=0.1, preassemble=True, save=False, weak=False, compute_norms=False): if weak: self.series['weak'] = scale scale = round(scale/sqrt(op2.MPI.comm.size), 3) self.meta['scale'] = scale else: self.series['scale'] = scale self.meta['cells'] = cells[scale] self.meta['vertices'] = vertices[scale] t_, mesh = self.make_mesh(scale) self.register_timing('mesh', t_) with self.timed_region('setup'): # Define function spaces (P2-P1) V = VectorFunctionSpace(mesh, "Lagrange", 2) Q = FunctionSpace(mesh, "Lagrange", 1) # Define trial and test functions u = TrialFunction(V) p = TrialFunction(Q) v = TestFunction(V) q = TestFunction(Q) # Set parameter values dt = 0.01 nu = 0.01 # Define time-dependent pressure boundary condition p_in = Constant(0.0) # Define boundary conditions noslip = DirichletBC(V, Constant((0.0, 0.0)), (1, 3, 4, 6)) inflow = DirichletBC(Q, p_in, 5) outflow = DirichletBC(Q, 0, 2) bcu = [noslip] bcp = [inflow, outflow] # Create functions u0 = Function(V) u1 = Function(V) p1 = Function(Q) # Define coefficients k = Constant(dt) f = Constant((0, 0)) # Tentative velocity step F1 = (1/k)*inner(u - u0, v)*dx + inner(grad(u0)*u0, v)*dx + \ nu*inner(grad(u), grad(v))*dx - inner(f, v)*dx a1 = lhs(F1) L1 = rhs(F1) # Pressure update a2 = inner(grad(p), grad(q))*dx L2 = -(1/k)*div(u1)*q*dx # Velocity update a3 = inner(u, v)*dx L3 = inner(u1, v)*dx - k*inner(grad(p1), v)*dx if preassemble: with self.timed_region('matrix assembly'): # Assemble matrices A1 = assemble(a1, bcs=bcu) A2 = assemble(a2, bcs=bcp) A3 = assemble(a3, bcs=bcu) A1.M A2.M A3.M if save: # Create files for storing solution ufile = File("vtk/firedrake_velocity.pvd") pfile = File("vtk/firedrake_pressure.pvd") vparams = {'ksp_type': 'gmres', 'pc_type': 'bjacobi', 'sub_pc_type': 'ilu', 'ksp_rtol': 1e-6, 'ksp_atol': 1e-15} pparams = {'ksp_type': 'cg', 'pc_type': 'bjacobi', 'sub_pc_type': 'ilu', 'ksp_rtol': 1e-6, 'ksp_atol': 1e-15} with self.timed_region('timestepping'): # Time-stepping t = dt while t < T + 1e-14: # Update pressure boundary condition p_in.assign(sin(3.0*t)) # Compute tentative velocity step info("Computing tentative velocity") if preassemble: with self.timed_region('tentative velocity RHS'): b1 = assemble(L1) [bc.apply(A1, b1) for bc in bcu] b1.dat.data_ro with self.timed_region('tentative velocity solve'): solve(A1, u1, b1, solver_parameters=vparams) u1.dat.data_ro else: with self.timed_region('tentative velocity solve'): solve(a1 == L1, u1, bcs=bcu, solver_parameters=vparams) u1.dat.data_ro # Pressure correction info("Computing pressure correction") if preassemble: with self.timed_region('pressure correction RHS'): b2 = assemble(L2) [bc.apply(A2, b2) for bc in bcp] b2.dat.data_ro with self.timed_region('pressure correction solve'): solve(A2, p1, b2, solver_parameters=pparams) p1.dat.data_ro else: with self.timed_region('pressure correction solve'): solve(a2 == L2, p1, bcs=bcp, solver_parameters=pparams) p1.dat.data_ro # Velocity correction info("Computing velocity correction") if preassemble: with self.timed_region('velocity correction RHS'): b3 = assemble(L3) [bc.apply(A3, b3) for bc in bcu] b3.dat.data_ro with self.timed_region('velocity correction solve'): solve(A3, u1, b3, solver_parameters=vparams) u1.dat.data_ro else: with self.timed_region('velocity correction solve'): solve(a3 == L3, u1, bcs=bcu, solver_parameters=vparams) u1.dat.data_ro if save: # Save to file ufile << u1 pfile << p1 if compute_norms: nu1, np1 = norm(u1), norm(p1) if op2.MPI.comm.rank == 0: print t, 'u1:', nu1, 'p1:', np1 # Move to next time step u0.assign(u1) t += dt for task, timer in get_timers(reset=True).items(): self.register_timing(task, timer.total)
def test_reset(self): tic("test_reset") toc("test_reset") reset() assert get_timers().keys() == []
def test_create(self): tic("create") toc("create") assert "create" in get_timers().keys()
def cahn_hilliard(self, size=96, steps=10, degree=1, pc='fieldsplit', inner_ksp='preonly', ksp='gmres', maxit=1, weak=False, measure_overhead=False, save=False, compute_norms=True, verbose=False): if weak: self.series['weak'] = size size = int((size*op2.MPI.comm.size)**0.5) self.meta['size'] = size else: self.series['size'] = size self.meta['cells'] = 2*size**2 self.meta['vertices'] = (size+1)**2 params = {'pc_type': pc, 'ksp_type': ksp, 'snes_rtol': 1e-9, 'snes_atol': 1e-10, 'snes_stol': 1e-16, 'snes_linesearch_type': 'basic', 'snes_linesearch_max_it': 1, 'ksp_rtol': 1e-6, 'ksp_atol': 1e-15, 'pc_fieldsplit_type': 'schur', 'pc_fieldsplit_schur_factorization_type': 'lower', 'pc_fieldsplit_schur_precondition': 'user', 'fieldsplit_0_ksp_type': inner_ksp, 'fieldsplit_0_ksp_max_it': maxit, 'fieldsplit_0_pc_type': 'hypre', 'fieldsplit_1_ksp_type': inner_ksp, 'fieldsplit_1_ksp_max_it': maxit, 'fieldsplit_1_pc_type': 'mat'} if verbose: params['ksp_monitor'] = True params['snes_view'] = True params['snes_monitor'] = True t_, mesh = self.make_mesh(size) self.register_timing('mesh', t_) with self.timed_region('setup'): V = FunctionSpace(mesh, "Lagrange", degree) ME = V*V # Define trial and test functions du = TrialFunction(ME) q, v = TestFunctions(ME) # Define functions u = Function(ME) # current solution u0 = Function(ME) # solution from previous converged step # Split mixed functions dc, dmu = split(du) c, mu = split(u) c0, mu0 = split(u0) with self.timed_region('initial condition'): # Create intial conditions and interpolate init_code = "A[0] = 0.63 + 0.02*(0.5 - (double)random()/RAND_MAX);" user_code = """int __rank; MPI_Comm_rank(MPI_COMM_WORLD, &__rank); srandom(2 + __rank);""" par_loop(init_code, direct, {'A': (u[0], WRITE)}, headers=["#include <stdlib.h>"], user_code=user_code) u.dat.data_ro # Compute the chemical potential df/dc c = variable(c) f = 100*c**2*(1-c)**2 dfdc = diff(f, c) mu_mid = (1.0-theta)*mu0 + theta*mu # Weak statement of the equations F0 = c*q*dx - c0*q*dx + dt*dot(grad(mu_mid), grad(q))*dx F1 = mu*v*dx - dfdc*v*dx - lmbda*dot(grad(c), grad(v))*dx F = F0 + F1 # Compute directional derivative about u in the direction of du (Jacobian) J = derivative(F, u, du) problem = NonlinearVariationalProblem(F, u, J=J) solver = NonlinearVariationalSolver(problem, solver_parameters=params) if pc in ['fieldsplit', 'ilu']: sigma = 100 # PC for the Schur complement solve trial = TrialFunction(V) test = TestFunction(V) mass = assemble(inner(trial, test)*dx).M.handle a = 1 c = (dt * lmbda)/(1+dt * sigma) hats = assemble(sqrt(a) * inner(trial, test)*dx + sqrt(c)*inner(grad(trial), grad(test))*dx).M.handle from firedrake.petsc import PETSc ksp_hats = PETSc.KSP() ksp_hats.create() ksp_hats.setOperators(hats) opts = PETSc.Options() opts['ksp_type'] = inner_ksp opts['ksp_max_it'] = maxit opts['pc_type'] = 'hypre' ksp_hats.setFromOptions() class SchurInv(object): def mult(self, mat, x, y): tmp1 = y.duplicate() tmp2 = y.duplicate() ksp_hats.solve(x, tmp1) mass.mult(tmp1, tmp2) ksp_hats.solve(tmp2, y) pc_schur = PETSc.Mat() pc_schur.createPython(mass.getSizes(), SchurInv()) pc_schur.setUp() pc = solver.snes.ksp.pc pc.setFieldSplitSchurPreType(PETSc.PC.SchurPreType.USER, pc_schur) # Output file if save: file = File("vtk/firedrake_cahn_hilliard_%d.pvd" % size) if measure_overhead: for _ in range(100): u0.assign(u) solver.solve() print "Assembly overhead:", timing("Assemble cells", total=False) print "Solver overhead:", timing("SNES solver execution", total=False) return with self.timed_region('timestepping'): for step in range(steps): with self.timed_region('timestep_%s' % step): u0.assign(u) solver.solve() if save: file << (u.split()[0], step) if compute_norms: nu = norm(u) if op2.MPI.comm.rank == 0: print step, 'L2(u):', nu for task, timer in get_timers(reset=True).items(): self.register_timing(task, timer.total)