def initial_mesh(self): self.initial_hot_wall_refinement_cycles = 8 mesh = self.coarse_mesh() for i in range(self.initial_hot_wall_refinement_cycles): cell_markers = fenics.MeshFunction("bool", mesh, mesh.topology().dim(), False) cell_markers.set_all(False) for cell in fenics.cells(mesh): found_left_boundary = False for vertex in fenics.vertices(cell): if fenics.near(vertex.x(0), 0.): found_left_boundary = True break if found_left_boundary: cell_markers[cell] = True break # There should only be one such point in 1D. mesh = fenics.refine(mesh, cell_markers) return mesh
def refine_initial_mesh(self): """ Replace 2D refinement method with 3D method. Perhaps one could make an n-dimensional method. """ for i in range(self.initial_hot_wall_refinement_cycles): cell_markers = fenics.MeshFunction("bool", self.mesh, self.mesh.topology().dim(), False) for cell in fenics.cells(self.mesh): found_left_boundary = False for vertex in fenics.vertices(cell): if fenics.near(vertex.x(0), 0.): found_left_boundary = True break if found_left_boundary: cell_markers[cell] = True self.mesh = fenics.refine(self.mesh, cell_markers)
def refine_near_left_boundary(mesh, cycles): """ Refine mesh near the left boundary. The usual approach of using SubDomain and EdgeFunction isn't appearing to work in 1D, so I'm going to just loop through the cells of the mesh and set markers manually. """ for i in range(cycles): cell_markers = fenics.CellFunction("bool", mesh) cell_markers.set_all(False) for cell in fenics.cells(mesh): found_left_boundary = False for vertex in fenics.vertices(cell): if fenics.near(vertex.x(0), 0.): found_left_boundary = True if found_left_boundary: cell_markers[cell] = True break # There should only be one such point. mesh = fenics.refine(mesh, cell_markers) return mesh
def _assemble(self): coordinates = np.array(np.zeros(self.mesh.num_vertices()), dtype=[('x', float), ('y', float)]) for i, vertex in enumerate(df.vertices(self.mesh)): coordinates['x'][i] = vertex.x(0) coordinates['y'][i] = vertex.x(1) self._Ny = len(np.unique(coordinates['y'])) self._Nx = len(np.unique(coordinates['x'])) coordinates = np.sort(coordinates, order=['y', 'x']) X = coordinates['x'].reshape(self._Ny, self._Nx) Y = coordinates['y'].reshape(self._Ny, self._Nx) self._X = np.flipud(X) self._Y = np.flipud(Y) # check if uniform mesh T = np.diff(X, axis=1) self._dx = T[0, 0] assert (np.all(np.abs(T - self._dx) < 1e-12)) T = np.diff(Y, axis=0) self._dy = T[0, 0] assert (np.all(np.abs(T - self._dy) < 1e-12)) Interpolator = np.zeros( ((self._Ny - 1) * (self._Nx - 1), self.V.dim())) for i, cell in enumerate(df.cells(self.mesh)): x = cell.midpoint().x() y = cell.midpoint().y() cx = int(x // self._dx) cy = int(y // self._dy) cy = (self._Ny - 2) - cy pixel_id = cy * (self._Ny - 1) + cx Interpolator[pixel_id, i] = 0.5 ReverseInterpolator = np.zeros( (self.V.dim(), (self._Ny - 1) * (self._Nx - 1))) for i, row in enumerate(Interpolator): ind = np.where(row)[0] ReverseInterpolator[ind[0], i] = 1 ReverseInterpolator[ind[1], i] = 1 self.Interpolator = Interpolator self.ReverseInterpolator = ReverseInterpolator # a, b = np.where(self.Interpolator != 0) self._DofToPixelPermutator = torch.tensor(b, dtype=torch.long) a, b = self.ReverseInterpolator.nonzero() self._PixelToDofPermutator = torch.tensor(b, dtype=torch.long)
def system_multiplication_DoGIP(AT_dogip, Bhat, u_vec): # mutliplication with DoGIP decomposition Au = np.zeros_like(u_vec) for ii, cell in enumerate(cells(mesh)): ind = dofmapV.cell_dofs(ii) # local to global map Au[ind] += Bhat.T.dot(AT_dogip[ii] * Bhat.dot(u_vec[ind])) return Au
def refine_initial_mesh(self): """ Locally refine near the hot boundary """ for i in range(self.initial_hot_boundary_refinement_cycles): cell_markers = fenics.MeshFunction("bool", self.mesh, self.mesh.topology().dim(), False) cell_markers.set_all(False) for cell in fenics.cells(self.mesh): found_left_boundary = False for vertex in fenics.vertices(cell): if fenics.near(vertex.x(0), 0.): found_left_boundary = True break if found_left_boundary: cell_markers[cell] = True break # There should only be one such point in 1D. self.mesh = fenics.refine( self.mesh, cell_markers) # Does this break references?
def local_refine(mesh, center, r): xc, yc = center cell_markers = MeshFunction("bool", mesh, mesh.topology().dim()) for c in cells(mesh): mp = c.midpoint() cell_markers[c] = sqrt((mp[0] - xc) * (mp[0] - xc) + (mp[1] - yc) * (mp[1] - yc)) < r mesh = refine(mesh, cell_markers) return mesh
def build_mesh(self): self.length = 8. self.height = 2. self.notch_length = 0.2 self.notch_height = 0.4 domain = mshr.Polygon([fe.Point(0., 0.), fe.Point(self.length/2. - self.notch_length/2., 0.), fe.Point(self.length/2., self.notch_height), fe.Point(self.length/2. + self.notch_length/2., 0.), fe.Point(self.length, 0.), fe.Point(self.length, self.height), fe.Point(self.length/2. + self.notch_length/2., self.height), fe.Point(self.length/2., self.height), fe.Point(self.length/2. - self.notch_length/2., self.height), fe.Point(0., self.height)]) # resolution = 100 if self.local_refinement_iteration == 0 else 200 # self.mesh = mshr.generate_mesh(domain, resolution) self.mesh = mshr.generate_mesh(domain, 100) for i in range(self.local_refinement_iteration): cell_markers = fe.MeshFunction('bool', self.mesh, self.mesh.topology().dim()) cell_markers.set_all(False) for cell in fe.cells(self.mesh): p = cell.midpoint() if p[0] > 14./32.*self.length and p[0] < 18./32.*self.length and p[1] < self.height - self.notch_height: cell_markers[cell] = True self.mesh = fe.refine(self.mesh, cell_markers) length = self.length height = self.height notch_length = self.notch_length class Upper(fe.SubDomain): def inside(self, x, on_boundary): # return on_boundary return on_boundary and fe.near(x[1], height) class LeftCorner(fe.SubDomain): def inside(self, x, on_boundary): return fe.near(x[0], 0.) and fe.near(x[1], 0.) class RightCorner(fe.SubDomain): def inside(self, x, on_boundary): return fe.near(x[0], length) and fe.near(x[1], 0.) class MiddlePoint(fe.SubDomain): def inside(self, x, on_boundary): # return fe.near(x[0], length/2.) and fe.near(x[1], height) return x[0] > length/2. - notch_length/2. and x[0] < length/2. + notch_length/2. and fe.near(x[1], height) self.upper = Upper() self.left = LeftCorner() self.right = RightCorner() self.middle = MiddlePoint()
def adapt_coarse_solution_to_fine_solution(scalar, coarse_solution, fine_solution, element, absolute_tolerance=1.e-2, maximum_refinement_cycles=6, circumradius_threshold=0.01): """ Refine the mesh of the coarse solution until the interpolation error tolerance is met. """ adapted_coarse_mesh = fenics.Mesh(coarse_solution.function_space().mesh()) adapted_coarse_function_space = fenics.FunctionSpace( adapted_coarse_mesh, element) adapted_coarse_solution = fenics.Function(adapted_coarse_function_space) adapted_coarse_solution.leaf_node().vector( )[:] = coarse_solution.leaf_node().vector() for refinement_cycle in range(maximum_refinement_cycles): cell_markers = fenics.MeshFunction( "bool", adapted_coarse_mesh.leaf_node(), adapted_coarse_mesh.topology().dim(), False) for coarse_cell in fenics.cells(adapted_coarse_mesh.leaf_node()): coarse_value = scalar(adapted_coarse_solution.leaf_node(), coarse_cell.midpoint()) fine_value = scalar(fine_solution.leaf_node(), coarse_cell.midpoint()) if (abs(coarse_value - fine_value) > absolute_tolerance): cell_markers[coarse_cell] = True cell_markers = unmark_cells_below_circumradius( adapted_coarse_mesh.leaf_node(), cell_markers, circumradius_threshold) if any(cell_markers): adapted_coarse_mesh = fenics.refine(adapted_coarse_mesh, cell_markers) adapted_coarse_function_space = fenics.FunctionSpace( adapted_coarse_mesh, element) adapted_coarse_solution = fenics.project( fine_solution.leaf_node(), adapted_coarse_function_space.leaf_node()) else: break return adapted_coarse_solution, adapted_coarse_function_space, adapted_coarse_mesh
def coarsen(self): """ Remesh and refine the new mesh until the interpolation error tolerance is met. For simplicity, for now we'll consider only one scalar component of the solution. """ time = 0. + self.old_state.time fine_solution = self.state.solution.copy(deepcopy=True) self.setup_coarse_mesh() for refinement_cycle in range( self.coarsening_maximum_refinement_cycles): self.setup_function_space() self.setup_states() self.old_state.time = 0. + time self.old_state.solution = fenics.project( fine_solution.leaf_node(), self.function_space.leaf_node()) if refinement_cycle == self.coarsening_maximum_refinement_cycles: break exceeds_tolerance = fenics.MeshFunction("bool", self.mesh.leaf_node(), self.mesh.topology().dim(), False) exceeds_tolerance.set_all(False) for cell in fenics.cells(self.mesh.leaf_node()): coarse_value = self.old_state.solution.leaf_node()(cell.midpoint())\ [self.coarsening_scalar_solution_component_index] fine_value = fine_solution.leaf_node()(cell.midpoint())\ [self.coarsening_scalar_solution_component_index] if (abs(coarse_value - fine_value) > self.coarsening_absolute_tolerance): exceeds_tolerance[cell] = True if any(exceeds_tolerance): self.mesh = fenics.refine(self.mesh, exceeds_tolerance) else: break self.setup_problem_and_solver() # We broke important references.
def get_A_T(m, V, W=None, problem=1): """ The element-wise (local) system matrices of DoGIP Projection/interpolation operator between spaces V and W on the whole computational domain. Parameters ---------- m : Expression defines material coefficients as a scalar valued function (without loss of generality, material m is considered to be isotropic) V : FunctionSpace original finite element space W : FunctionSpace double-grid finite element space problem : {int, string} parameter defining problem: 0 - weighted projection, 1 - elliptic problem Returns ------- AT_dogip : ndarray element-wise (local) system matrices of DoGIP """ mesh = V.mesh() dim = mesh.geometry().dim() w = TestFunction(W) if problem in [0, 'projection']: AT_dogip = np.empty([mesh.num_cells(), W.element().space_dimension()]) for ii, cell in enumerate(cells(V.mesh())): AT_dogip[ii] = assemble_local(m * w * dx, cell) elif problem in [1, 'elliptic']: # assumes (without generality) that material coefficients are isotropic AT_dogip = np.empty( [mesh.num_cells(), dim, dim, W.element().space_dimension()]) for ii, cell in enumerate(cells(V.mesh())): refmap = Mapping(nodes=np.array( cell.get_vertex_coordinates()).reshape(dim + 1, dim)) MT = np.einsum('ij,k', np.eye(dim), np.atleast_1d(assemble_local(m * w * dx, cell))) AT_dogip[ii] = np.einsum('rp,sq,pqj->rsj', refmap.Ai, refmap.Ai, MT) return AT_dogip
def plot_mesh(mesh, color="green", alpha=0.5): """ Plot 2D mesh.""" coors = mesh.coordinates() trigs = numpy.asarray([cell.entities(0) for cell in cells(mesh)]) trimesh = tri.Triangulation(coors[:, 0], coors[:, 1], trigs) plt.triplot(trimesh, color=color, alpha=alpha) (x0, y0) = numpy.min(mesh.coordinates(), axis=0) (x1, y1) = numpy.max(mesh.coordinates(), axis=0) plt.axis([x0, x1, y0, y1]) plt.axes().set_aspect('equal')
def refine_mesh(self, tolerance: float) -> Optional[bool]: """Generate refined mesh. This method locates cells of the mesh where the error of the eigenfunction is above a certain threshold and generates a new mesh with finer resolution on the problematic regions. For a given eigenfunction $u$ with corresponding eigenvalue $\lambda$, it must be true that $a(u, v) = \lambda b(u, v)$ for all functions $v$. We make $v$ go through all the basis functions on the mesh and locate the cells where the previous identity fails to hold. Parameters ---------- tolerance : float Criterion to determine whether a cell needs to be refined or not. Returns ------- refined_mesh : Optional[fenics.Mesh] A new mesh derived from `mesh` with higher level of granularity on certain regions. If no refinements are needed, None is returned. """ ew, ev = self.eigenvalues[1:], self.eigenfunctions[1:] dofs_needing_refinement = set() # Find all the degrees of freedom needing refinement. for k, (l, u) in enumerate(zip(ew, ev)): v = fenics.TrialFunction(self.vector_space) a, b = self._construct_eigenproblem(u, v) A = fenics.assemble(a * fenics.dx) B = fenics.assemble(b * fenics.dx) error = np.abs((A - l * B).sum()) indices = np.flatnonzero(error > tolerance) dofs_needing_refinement.update(indices) if not dofs_needing_refinement: return # Refine the cells corresponding to the degrees of freedom needing # refinement. dofmap = self.vector_space.dofmap() cell_markers = fenics.MeshFunction('bool', self.mesh, self.mesh.topology().dim()) cell_markers.set_all(False) for cell in fenics.cells(self.mesh): cell_dofs = set(dofmap.cell_dofs(cell.index())) if cell_dofs.intersection(dofs_needing_refinement): cell_markers[cell] = True return fenics.refine(self.mesh, cell_markers)
def AssembleMeshOverlapMatrix(Vc, Vf): # assumes that Vc and Vf are conforming function spaces meshc = Vc.mesh() meshf = Vf.mesh() if Vc.dim() != meshc.num_cells() or Vf.dim() != meshf.num_cells(): raise TypeError('One of supplied function spaces not of type DG0') if meshc.num_cells() > meshf.num_cells(): raise ValueError tree = meshc.bounding_box_tree() reversemap = np.zeros(meshf.num_cells(), dtype=np.int) areafraction = np.zeros(meshf.num_cells()) coarse_area_by_id = np.zeros(meshc.num_cells()) dofmapc = Vc.dofmap() dofmapf = Vf.dofmap() for cell in df.cells(meshc): coarse_area_by_id[cell.index()] = cell.volume() for cell in df.cells(meshf): cell_id = tree.compute_first_entity_collision(cell.midpoint()) coarse_dof = dofmapc.cell_dofs(cell_id) fine_dof = dofmapf.cell_dofs(cell.index()) reversemap[fine_dof] = coarse_dof areafraction[fine_dof] = cell.volume() / coarse_area_by_id[cell_id] _W = np.zeros((Vc.dim(), Vf.dim())) # Issue: slow and not sparse for i in range(Vc.dim()): finedofs = np.where(reversemap == i)[0] _W[i, finedofs] = areafraction[finedofs] W = csr_matrix(_W); del(_W); return W
def unmark_cells_below_circumradius(mesh, cell_markers, circumradius): for cell in fenics.cells(mesh): if not cell_markers[cell]: continue if cell.circumradius() <= circumradius: cell_markers[cell] = False return cell_markers
ver = fn.Vertex(mesh, node) for edge in fn.edges(ver): if edge.index() in BoundaryEdges: entity = edge.entities(0) if all(item in nodes for item in entity): boundaries[edge.index()] = idx idx += 1 else: interior[key] = nodes sections = fn.MeshFunction('size_t', mesh, dim=2) sections.set_all(0) for num, (key, value) in enumerate(Faces.items(), 1): for node in value: ver = fn.Vertex(mesh, node) for cell in fn.cells(ver): entity = cell.entities(0) if all(item in value for item in entity): sections[cell.index()] = num fn.File("./UserFiles/boundaries.pvd") << boundaries fn.File("./UserFiles/sections.pvd") << sections F = fn.Function(V) File = fn.File("./UserFiles/result.pvd") for i in range(10): t = 0 + (i + 1) / 10 F.interpolate(fn.Expression("x[0]+5*t*x[1]", t=t, degree=2)) File << (F, t) ''' changes made:
import matplotlib.pyplot as plt from fenics import FunctionSpace, cells, interpolate from regge_geodesics import exponential_map from utils import plot_mesh, reference_data, exact_kepler # get initial data and mesh for a Kelper problem with # energy H=-1.5 (elliptic orbit) and initial momentum L=0.5. H = -1.5 L = 0.5 (_, _, gexp, mesh) = reference_data(H=H, L=L, mesh_type='unstructured', mesh_size=24, padding=0.07) (q0, p0, T, S, (c, a, b), sol, t2s) = exact_kepler(H, L) # Regge 0 is used g = interpolate(gexp, FunctionSpace(mesh, "Regge", 1)) # ODE solver step size h = min([c.inradius() for c in cells(mesh)]) / 2.0 # solve (ts, solh) = exponential_map(g, 0, q0, p0, h, 50 * S) # plot (qh, _) = solh(ts) plt.plot(qh[:, 0], qh[:, 1], color="blue") plot_mesh(mesh) plt.show()
def mfd_cellcell(mesh, V, u_n, De, nexp): """ MFD cell-to-cell Flow routing distributed from cell-to-cell :param mesh: mesh object generated using mshr (fenics) :param V: finite element function space :param u_n: solution (trial function) for water flux :param De: dimensionless diffusion coefficient :param nexp: water flux exponent :return: """ # get a map of neighbours (thanks google!) tdim = mesh.topology().dim() mesh.init(tdim - 1, tdim) cell_neighbors = np.array([ sum((list(filter(lambda ci: ci != cell.index(), facet.entities(tdim))) for facet in facets(cell)), []) for cell in cells(mesh) ]) # first get the elevation area of each element dofmap = V.dofmap() elevation = [] area = [] xm = [] ym = [] for cell in cells(mesh): cellnodes = dofmap.cell_dofs(cell.index()) elevation.append(sum(u_n.vector()[cellnodes]) / 3) area.append(cell.volume()) p = cell.midpoint() xm.append(p.x()) ym.append(p.y()) elevation = np.array(elevation) area = np.array(area) xm = np.array(xm) ym = np.array(ym) # now sort the vector of elevations by decending topography ind = np.argsort(-elevation) sorted_neighbors = cell_neighbors[ind] # determine length between elements steep_len = [] for cell in cells(mesh): xh = xm[cell.index()] yh = ym[cell.index()] neicells = cell_neighbors[cell.index()] tnei = elevation[neicells] imin = np.argmin(tnei) ncell = neicells[imin] xn = xm[ncell] yn = ym[ncell] steep_len.append(np.sqrt((xh - xn) * (xh - xn) + (yh - yn) * (yh - yn))) steep_len = np.array(steep_len) flux = area / steep_len # determine flux from highest to lowest cells for cell in cells(mesh): neicells = sorted_neighbors[cell.index()] tnei = elevation[neicells] imin = np.argmin(tnei) ncell = neicells[imin] weight = np.zeros(len(neicells)) i = 0 for neicell in neicells: weight[i] = elevation[ind[cell.index()]] - elevation[neicell] # downhill only if weight[i] < 0: weight[i] = 0 i += 1 # weight flux by the sum of the lengths down slope if max(weight) > 0: weight = weight / sum(weight) else: weight[:] = 0 i = 0 for neicell in neicells: flux[neicell] = flux[neicell] + flux[ind[cell.index()]] * weight[i] i += 1 # interpolate to the nodes gc = mesh.coordinates() flux_node = np.zeros(len(gc)) for cell in cells(mesh): cellnodes = dofmap.cell_dofs(cell.index()) for nod in cellnodes: flux_node[nod] = flux_node[nod] + flux[cell.index()] / 3 q = Function(V) q.vector()[:] = 1 + De * pow(flux_node, nexp) return q
# initialize degree = int(sys.argv[1]) levels = [int(sys.argv[2]) * 2**i for i in range(int(sys.argv[3]))] (q0, p0, T, S, (c, a, b), sol, t2s) = exact_kepler(H, L) Tmax = T * M gexp = kepler_jacobi_metric(c=H) ee = [] eH = [] eL = [] hs = [] # main loop for n in levels: (_, _, _, mesh) = reference_data(H, L, 'unstructured', n, padding=padding) hs.append(numpy.mean([c.h() for c in cells(mesh)])) print('Compute the solution for n={}...'.format(n)) g = interpolate(gexp, FunctionSpace(mesh, 'Regge', degree)) h = min([c.inradius() for c in cells(mesh)]) / 2.0 (_, solh) = exponential_map(g, 0, q0, p0, h, t2s(Tmax), verbose=True) print('Evaluate the solution and compute the error...') t = numpy.linspace(0, Tmax, 200 * M + 1) s = t2s(t) qe = sol(t) (qh, ph) = solh(s) (Hh, Lh) = integrals(qh, ph) d = qe - qh ee.append(numpy.max(numpy.sqrt(numpy.array([q.dot(q) for q in d]))))