def run_and_calculate_error(N, dt, tmax, polydeg_rho, last=False): """ Run Ocellaris and return L2 & H1 errors in the last time step """ say(N, dt, tmax, polydeg_rho) # Setup and run simulation sim = Simulation() sim.input.read_yaml('transport.inp') mesh_type = sim.input.get_value('mesh/type') if mesh_type == 'XML': # Create unstructured mesh with gmsh cmd1 = [ 'gmsh', '-string', 'lc = %f;' % (3.14 / N), '-o', 'disc_%d.msh' % N, '-2', '../convergence-variable-density-disk/disc.geo' ] cmd2 = ['dolfin-convert', 'disc_%d.msh' % N, 'disc.xml'] with open('/dev/null', 'w') as devnull: for cmd in (cmd1, cmd2): say(' '.join(cmd)) if ISROOT: subprocess.call(cmd, stdout=devnull, stderr=devnull) elif mesh_type == 'UnitDisc': sim.input.set_value('mesh/N', N // 2) else: sim.input.set_value('mesh/Nx', N) sim.input.set_value('mesh/Ny', N) sim.input.set_value('time/dt', dt) sim.input.set_value('time/tmax', tmax) sim.input.set_value('multiphase_solver/polynomial_degree_rho', polydeg_rho) sim.input.set_value('output/stdout_enabled', False) say('Running with multiphase solver %s ...' % (sim.input.get_value('multiphase_solver/type'))) t1 = time.time() setup_simulation(sim) run_simulation(sim) duration = time.time() - t1 say('DONE') # Interpolate the analytical solution to the same function space Vu = sim.data['Vu'] Vp = sim.data['Vp'] Vr = sim.data['Vrho'] polydeg_r = Vr.ufl_element().degree() vals = dict(t=sim.time, dt=sim.dt) rho_e = dolfin.Expression( sim.input.get_value('initial_conditions/rho_p/cpp_code'), degree=polydeg_r, **vals) rho_a = dolfin.project(rho_e, Vr) rho_e.t = 0 rho_0 = dolfin.project(rho_e, Vr) # Calculate L2 errors err_rho = calc_err(sim.data['rho'], rho_a) # Calculate H1 errors err_rho_H1 = calc_err(sim.data['rho'], rho_a, 'H1') mesh = sim.data['mesh'] n = dolfin.FacetNormal(mesh) reports = sim.reporting.timestep_xy_reports say('Num time steps:', sim.timestep) say('Num cells:', mesh.num_cells()) say('Co_max:', numpy.max(reports['Co'])) say('rho_min went from %r to %r' % (reports['min(rho)'][0], reports['min(rho)'][-1])) say('rho_max went from %r to %r' % (reports['max(rho)'][0], reports['max(rho)'][-1])) m0, m1 = reports['mass'][0], reports['mass'][-1] say('mass error %.3e (%.3e)' % (m1 - m0, (m1 - m0) / m0)) say('vel compat error %.3e' % dolfin.assemble(dolfin.dot(sim.data['u'], n) * dolfin.ds)) int_p = dolfin.assemble(sim.data['p'] * dolfin.dx) say('p*dx', int_p) div_u_Vp = abs( dolfin.project(dolfin.div(sim.data['u']), Vp).vector().get_local()).max() say('div(u)|Vp', div_u_Vp) div_u_Vu = abs( dolfin.project(dolfin.div(sim.data['u']), Vu).vector().get_local()).max() say('div(u)|Vu', div_u_Vu) Vdg0 = dolfin.FunctionSpace(mesh, "DG", 0) div_u_DG0 = abs( dolfin.project(dolfin.div(sim.data['u']), Vdg0).vector().get_local()).max() say('div(u)|DG0', div_u_DG0) Vdg1 = dolfin.FunctionSpace(mesh, "DG", 1) div_u_DG1 = abs( dolfin.project(dolfin.div(sim.data['u']), Vdg1).vector().get_local()).max() say('div(u)|DG1', div_u_DG1) isoparam = mesh.ufl_coordinate_element().degree() > 1 if last and (not isoparam or sim.input.get_value('mesh/type') == 'UnitDisc'): # Plot the results for fa, name in ((rho_a, 'rho'), ): fh = sim.data[name] if isoparam: # Bug in matplotlib plotting for isoparametric elements mesh2 = dolfin.UnitDiscMesh(dolfin.MPI.comm_world, N // 2, 1, 2) ue = fa.function_space().ufl_element() V2 = dolfin.FunctionSpace(mesh2, ue.family(), ue.degree()) fa2, fh2 = dolfin.Function(V2), dolfin.Function(V2) fa2.vector().set_local(fa.vector().get_local()) fh2.vector().set_local(fh.vector().get_local()) fa, fh = fa2, fh2 plot(fh - fa, name + ' diff', '%g_%g_%s_diff' % (N, dt, name)) plot(fa, name + ' analytical', '%g_%g_%s_analytical' % (N, dt, name)) plot(fh, name + ' numerical', '%g_%g_%s_numerical' % (N, dt, name)) plot(rho_0, name + ' initial', '%g_%g_%s_initial' % (N, dt, name)) hmin = mesh.hmin() return err_rho, err_rho_H1, hmin, dt, duration
def load_mesh(simulation): """ Get the mesh from the simulation input Returns the facet regions contained in the mesh data or None if these do not exist """ inp = simulation.input mesh_type = inp.get_value('mesh/type', required_type='string') mesh_facet_regions = None # For testing COMM_SELF may be specified comm_type = inp.get_value('mesh/mpi_comm', 'WORLD', required_type='string') verify_key('mesh/mpi_comm', comm_type, ('SELF', 'WORLD')) if comm_type == 'WORLD': comm = dolfin.MPI.comm_world else: comm = dolfin.MPI.comm_self if mesh_type == 'Rectangle': simulation.log.info('Creating rectangular mesh') startx = inp.get_value('mesh/startx', 0, 'float') starty = inp.get_value('mesh/starty', 0, 'float') start = dolfin.Point(startx, starty) endx = inp.get_value('mesh/endx', 1, 'float') endy = inp.get_value('mesh/endy', 1, 'float') end = dolfin.Point(endx, endy) Nx = inp.get_value('mesh/Nx', required_type='int') Ny = inp.get_value('mesh/Ny', required_type='int') diagonal = inp.get_value('mesh/diagonal', 'right', required_type='string') mesh = dolfin.RectangleMesh(comm, start, end, Nx, Ny, diagonal) elif mesh_type == 'Box': simulation.log.info('Creating box mesh') startx = inp.get_value('mesh/startx', 0, 'float') starty = inp.get_value('mesh/starty', 0, 'float') startz = inp.get_value('mesh/startz', 0, 'float') start = dolfin.Point(startx, starty, startz) endx = inp.get_value('mesh/endx', 1, 'float') endy = inp.get_value('mesh/endy', 1, 'float') endz = inp.get_value('mesh/endz', 1, 'float') end = dolfin.Point(endx, endy, endz) Nx = inp.get_value('mesh/Nx', required_type='int') Ny = inp.get_value('mesh/Ny', required_type='int') Nz = inp.get_value('mesh/Nz', required_type='int') mesh = dolfin.BoxMesh(comm, start, end, Nx, Ny, Nz) elif mesh_type == 'UnitDisc': simulation.log.info('Creating circular mesh') N = inp.get_value('mesh/N', required_type='int') degree = inp.get_value('mesh/degree', 1, required_type='int') gdim = inp.get_value('mesh/gdim', 2, required_type='int') mesh = dolfin.UnitDiscMesh(comm, N, degree, gdim) if degree > 1 and dolfin.parameters['form_compiler'][ 'representation'] != 'uflacs': simulation.log.warning( 'Using isoparametric elements without uflacs!') elif mesh_type == 'XML': simulation.log.info('Creating mesh from XML file') simulation.log.warning('(deprecated, please use meshio reader)') mesh_file = inp.get_value('mesh/mesh_file', required_type='string') facet_region_file = inp.get_value('mesh/facet_region_file', None, required_type='string') # Load the mesh from file pth = inp.get_input_file_path(mesh_file) mesh = dolfin.Mesh(comm, pth) # Load the facet regions if available if facet_region_file is not None: pth = inp.get_input_file_path(facet_region_file) mesh_facet_regions = dolfin.MeshFunction('size_t', mesh, pth) else: mesh_facet_regions = None elif mesh_type == 'XDMF': simulation.log.info('Creating mesh from XDMF file') simulation.log.warning('(deprecated, please use meshio reader)') mesh_file = inp.get_value('mesh/mesh_file', required_type='string') # Load the mesh from file pth = inp.get_input_file_path(mesh_file) mesh = dolfin.Mesh(comm) with dolfin.XDMFFile(comm, pth) as xdmf: xdmf.read(mesh, False) elif mesh_type == 'HDF5': simulation.log.info('Creating mesh from DOLFIN HDF5 file') h5_file_name = inp.get_value('mesh/mesh_file', required_type='string') with dolfin.HDF5File(comm, h5_file_name, 'r') as h5: # Read mesh mesh = dolfin.Mesh(comm) h5.read(mesh, '/mesh', False) # Read facet regions if h5.has_dataset('/mesh_facet_regions'): mesh_facet_regions = dolfin.FacetFunction('size_t', mesh) h5.read(mesh_facet_regions, '/mesh_facet_regions') else: mesh_facet_regions = None elif mesh_type == 'meshio': simulation.log.info('Creating mesh with meshio reader') file_name = inp.get_value('mesh/mesh_file', required_type='string') file_type = inp.get_value('mesh/meshio_type', None, required_type='string') sort_order = inp.get_value('mesh/sort_order', None, required_type='list(int)') if sort_order: simulation.log.info(' Ordering mesh elements by ' + ', then '.join('xyz'[i] for i in sort_order)) # Read mesh on rank 0 t1 = time.time() mesh = dolfin.Mesh(comm) if comm.rank == 0: # Read a mesh file by use of meshio physical_regions = load_meshio_mesh(mesh, file_name, file_type, sort_order) simulation.log.info(' Read mesh with %d cells in %.2f seconds' % (mesh.num_cells(), time.time() - t1)) else: physical_regions = None # Distribute the mesh if comm.size > 1: physical_regions = comm.bcast(physical_regions) t1 = time.time() simulation.log.info(' Distributing mesh to %d processors' % comm.size) build_distributed_mesh(mesh) simulation.log.info(' Distributed mesh in %.2f seconds' % (time.time() - t1)) else: ocellaris_error('Unknown mesh type', 'Mesh type %r is not supported' % mesh_type) # Optionally move the mesh (for simple grading etc) move = inp.get_value('mesh/move', None, required_type='list(string)') if move is not None: simulation.log.info(' Moving mesh') if len(move) != mesh.geometry().dim(): ocellaris_error( 'Mesh move not correct', 'Length of move field is %d while geometric dimension is %r' % (len(move), mesh.geometry().dim()), ) e_move = dolfin.Expression(move, degree=1) V_move = dolfin.VectorFunctionSpace(mesh, 'CG', 1) f_move = dolfin.interpolate(e_move, V_move) dolfin.ALE.move(mesh, f_move) mesh.bounding_box_tree().build(mesh) # Update the simulation simulation.set_mesh(mesh, mesh_facet_regions) # Load meshio facet regions if mesh_type == 'meshio' and physical_regions: mfr = dolfin.MeshFunction("size_t", mesh, mesh.topology().dim() - 1) conn_FV = simulation.data['connectivity_FV'] vcoords = mesh.coordinates() for ifacet in range(mfr.size()): facet_vertices = conn_FV(ifacet) key = sorted([tuple(vcoords[vidx]) for vidx in facet_vertices]) number = physical_regions.get(tuple(key), 0) mfr[ifacet] = number # Store the loaded regions simulation.data['mesh_facet_regions'] = mfr mesh_facet_regions = mfr # Optionally plot mesh right after loading (for debugging) if simulation.input.get_value('output/plot_mesh', False, 'bool'): prefix = simulation.input.get_value('output/prefix', '', 'string') pfile = prefix + '_mesh.xdmf' simulation.log.info( ' Plotting mesh with current MPI ranks to XDMF file %r' % pfile) V0 = dolfin.FunctionSpace(mesh, 'DG', 0) ranks = dolfin.Function(V0) ranks.vector().set_local(ranks.vector().get_local() * 0 + comm.rank) ranks.vector().apply('insert') ranks.rename('MPI_rank', 'MPI_rank') with dolfin.XDMFFile(comm, pfile) as xdmf: xdmf.write(ranks) # Optionally plot facet regions to file if simulation.input.get_value('output/plot_facet_regions', False, 'bool'): prefix = simulation.input.get_value('output/prefix', '', 'string') pfile = prefix + '_input_facet_regions.xdmf' simulation.log.info( ' Plotting input mesh facet regions to XDMF file %r' % pfile) if mesh_facet_regions is None: simulation.log.warning( 'Cannot plot mesh facet regions, no regions found!') else: with dolfin.XDMFFile(comm, pfile) as xdmf: xdmf.write(mesh_facet_regions)
def run_and_calculate_error(N, dt, tmax, polydeg_u, polydeg_p, nu, last=False): """ Run Ocellaris and return L2 & H1 errors in the last time step """ say(N, dt, tmax, polydeg_u, polydeg_p) # Setup and run simulation timingtypes = [ dolfin.TimingType.user, dolfin.TimingType.system, dolfin.TimingType.wall ] dolfin.timings(dolfin.TimingClear_clear, timingtypes) sim = Simulation() sim.input.read_yaml('disc.inp') mesh_type = sim.input.get_value('mesh/type') if mesh_type == 'XML': # Create unstructured mesh with gmsh cmd1 = [ 'gmsh', '-string', 'lc = %f;' % (3.14 / N), '-o', 'disc_%d.msh' % N, '-2', 'disc.geo' ] cmd2 = ['dolfin-convert', 'disc_%d.msh' % N, 'disc.xml'] with open('/dev/null', 'w') as devnull: for cmd in (cmd1, cmd2): say(' '.join(cmd)) subprocess.call(cmd, stdout=devnull, stderr=devnull) elif mesh_type == 'UnitDisc': sim.input.set_value('mesh/N', N // 2) else: sim.input.set_value('mesh/Nx', N) sim.input.set_value('mesh/Ny', N) sim.input.set_value('time/dt', dt) sim.input.set_value('time/tmax', tmax) sim.input.set_value('solver/polynomial_degree_velocity', polydeg_u) sim.input.set_value('solver/polynomial_degree_pressure', polydeg_p) sim.input.set_value('physical_properties/nu', nu) sim.input.set_value('output/stdout_enabled', False) say('Running with %s %s solver ...' % (sim.input.get_value('solver/type'), sim.input.get_value('solver/function_space_velocity'))) t1 = time.time() setup_simulation(sim) run_simulation(sim) duration = time.time() - t1 say('DONE') # Interpolate the analytical solution to the same function space Vu = sim.data['Vu'] Vp = sim.data['Vp'] Vr = sim.data['Vrho'] polydeg_r = Vr.ufl_element().degree() vals = dict(t=sim.time, dt=sim.dt, Q=sim.input.get_value('user_code/constants/Q')) rho_e = dolfin.Expression( sim.input.get_value('initial_conditions/rho_p/cpp_code'), degree=polydeg_r, **vals) u0e = dolfin.Expression( sim.input.get_value('initial_conditions/up0/cpp_code'), degree=polydeg_u, **vals) u1e = dolfin.Expression( sim.input.get_value('initial_conditions/up1/cpp_code'), degree=polydeg_u, **vals) pe = dolfin.Expression( sim.input.get_value('initial_conditions/p/cpp_code'), degree=polydeg_p, **vals) rho_a = dolfin.project(rho_e, Vr) u0a = dolfin.project(u0e, Vu) u1a = dolfin.project(u1e, Vu) pa = dolfin.project(pe, Vp) mesh = sim.data['mesh'] n = dolfin.FacetNormal(mesh) # Correct for possible non-zero average p int_p = dolfin.assemble(sim.data['p'] * dolfin.dx) int_pa = dolfin.assemble(pa * dolfin.dx) vol = dolfin.assemble(dolfin.Constant(1.0) * dolfin.dx(domain=mesh)) pa_avg = int_pa / vol sim.data['p'].vector()[:] += pa_avg # Calculate L2 errors err_rho = calc_err(sim.data['rho'], rho_a) err_u0 = calc_err(sim.data['u0'], u0a) err_u1 = calc_err(sim.data['u1'], u1a) err_p = calc_err(sim.data['p'], pa) # Calculate H1 errors err_rho_H1 = calc_err(sim.data['rho'], rho_a, 'H1') err_u0_H1 = calc_err(sim.data['u0'], u0a, 'H1') err_u1_H1 = calc_err(sim.data['u1'], u1a, 'H1') err_p_H1 = calc_err(sim.data['p'], pa, 'H1') reports = sim.reporting.timestep_xy_reports say('Num time steps:', sim.timestep) say('Num cells:', mesh.num_cells()) Co_max, Pe_max = numpy.max(reports['Co']), numpy.max(reports['Pe']) say('Co_max:', Co_max) say('Pe_max:', Pe_max) say('rho_min went from %r to %r' % (reports['min(rho)'][0], reports['min(rho)'][-1])) say('rho_max went from %r to %r' % (reports['max(rho)'][0], reports['max(rho)'][-1])) m0, m1 = reports['mass'][0], reports['mass'][-1] say('mass error %.3e (%.3e)' % (m1 - m0, (m1 - m0) / m0)) say('vel repr error %.3e' % dolfin.assemble(dolfin.dot(sim.data['u'], n) * dolfin.ds)) say('p*dx', int_p) div_u_Vp = abs( dolfin.project(dolfin.div(sim.data['u']), Vp).vector().get_local()).max() say('div(u)|Vp', div_u_Vp) div_u_Vu = abs( dolfin.project(dolfin.div(sim.data['u']), Vu).vector().get_local()).max() say('div(u)|Vu', div_u_Vu) Vdg0 = dolfin.FunctionSpace(mesh, "DG", 0) div_u_DG0 = abs( dolfin.project(dolfin.div(sim.data['u']), Vdg0).vector().get_local()).max() say('div(u)|DG0', div_u_DG0) Vdg1 = dolfin.FunctionSpace(mesh, "DG", 1) div_u_DG1 = abs( dolfin.project(dolfin.div(sim.data['u']), Vdg1).vector().get_local()).max() say('div(u)|DG1', div_u_DG1) isoparam = mesh.ufl_coordinate_element().degree() > 1 allways_plot = True if (last or allways_plot) and ( not isoparam or sim.input.get_value('mesh/type') == 'UnitDisc'): # Plot the results for fa, name in ((u0a, 'u0'), (u1a, 'u1'), (pa, 'p'), (rho_a, 'rho')): fh = sim.data[name] if isoparam: # Bug in matplotlib plotting for isoparametric elements mesh2 = dolfin.UnitDiscMesh(dolfin.MPI.comm_world, N // 2, 1, 2) ue = fa.function_space().ufl_element() V2 = dolfin.FunctionSpace(mesh2, ue.family(), ue.degree()) fa2, fh2 = dolfin.Function(V2), dolfin.Function(V2) fa2.vector().set_local(fa.vector().get_local()) fh2.vector().set_local(fh.vector().get_local()) fa, fh = fa2, fh2 discr = '' # '%g_%g_' % (N, dt) plot(fa, name + ' analytical', '%s%s_1analytical' % (discr, name)) plot(fh, name + ' numerical', '%s%s_2numerical' % (discr, name)) plot(fh - fa, name + ' diff', '%s%s_3diff' % (discr, name)) hmin = mesh.hmin() return err_rho, err_u0, err_u1, err_p, err_rho_H1, err_u0_H1, err_u1_H1, err_p_H1, hmin, dt, Co_max, Pe_max, duration