def test_local_assembler_on_facet_integrals(): mesh = UnitSquareMesh(MPI.comm_world, 4, 4, 'right') Vdgt = FunctionSpace(mesh, 'DGT', 1) v = TestFunction(Vdgt) x = SpatialCoordinate(mesh) w = (1.0 + x[0] ** 2.2 + 1. / (0.1 + x[1] ** 3)) * 300 # Define form that tests that the correct + and - values are used L = w('-') * v('+') * dS # Compile form. This is collective L = Form(L) # Get global cell 10. This will return a cell only on one of the # processes c = get_cell_at(mesh, 5 / 12, 1 / 3, 0) if c: # Assemble locally on the selected cell b_e = assemble_local(L, c) # Compare to values from phonyx (fully independent # implementation) b_phonyx = numpy.array([266.55210302, 266.55210302, 365.49000122, 365.49000122, 0.0, 0.0]) error = sum((b_e - b_phonyx)**2)**0.5 error = float(error) # MPI.max does strange things to numpy.float64 else: error = 0.0 error = MPI.max(MPI.comm_world, float(error)) assert error < 1e-8
def _adaptive_mesh_refinement(dx, phi, mu, sigma, omega, conv, voltages): from dolfin import cells, refine eta = _error_estimator(dx, phi, mu, sigma, omega, conv, voltages) mesh = phi.function_space().mesh() level = 0 TOL = 1.0e-4 E = sum([e * e for e in eta]) E = sqrt(MPI.sum(E)) info('Level %d: E = %g (TOL = %g)' % (level, E, TOL)) # Mark cells for refinement REFINE_RATIO = 0.5 cell_markers = MeshFunction('bool', mesh, mesh.topology().dim()) eta_0 = sorted(eta, reverse=True)[int(len(eta) * REFINE_RATIO)] eta_0 = MPI.max(eta_0) for c in cells(mesh): cell_markers[c] = eta[c.index()] > eta_0 # Refine mesh mesh = refine(mesh, cell_markers) # Plot mesh plot(mesh) interactive() exit() ## Compute error indicators #K = array([c.volume() for c in cells(mesh)]) #R = array([abs(source([c.midpoint().x(), c.midpoint().y()])) for c in cells(mesh)]) #gam = h*R*sqrt(K) return
def print_min_max(u, title, color='97', cls=None): """ Print the minimum and maximum values of ``u``, a Vector, Function, or array. :param u: the variable to print the min and max of :param title: the name of the function to print :param color: the color of printed text :type u: :class:`~dolfin.GenericVector`, :class:`~numpy.ndarray`, :class:`~dolfin.Function`, int, float, :class:`~dolfin.Constant` :type title: string :type color: string """ if isinstance(u, GenericVector): uMin = MPI.min(mpi_comm_world(), u.min()) uMax = MPI.max(mpi_comm_world(), u.max()) s = title + ' <min, max> : <%.3e, %.3e>' % (uMin, uMax) print_text(s, color, cls=cls) elif isinstance(u, indexed.Indexed): dim = u.value_rank() + 1 for i in range(u.value_rank()): uMin = u.vector().array()[i : u.vector().size() : dim].min() uMax = u.vector().array()[i : u.vector().size() : dim].max() s = title + '_%i <min, max> : <%.3e, %.3e>' % (i, uMin, uMax) print_text(s, color, cls=cls) elif isinstance(u, ndarray): if u.dtype != float64: u = u.astype(float64) uMin = MPI.min(mpi_comm_world(), u.min()) uMax = MPI.max(mpi_comm_world(), u.max()) s = title + ' <min, max> : <%.3e, %.3e>' % (uMin, uMax) print_text(s, color, cls=cls) elif isinstance(u, Function):# \ # or isinstance(u, dolfin.functions.function.Function): uMin = MPI.min(mpi_comm_world(), u.vector().min()) uMax = MPI.max(mpi_comm_world(), u.vector().max()) s = title + ' <min, max> : <%.3e, %.3e>' % (uMin, uMax) print_text(s, color, cls=cls) elif isinstance(u, int) or isinstance(u, float): s = title + ' : %.3e' % u print_text(s, color, cls=cls) elif isinstance(u, Constant): s = title + ' : %.3e' % u(0) print_text(s, color, cls=cls) else: er = title + ": print_min_max function requires a Vector, Function" \ + ", array, int or float, not %s." % type(u) print_text(er, 'red', 1)
def error(self, ys1, ys2) : errors = [] for i in range(self.num_unknowns): err = MPI.max(mpi_comm_world(), (abs(ys2[i] - ys1[i])).max()) errors.append(err) return errors
def _check_space_order(problem, method): mesh_generator, solution, weak_F = problem() # Translate data into FEniCS expressions. fenics_sol = Expression(smp.prining.ccode(solution['value']), degree=solution['degree'], t=0.0 ) # Create initial solution. theta0 = Expression(fenics_sol.cppcode, degree=solution['degree'], t=0.0, cell=triangle ) # Estimate the error component in space. # Leave out too rough discretizations to avoid showing spurious errors. N = [2 ** k for k in range(2, 8)] dt = 1.0e-8 Err = [] H = [] for n in N: mesh = mesh_generator(n) H.append(MPI.max(mesh.hmax())) V = FunctionSpace(mesh, 'CG', 3) # Create boundary conditions. fenics_sol.t = dt #bcs = DirichletBC(V, fenics_sol, 'on_boundary') # Create initial state. theta_approx = method(V, weak_F, theta0, 0.0, dt, bcs=[solution], tol=1.0e-12, verbose=True ) # Compute the error. fenics_sol.t = dt Err.append(errornorm(fenics_sol, theta_approx) / norm(fenics_sol, mesh=mesh) ) print('n: %d error: %e' % (n, Err[-1])) from matplotlib import pyplot as pp # Compare with order 1, 2, 3 curves. for o in [2, 3, 4]: pp.loglog([H[0], H[-1]], [Err[0], Err[0] * (H[-1] / H[0]) ** o], color='0.5' ) # Finally, the actual data. pp.loglog(H, Err, '-o') pp.xlabel('h_max') pp.ylabel('||u-u_h|| / ||u||') pp.show() return
def compute(self, get): u = get(self.valuename) if u is None: return None if isinstance(u, Function): if len(u.vector().array()) > 0: maximum = numpy.max(u.vector().array()) else: maximum = -1e16 return MPI.max(mpi_comm_world(), maximum) #return MPI.max(mpi_comm_world(), numpy.max(u.vector().array())) elif hasattr(u, "__len__"): return MPI.max(mpi_comm_world(), max(u)) elif isinstance(u, (float,int,long)): return MPI.max(mpi_comm_world(), u) else: raise Exception("Unable to take max of %s" %str(u))
def test_interpolation_rank0(V): @function.expression.numba_eval def expr_eval(values, x, cell_idx): values[:, 0] = 1.0 f = Expression(expr_eval, shape=()) w = interpolate(f, V) x = w.vector() assert MPI.max(MPI.comm_world, abs(x.get_local()).max()) == 1 assert MPI.min(MPI.comm_world, abs(x.get_local()).min()) == 1
def _x_cell_id(self): x = self.x mesh = self.probes._mesh val = -1 index = mesh.bounding_box_tree().compute_first_entity_collision(x) if (0 <= index < mesh.num_cells()): val = index return MPI.max(dolfin.mpi_comm_world(), val)
def _compute_errors(problem, mesh_sizes): mesh_generator, solution, f, cell_type = problem() max_degree = 20 if solution['degree'] > max_degree: warnings.warn(('Expression degree (%r) > maximum degree (%d). ' 'Truncating.') % (solution['degree'], max_degree) ) degree = 20 else: degree = solution['degree'] sol = Expression((smp.printing.ccode(solution['value'][0]), smp.printing.ccode(solution['value'][1])), t=0.0, degree=degree, cell=cell_type ) errors = numpy.empty(len(mesh_sizes)) hmax = numpy.empty(len(mesh_sizes)) for k, mesh_size in enumerate(mesh_sizes): mesh, dx, ds = mesh_generator(mesh_size) hmax[k] = MPI.max(mpi_comm_world(), mesh.hmax()) V = FunctionSpace(mesh, 'CG', 1) # TODO don't hardcode Mu, Sigma, ... phi_approx = mcyl.solve_maxwell(V, dx, Mu={0: 1.0}, Sigma={0: 1.0}, omega=1.0, f_list=[{0: f['value']}], convections={}, tol=1.0e-12, bcs=None, compute_residuals=False, verbose=False ) #plot(sol0, mesh=mesh, title='sol') #plot(phi_approx[0][0], title='approx') ##plot(fenics_sol - theta_approx, title='diff') #interactive() #exit() # errors[k] = errornorm(sol, phi_approx[0]) # Compute the numerical order of convergence. order = numpy.empty(len(errors) - 1) for i in range(len(errors) - 1): order[i] = numpy.log(errors[i + 1] / errors[i]) \ / numpy.log(hmax[i + 1] / hmax[i]) return errors, order, hmax
def _check_spatial_order(problem, method): mesh_generator, solution, weak_F = problem() # Translate data into FEniCS expressions. fenics_sol = Expression(sympy.printing.ccode(solution['value']), degree=solution['degree'], t=0.0) # Create initial solution. theta0 = Expression(fenics_sol.cppcode, degree=solution['degree'], t=0.0, cell=triangle) # Estimate the error component in space. # Leave out too rough discretizations to avoid showing spurious errors. N = [2**k for k in range(2, 8)] dt = 1.0e-8 Err = [] H = [] for n in N: mesh = mesh_generator(n) H.append(MPI.max(mesh.hmax())) V = FunctionSpace(mesh, 'CG', 5) # Create boundary conditions. fenics_sol.t = dt # bcs = DirichletBC(V, fenics_sol, 'on_boundary') # Create initial state. theta_approx = method(V, weak_F, theta0, 0.0, dt, bcs=[solution], tol=1.0e-12, verbose=True) # Compute the error. fenics_sol.t = dt Err.append( errornorm(fenics_sol, theta_approx) / norm(fenics_sol, mesh=mesh)) print('n: %d error: %e' % (n, Err[-1])) # Plot order curves for comparison. for order in [2, 3, 4]: plt.loglog([H[0], H[-1]], [Err[0], Err[0] * (H[-1] / H[0])**order], color='0.5') # Finally, the actual data. plt.loglog(H, Err, '-o') plt.xlabel('h_max') plt.ylabel('||u-u_h|| / ||u||') plt.show() return
def print_min_max(u, title, color='97'): r""" Print the minimum and maximum values of ``u``, a Vector, Function, or array. :param u: the variable to print the min and max of :param title: the name of the function to print :param color: the color of printed text :type u: :class:`~fenics.GenericVector`, :class:`~numpy.ndarray`, :class:`~fenics.Function`, int, float, :class:`~fenics.Constant` :type title: string :type color: string """ if isinstance(u, GenericVector): uMin = MPI.min(MPI.comm_world, u.min()) uMax = MPI.max(MPI.comm_world, u.max()) s = title + ' <min, max> : <%.3e, %.3e>' % (uMin, uMax) print_text(s, color) elif isinstance(u, np.ndarray): if u.dtype != np.float64: u = u.astype(float64) uMin = MPI.min(MPI.comm_world, u.min()) uMax = MPI.max(MPI.comm_world, u.max()) s = title + ' <min, max> : <%.3e, %.3e>' % (uMin, uMax) print_text(s, color) elif isinstance(u, Function): # \ # or isinstance(u, dolfin.functions.function.Function): uMin = MPI.min(MPI.comm_world, u.vector().min()) uMax = MPI.max(MPI.comm_world, u.vector().max()) s = title + ' <min, max> : <%.3e, %.3e>' % (uMin, uMax) print_text(s, color) elif isinstance(u, int) or isinstance(u, float): s = title + ' : %.3e' % u print_text(s, color) elif isinstance(u, Constant): s = title + ' : %.3e' % u(0) print_text(s, color) else: er = title + ": print_min_max function requires a Vector, Function" \ + ", array, int or float, not %s." % type(u) print_text(er, 'red', 1)
def _compute_errors(problem, mesh_sizes): mesh_generator, solution, f, cell_type = problem() if solution["degree"] > MAX_DEGREE: warnings.warn( "Expression degree ({}) > maximum degree ({}). Truncating.".format( solution["degree"], MAX_DEGREE)) degree = MAX_DEGREE else: degree = solution["degree"] sol = Expression( (helpers.ccode( solution["value"][0]), helpers.ccode(solution["value"][1])), t=0.0, degree=degree, cell=cell_type, ) errors = numpy.empty(len(mesh_sizes)) hmax = numpy.empty(len(mesh_sizes)) for k, mesh_size in enumerate(mesh_sizes): mesh, dx, _ = mesh_generator(mesh_size) hmax[k] = MPI.max(mpi_comm_world(), mesh.hmax()) V = FunctionSpace(mesh, "CG", 1) # TODO don't hardcode Mu, Sigma, ... phi_approx = maxwell.solve( V, dx, Mu={0: 1.0}, Sigma={0: 1.0}, omega=1.0, f_list=[{ 0: f["value"] }], f_degree=f["degree"], convections={}, tol=1.0e-12, bcs=None, verbose=False, ) # plot(sol0, mesh=mesh, title='sol') # plot(phi_approx[0][0], title='approx') # #plot(fenics_sol - theta_approx, title='diff') # interactive() # exit() # errors[k] = errornorm(sol, phi_approx[0]) return errors, hmax
def get_cell_at(mesh, x, y, z, eps=1e-3): """Return the cell with the given midpoint or None if not found. The function also checks that the cell is found on one of the processes when running in parallel to avoid that the above tests always suceed if the cell is not found on any of the processes. """ found = None for cell in Cells(mesh): mp = cell.midpoint().array() if abs(mp[0] - x) + abs(mp[1] - y) + abs(mp[2] - z) < eps: found = cell break # Make sure this cell is on at least one of the parallel processes marker = 1 if found is not None else 0 assert MPI.max(MPI.comm_world, marker) == 1 return found
def _compute_errors(problem, mesh_sizes, stabilization): mesh_generator, solution, f, cell_type, kappa, rho, cp, conv = problem() if solution["degree"] > MAX_DEGREE: warnings.warn( "Expression degree ({}) > maximum degree ({}). Truncating.".format( solution["degree"], MAX_DEGREE ) ) degree = MAX_DEGREE else: degree = solution["degree"] sol = Expression( helpers.ccode(solution["value"]), t=0.0, degree=degree, cell=cell_type ) errors = numpy.empty(len(mesh_sizes)) hmax = numpy.empty(len(mesh_sizes)) for k, mesh_size in enumerate(mesh_sizes): mesh = mesh_generator(mesh_size) hmax[k] = MPI.max(mpi_comm_world(), mesh.hmax()) Q = FunctionSpace(mesh, "CG", 1) prob = heat.Heat( Q, kappa=kappa, rho=rho, cp=cp, convection=conv, source=f["value"], dirichlet_bcs=[DirichletBC(Q, 0.0, "on_boundary")], stabilization=stabilization, ) phi_approx = prob.solve_stationary() errors[k] = errornorm(sol, phi_approx) return errors, hmax
def _compute_errors(problem, mesh_sizes, stabilization): mesh_generator, solution, f, cell_type, kappa, rho, cp, conv = problem() if solution["degree"] > MAX_DEGREE: warnings.warn( "Expression degree ({}) > maximum degree ({}). Truncating.".format( solution["degree"], MAX_DEGREE)) degree = MAX_DEGREE else: degree = solution["degree"] sol = Expression(helpers.ccode(solution["value"]), t=0.0, degree=degree, cell=cell_type) errors = numpy.empty(len(mesh_sizes)) hmax = numpy.empty(len(mesh_sizes)) for k, mesh_size in enumerate(mesh_sizes): mesh = mesh_generator(mesh_size) hmax[k] = MPI.max(mpi_comm_world(), mesh.hmax()) Q = FunctionSpace(mesh, "CG", 1) prob = heat.Heat( Q, kappa=kappa, rho=rho, cp=cp, convection=conv, source=f["value"], dirichlet_bcs=[DirichletBC(Q, 0.0, "on_boundary")], stabilization=stabilization, ) phi_approx = prob.solve_stationary() errors[k] = errornorm(sol, phi_approx) return errors, hmax
def test_local_assembler_on_facet_integrals2(): mesh = UnitSquareMesh(MPI.comm_world, 4, 4) Vu = VectorFunctionSpace(mesh, 'DG', 1) Vv = FunctionSpace(mesh, 'DGT', 1) u = TrialFunction(Vu) v = TestFunction(Vv) n = FacetNormal(mesh) # Define form a = dot(u, n) * v * ds for R in '+-': a += dot(u(R), n(R)) * v(R) * dS # Compile form. This is collective a = Form(a) # Get global cell 0. This will return a cell only on one of the # processes c = get_cell_at(mesh, 1 / 6, 1 / 12, 0) if c: A_e = assemble_local(a, c) A_correct = numpy.array([[0, 1 / 12, 1 / 24, 0, 0, 0], [0, 1 / 24, 1 / 12, 0, 0, 0], [-1 / 12, 0, -1 / 24, 1 / 12, 0, 1 / 24], [-1 / 24, 0, -1 / 12, 1 / 24, 0, 1 / 12], [0, 0, 0, -1 / 12, -1 / 24, 0], [0, 0, 0, -1 / 24, -1 / 12, 0]]) error = ((A_e - A_correct)**2).sum()**0.5 error = float(error) # MPI.max does strange things to numpy.float64 else: error = 0.0 error = MPI.max(MPI.comm_world, float(error)) assert error < 1e-16
def test_interpolation_jit_rank0(V): f = Expression("1.0", degree=0) w = interpolate(f, V) x = w.vector() assert MPI.max(MPI.comm_world, abs(x.get_local()).max()) == 1 assert MPI.min(MPI.comm_world, abs(x.get_local()).min()) == 1
def before_first_compute(self, get): u = get(self.valuename) if isinstance(u, Function): if LooseVersion(dolfin_version()) > LooseVersion("1.6.0"): rank = len(u.ufl_shape) else: rank = u.rank() if rank == 0: self.f = Function(u.function_space()) elif rank >= 1: # Assume all subpaces are equal V = u.function_space().extract_sub_space([0]).collapse() mesh = V.mesh() el = V.ufl_element() self.f = Function(V) # Find out if we can operate directly on vectors, or if we have to use a projection # We can operate on vectors if all sub-dofmaps are ordered the same way # For simplicity, this is only tested for CG- or DG0-spaces # (this might always be true for these spaces, but better to be safe than sorry ) self.use_project = True if el.family() == "Lagrange" or (el.family() == "Discontinuous Lagrange" and el.degree() == 0): #dm = u.function_space().dofmap() dm0 = V.dofmap() self.use_project = False for i in xrange(u.function_space().num_sub_spaces()): Vi = u.function_space().extract_sub_space( [i]).collapse() dmi = Vi.dofmap() try: # For 1.6.0+ and newer diff = Vi.tabulate_dof_coordinates( ) - V.tabulate_dof_coordinates() except: # For 1.6.0 and older diff = dmi.tabulate_all_coordinates( mesh) - dm0.tabulate_all_coordinates(mesh) if len(diff) > 0: max_diff = max(abs(diff)) else: max_diff = 0.0 max_diff = MPI.max(mpi_comm_world(), max_diff) if max_diff > 1e-12: self.use_project = True break self.assigner = FunctionAssigner( [V] * u.function_space().num_sub_spaces(), u.function_space()) self.subfuncs = [ Function(V) for _ in range(u.function_space().num_sub_spaces()) ] # IF we have to use a projection, build projection matrix only once if self.use_project: self.v = TestFunction(V) M = assemble(inner(self.v, TrialFunction(V)) * dx) self.projection = KrylovSolver("cg", "default") self.projection.set_operator(M) elif isinstance(u, Iterable) and all( isinstance(_u, Number) for _u in u): pass elif isinstance(u, Number): pass else: # Don't know how to handle object cbc_warning( "Don't know how to calculate magnitude of object of type %s." % type(u))
def default_error(self, x1, x2) : dif_max = MPI.max(mpi_comm_world(), abs(x1 - x2).max()) return dif_max
def create_submesh(mesh, markers, marker): "This function allows for a SubMesh-equivalent to be created in parallel" # Build mesh submesh = Mesh() mesh_editor = MeshEditor() mesh_editor.open(submesh, mesh.ufl_cell().cellname(), mesh.ufl_cell().topological_dimension(), mesh.ufl_cell().geometric_dimension()) # Return empty mesh if no matching markers if MPI.sum(mpi_comm_world(), int(marker in markers.array())) == 0: cbc_warning( "Unable to find matching markers in meshfunction. Submesh is empty." ) mesh_editor.close() return submesh base_cell_indices = np.where(markers.array() == marker)[0] base_cells = mesh.cells()[base_cell_indices] base_vertex_indices = np.unique(base_cells.flatten()) base_global_vertex_indices = sorted( [mesh.topology().global_indices(0)[vi] for vi in base_vertex_indices]) gi = mesh.topology().global_indices(0) shared_local_indices = set(base_vertex_indices).intersection( set(mesh.topology().shared_entities(0).keys())) shared_global_indices = [gi[vi] for vi in shared_local_indices] unshared_global_indices = list( set(base_global_vertex_indices) - set(shared_global_indices)) unshared_vertices_dist = distribution(len(unshared_global_indices)) # Number unshared vertices on separate process idx = sum(unshared_vertices_dist[:MPI.rank(mpi_comm_world())]) base_to_sub_global_indices = {} for gi in unshared_global_indices: base_to_sub_global_indices[gi] = idx idx += 1 # Gather all shared process on process 0 and assign global index all_shared_global_indices = gather(shared_global_indices, on_process=0, flatten=True) all_shared_global_indices = np.unique(all_shared_global_indices) shared_base_to_sub_global_indices = {} idx = int( MPI.max(mpi_comm_world(), float(max(base_to_sub_global_indices.values() + [-1e16]))) + 1) if MPI.rank(mpi_comm_world()) == 0: for gi in all_shared_global_indices: shared_base_to_sub_global_indices[int(gi)] = idx idx += 1 # Broadcast global numbering of all shared vertices shared_base_to_sub_global_indices = dict( zip(broadcast(shared_base_to_sub_global_indices.keys(), 0), broadcast(shared_base_to_sub_global_indices.values(), 0))) # Join shared and unshared numbering in one dict base_to_sub_global_indices = dict( base_to_sub_global_indices.items() + shared_base_to_sub_global_indices.items()) # Create mapping of local indices base_to_sub_local_indices = dict( zip(base_vertex_indices, range(len(base_vertex_indices)))) # Define sub-cells sub_cells = [None] * len(base_cells) for i, c in enumerate(base_cells): sub_cells[i] = [base_to_sub_local_indices[j] for j in c] # Store vertices as sub_vertices[local_index] = (global_index, coordinates) sub_vertices = {} for base_local, sub_local in base_to_sub_local_indices.items(): sub_vertices[sub_local] = (base_to_sub_global_indices[ mesh.topology().global_indices(0)[base_local]], mesh.coordinates()[base_local]) ## Done with base mesh # Distribute meshdata on (if any) empty processes sub_cells, sub_vertices = distribute_meshdata(sub_cells, sub_vertices) global_cell_distribution = distribution(len(sub_cells)) #global_vertex_distribution = distribution(len(sub_vertices)) global_num_cells = MPI.sum(mpi_comm_world(), len(sub_cells)) global_num_vertices = sum(unshared_vertices_dist) + MPI.sum( mpi_comm_world(), len(all_shared_global_indices)) mesh_editor.init_vertices(len(sub_vertices)) #mesh_editor.init_cells(len(sub_cells)) mesh_editor.init_cells_global(len(sub_cells), global_num_cells) global_index_start = sum( global_cell_distribution[:MPI.rank(mesh.mpi_comm())]) for index, cell in enumerate(sub_cells): if LooseVersion(dolfin_version()) >= LooseVersion("1.6.0"): mesh_editor.add_cell(index, *cell) else: mesh_editor.add_cell(int(index), global_index_start + index, np.array(cell, dtype=np.uintp)) for local_index, (global_index, coordinates) in sub_vertices.items(): #print coordinates mesh_editor.add_vertex_global(int(local_index), int(global_index), coordinates) mesh_editor.close() submesh.topology().init(0, len(sub_vertices), global_num_vertices) submesh.topology().init(mesh.ufl_cell().topological_dimension(), len(sub_cells), global_num_cells) # FIXME: Set up shared entities # What damage does this do? submesh.topology().shared_entities(0)[0] = [] # The code below sets up shared vertices, but lacks shared facets. # It is considered incomplete, and therefore commented out ''' #submesh.topology().shared_entities(0)[0] = [] from dolfin import compile_extension_module cpp_code = """ void set_shared_entities(Mesh& mesh, std::size_t idx, const Array<std::size_t>& other_processes) { std::set<unsigned int> set_other_processes; for (std::size_t i=0; i<other_processes.size(); i++) { set_other_processes.insert(other_processes[i]); //std::cout << idx << " --> " << other_processes[i] << std::endl; } //std::cout << idx << " --> " << set_other_processes[0] << std::endl; mesh.topology().shared_entities(0)[idx] = set_other_processes; } """ set_shared_entities = compile_extension_module(cpp_code).set_shared_entities base_se = mesh.topology().shared_entities(0) se = submesh.topology().shared_entities(0) for li in shared_local_indices: arr = np.array(base_se[li], dtype=np.uintp) sub_li = base_to_sub_local_indices[li] set_shared_entities(submesh, base_to_sub_local_indices[li], arr) ''' return submesh
def distribute_meshdata(cells, vertices): """Because dolfin does not support a distributed mesh that is empty on some processes, we move a single cell from the process with the largest mesh to all processes with empty meshes.""" global_cell_distribution = distribution(len(cells)) x_per_v = 0 v_per_cell = 0 if len(vertices.values()) > 0: x_per_v = len(vertices.values()[0][1]) v_per_cell = len(cells[0]) x_per_v = int(MPI.max(mpi_comm_world(), x_per_v)) v_per_cell = int(MPI.max(mpi_comm_world(), v_per_cell)) # Move a single cell to process with no cells while 0 in global_cell_distribution: to_process = list(global_cell_distribution).index(0) from_process = list(global_cell_distribution).index( max(global_cell_distribution)) # Extract vertices and remove cells[0] on from_process v_out = np.zeros((1 + x_per_v) * v_per_cell) if MPI.rank(mpi_comm_world()) == from_process: # Structure v_out as (ind0, x0, y0, .., ind1, x1, .., ) for i, v in enumerate(cells[0]): v_out[i * (x_per_v + 1)] = vertices[v][0] v_out[i * (x_per_v + 1) + 1:(i + 1) * (x_per_v + 1)] = vertices[v][1] # Remove vertices no longer used in remaining cells. for i, v in enumerate(cells[0]): if not any([v in c for c in cells[1:]]): for j in xrange(len(cells)): cells[j] = [ vi - 1 if vi > v else vi for vi in cells[j] ] for vi in range(v, max(vertices)): vertices[vi] = vertices[vi + 1] vertices.pop(max(vertices)) cells.pop(0) MPI.barrier(mpi_comm_world()) # Broadcast vertices in cell[0] on from_process v_in = broadcast(v_out, from_process) MPI.barrier(mpi_comm_world()) # Create cell and vertices on to_process if MPI.rank(mpi_comm_world()) == to_process: for i in xrange(v_per_cell): vertices[i] = (int(v_in[i * (x_per_v + 1)]), v_in[i * (x_per_v + 1) + 1:(i + 1) * (x_per_v + 1)]) assert len(cells) == 0 cells = [range(v_per_cell)] MPI.barrier(mpi_comm_world()) # Update distribution global_cell_distribution = distribution(len(cells)) return cells, vertices
rndnoise = np.random.randn(nbobspt*dimsol).reshape((nbobspt, dimsol)) DD[ii] = dd + sigmas.reshape((len(sigmas),1))*rndnoise waveobj.dd = DD waveobj.solvefwd_cost() if mpirank == 0: print 'noise misfit={}, regul cost={}, ratio={}'.format(waveobj.cost_misfit, \ waveobj.cost_reg, waveobj.cost_misfit/waveobj.cost_reg) #myplot.plot_timeseries(waveobj.solfwd[2], 'pd', 0, skip, dl.Function(V)) # Matvec for Hessian if mpirank == 0: print 'Compute gradient' waveobj.update_PDE({'b':b_target_fn}) waveobj.solvefwd_cost() waveobj.solveadj_constructgrad() x, y = dl.Function(Vm), dl.Function(Vm) setfct(x, 1.0) if mpirank == 0: print 'Time Hessian matvec' for ii in range(10): MPI.barrier(mpicomm) t0 = Wtime() waveobj.mult(x.vector(), y.vector()) t1 = Wtime() dt = t1-t0 mindt = MPI.min(mpicomm, t1-t0) maxdt = MPI.max(mpicomm, t1-t0) avgdt = MPI.sum(mpicomm, t1-t0) / float(mpisize) if mpirank == 0: print 'min={}, max={}, avg={}'.format(mindt, maxdt, avgdt)
def create_slice(basemesh, point, normal, closest_region=False, crinkle_clip=False): """Create a slicemesh from a basemesh. :param basemesh: Mesh to slice :param point: Point in slicing plane :param normal: Normal to slicing plane :param closest_region: Set to True to extract disjoint region closest to specified point :param crinkle_clip: Set to True to return mesh of same topological dimension as basemesh .. note:: Only 3D-meshes currently supported for slicing. .. warning:: Slice-instances are intended for visualization only, and may produce erronous results if used for computations. """ assert basemesh.geometry().dim() == 3, "Can only slice 3D-meshes." P = np.array([point[0], point[1], point[2]], dtype=np.double) # Create unit normal n = np.array([normal[0],normal[1], normal[2]]) n = n/np.linalg.norm(n) #self.n = Constant((n[0], n[1], n[2])) # Calculate the distribution of vertices around the plane # (sign of np.dot(p-P, n) determines which side of the plane p is on) vsplit = np.dot(basemesh.coordinates()-P, n) # Count each cells number of vertices on the "positive" side of the plane # Only cells with vertices on both sides of the plane intersect the plane operator = np.less npos = np.sum(vsplit[basemesh.cells()] < 0, 1) intersection_cells = basemesh.cells()[(npos > 0) & (npos < 4)] if len(intersection_cells) == 0: # Try to put "zeros" on other side of plane # FIXME: handle cells with vertices exactly intersecting the plane in a more robust manner. operator = np.greater npos = np.sum(vsplit[basemesh.cells()] > 0, 1) #cell_indices = (npos > 0) & (npos < 4) intersection_cells = basemesh.cells()[(npos > 0) & (npos < 4)] if crinkle_clip: cf = CellFunction("size_t", basemesh) cf.set_all(0) cf.array()[(npos>0) & (npos<4)] = 1 mesh = create_submesh(basemesh, cf, 1) else: def add_cell(cells, cell): # Split cell into triangles for i in xrange(len(cell)-2): cells.append(cell[i:i+3]) cells = [] index = 0 indexes = {} for c in intersection_cells: a = operator(vsplit[c], 0) positives = c[np.where(a==True)[0]] negatives = c[np.where(a==False)[0]] cell = [] for pp_ind in positives: pp = basemesh.coordinates()[pp_ind] for pn_ind in negatives: pn = basemesh.coordinates()[pn_ind] if (pp_ind, pn_ind) not in indexes: # Calculate intersection point with the plane d = np.dot(P-pp, n)/np.dot(pp-pn, n) ip = pp+(pp-pn)*d indexes[(pp_ind, pn_ind)] = (index, ip) index += 1 cell.append(indexes[(pp_ind, pn_ind)][0]) add_cell(cells, cell) MPI.barrier(mpi_comm_world()) # Assign global indices # TODO: Assign global indices properly dist = distribution(index) global_idx = sum(dist[:MPI.rank(mpi_comm_world())]) vertices = {} for idx, p in indexes.values(): vertices[idx] = (global_idx, p) global_idx += 1 global_num_cells = MPI.sum(mpi_comm_world(), len(cells)) global_num_vertices = MPI.sum(mpi_comm_world(), len(vertices)) mesh = Mesh() # Return empty mesh if no intersections were found if global_num_cells == 0: mesh_editor = MeshEditor() mesh_editor.open(mesh, "triangle", 2, 3) mesh_editor.init_vertices(0) mesh_editor.init_cells(0) mesh_editor.close() else: # Distribute mesh if empty on any processors cells, vertices = distribute_meshdata(cells, vertices) # Build mesh mesh_editor = MeshEditor() mesh_editor.open(mesh, "triangle", 2, 3) mesh_editor.init_vertices(len(vertices)) mesh_editor.init_cells(len(cells)) for index, cell in enumerate(cells): mesh_editor.add_cell(index, cell[0], cell[1], cell[2]) for local_index, (global_index, coordinates) in vertices.items(): mesh_editor.add_vertex_global(int(local_index), int(global_index), coordinates) mesh_editor.close() mesh.topology().init(0, len(vertices), global_num_vertices) mesh.topology().init(2, len(cells), global_num_cells) if closest_region and mesh.size_global(0) > 0: assert MPI.size(mpi_comm_world())==1, "Extract closest region does not work in parallel" regions = compute_connectivity(mesh) i,d = mesh.bounding_box_tree().compute_closest_entity(Point(P)) if d == MPI.min(mesh.mpi_comm(), d): v = regions[int(i)] else: v = 0 v = MPI.max(mesh.mpi_comm(), v) mesh = create_submesh(mesh, regions, v) return mesh
def _compute_boussinesq( problem, u0, p0, theta0, lorentz, joule, target_time=0.1, show=False ): # Define a facet measure on the boundaries. See discussion on # <https://bitbucket.org/fenics-project/dolfin/issue/249/facet-specification-doesnt-work-on-ds>. ds_workpiece = Measure("ds", subdomain_data=problem.wp_boundaries) submesh_workpiece = problem.W.mesh() # Start time, time step. t = 0.0 dt = 1.0e-3 dt_max = 1.0e-1 # Standard gravity, <https://en.wikipedia.org/wiki/Standard_gravity>. grav = 9.80665 assert problem.W.num_sub_spaces() == 3 g = Constant((0.0, -grav, 0.0)) # Compute a few mesh characteristics. wpi_area = assemble(1.0 * dx(submesh_workpiece)) # mesh.hmax() is a local function; get the global hmax. hmax_workpiece = MPI.max(submesh_workpiece.mpi_comm(), submesh_workpiece.hmax()) # Take the maximum length in x-direction as characteristic length of the # domain. coords = submesh_workpiece.coordinates() char_length = max(coords[:, 0]) - min(coords[:, 0]) # Prepare some parameters for the Navier-Stokes simulation in the workpiece m = problem.subdomain_materials[problem.wpi] k_wpi = m.thermal_conductivity cp_wpi = m.specific_heat_capacity rho_wpi = m.density mu_wpi = m.dynamic_viscosity theta_average = average(theta0) # show_total_force = True # if show_total_force: # f = rho_wpi(theta0) * g # if lorentz: # f += as_vector((lorentz[0], lorentz[1], 0.0)) # tri = plot(f, mesh=submesh_workpiece, title='Total external force') # plt.colorbar(tri) # plt.show() with XDMFFile(submesh_workpiece.mpi_comm(), "all.xdmf") as outfile: outfile.parameters["flush_output"] = True outfile.parameters["rewrite_function_mesh"] = False _store(outfile, u0, p0, theta0, t) if show: _plot(p0, theta0) plt.show() successful_steps = 0 failed_steps = 0 while t < target_time + DOLFIN_EPS: info( "Successful steps: {} (failed: {}, total: {})".format( successful_steps, failed_steps, successful_steps + failed_steps ) ) with Message("Time step {:e} -> {:e}...".format(t, t + dt)): # Do one heat time step. with Message("Computing heat..."): # Redefine the heat problem with the new u0. heat_problem = cyl_heat.Heat( problem.Q, kappa=k_wpi, rho=rho_wpi(theta_average), cp=cp_wpi, convection=u0, source=joule, dirichlet_bcs=problem.theta_bcs_d, neumann_bcs=problem.theta_bcs_n, my_dx=dx(submesh_workpiece), my_ds=ds_workpiece, ) # For time-stepping in buoyancy-driven flows, see # # Numerical solution of buoyancy-driven flows; # Einar Rossebø Christensen; # Master's thesis; # <http://www.diva-portal.org/smash/get/diva2:348831/FULLTEXT01.pdf>. # # Similar to the present approach, one first solves for # velocity and pressure, then for temperature. # heat_stepper = parabolic.ImplicitEuler(heat_problem) ns_stepper = cyl_ns.IPCS(time_step_method="backward euler") theta1 = heat_stepper.step(theta0, t, dt) theta0_average = average(theta0) try: # Do one Navier-Stokes time step. with Message("Computing flux and pressure..."): # Include proper temperature-dependence here to account # for the Boussinesq effect. f0 = rho_wpi(theta0) * g f1 = rho_wpi(theta1) * g if lorentz is not None: f = as_vector((lorentz[0], lorentz[1], 0.0)) f0 += f f1 += f u1, p1 = ns_stepper.step( Constant(dt), {0: u0}, p0, problem.W, problem.P, problem.u_bcs, problem.p_bcs, # Make constant TODO Constant(rho_wpi(theta0_average)), Constant(mu_wpi(theta0_average)), f={0: f0, 1: f1}, tol=1.0e-10, my_dx=dx(submesh_workpiece), ) except RuntimeError as e: info(e.args[0]) info( "Navier--Stokes solver failed to converge. " "Decrease time step from {:e} to {:e} and try again.".format( dt, 0.5 * dt ) ) dt *= 0.5 failed_steps += 1 continue successful_steps += 1 # Assignments and plotting. theta0.assign(theta1) u0.assign(u1) p0.assign(p1) _store(outfile, u0, p0, theta0, t + dt) if show: _plot(p0, theta0) plt.show() t += dt with Message("Diagnostics..."): # Print some general info on the flow in the crucible. umax = get_umax(u0) _print_diagnostics( theta0, umax, submesh_workpiece, wpi_area, problem.subdomain_materials, problem.wpi, rho_wpi, mu_wpi, char_length, grav, ) info("") with Message("Step size adaptation..."): # Some smooth step-size adaption. target_dt = 0.2 * hmax_workpiece / umax info("previous dt: {:e}".format(dt)) info("target dt: {:e}".format(target_dt)) # agg is the aggressiveness factor. The distance between # the current step size and the target step size is reduced # by |1-agg|. Hence, if agg==1 then dt_next==target_dt. # Otherwise target_dt is approached more slowly. agg = 0.5 dt = min( dt_max, # At most double the step size from step to step. dt * min(2.0, 1.0 + agg * (target_dt - dt) / dt), ) info("new dt: {:e}".format(dt)) info("") info("") return u0, p0, theta0