def read_fenics_solution(filepath): from dolfin import (Mesh, XDMFFile, MeshValueCollection, cpp, FunctionSpace, Function, HDF5File, MPI) mesh = Mesh() with XDMFFile("%s_triangle.xdmf" % filepath.split('.')[0]) as infile: infile.read(mesh) # read the complete mesh #mvc_subdo = MeshValueCollection("size_t", mesh, mesh.geometric_dimension() - 1) #with XDMFFile("%s_triangle.xdmf" % filepath.split('.')[0]) as infile: # infile.read(mvc_subdo, "subdomains") # read the diferent subdomians #subdomains = cpp.mesh.MeshFunctionSizet(mesh, mvc_subdo) #mvc = MeshValueCollection("size_t", mesh, mesh.geometric_dimension() - 2) #with XDMFFile("%s_line.xdmf" % filepath.split('.')[0]) as infile: # infile.read(mvc, "boundary_conditions") # read the boundary conditions #boundary = cpp.mesh.MeshFunctionSizet(mesh, mvc) # Define function space and basis functions V = FunctionSpace(mesh, "CG", 1) U = Function(V) input_file = HDF5File(MPI.comm_world, filepath.split('.')[0] + "_solution_field.h5", "r") input_file.read(U, "solution") input_file.close() dofs = V.tabulate_dof_coordinates().reshape( V.dim(), mesh.geometry().dim()) # coordinates of nodes U.set_allow_extrapolation(True) return U, mesh, dofs.shape[0]
def test_fenics_vector_copy(): mesh = UnitSquare(3, 3) fs = FunctionSpace(mesh, "CG", 1) vec1 = FEniCSVector(Function(fs)) vec1.coeffs = np.array(range(fs.dim())) assert_equal(vec1.coeffs[0], 0) vec2 = vec1.copy() vec2.coeffs[0] = 5 assert_equal(vec1.coeffs[0], 0)
def create_function_space(cls, simulation): mesh = simulation.data['mesh'] cd = simulation.data['constrained_domain'] Vc_name = simulation.input.get_value( 'multiphase_solver/function_space_colour', 'Discontinuous Lagrange', 'string') Pc = simulation.input.get_value( 'multiphase_solver/polynomial_degree_colour', cls.default_polynomial_degree_colour, 'int', ) Vc = FunctionSpace(mesh, Vc_name, Pc, constrained_domain=cd) simulation.data['Vc'] = Vc simulation.ndofs += Vc.dim()
def _prepare_solution_fcns(self): # Extract parameters needed to create finite elements N = self.parameters["N"] gdim = self._mesh.geometry().dim() # Group elements for phi, chi, v elements_ch = (N - 1) * [ self._FE["phi"], ] + (N - 1) * [ self._FE["chi"], ] elements_ns = [ VectorElement(self._FE["v"], dim=gdim), ] # Append elements for p and th elements_ns.append(self._FE["p"]) if self._FE["th"] is not None: elements_ns.append(self._FE["th"]) # Build function spaces W_ch = FunctionSpace(self._mesh, MixedElement(elements_ch), constrained_domain=self._constrained_domain) W_ns = FunctionSpace(self._mesh, MixedElement(elements_ns), constrained_domain=self._constrained_domain) self._ndofs["CH"] = W_ch.dim() self._ndofs["NS"] = W_ns.dim() self._ndofs["total"] = W_ch.dim() + W_ns.dim() self._subspace["phi"] = [W_ch.sub(i) for i in range(N - 1)] self._subspace["chi"] = [ W_ch.sub(i) for i in range(N - 1, 2 * (N - 1)) ] self._ndofs["phi"] = W_ch.sub(0).dim() self._ndofs["chi"] = W_ch.sub(N - 1).dim() if gdim == 1: self._subspace["v"] = [ W_ns.sub(0), ] self._ndofs["v"] = W_ns.sub(0).dim() else: self._subspace["v"] = [W_ns.sub(0).sub(i) for i in range(gdim)] self._ndofs["v"] = W_ns.sub(0).sub(0).dim() self._subspace["p"] = W_ns.sub(1) self._ndofs["p"] = W_ns.sub(1).dim() self._ndofs["th"] = 0 if W_ns.num_sub_spaces() == 3: self._subspace["th"] = W_ns.sub(2) self._ndofs["th"] = W_ns.sub(2).dim() # ndofs = ( # (N-1)*(self._ndofs["phi"] + self._ndofs["chi"]) # + gdim*self._ndofs["v"] # + self._ndofs["p"] # + self._ndofs["th"] # ) # assert self._ndofs["total"] == ndofs # Create solution variables at ctl w_ctl = (Function(W_ch), Function(W_ns)) w_ctl[0].rename("semi_ctl_ch", "solution_semi_ch_ctl") w_ctl[1].rename("semi_ctl_ns", "solution_semi_ns_ctl") # Create solution variables at ptl w_ptl = [(Function(W_ch), Function(W_ns)) \ for i in range(self.parameters["PTL"])] for i, f in enumerate(w_ptl): f[0].rename("semi_ptl%i_ch" % i, "solution_semi_ch_ptl%i" % i) f[1].rename("semi_ptl%i_ns" % i, "solution_semi_ns_ptl%i" % i) return (w_ctl, w_ptl)
def _prepare_solution_fcns(self): # Extract parameters needed to create finite elements N = self.parameters["N"] gdim = self._mesh.geometry().dim() # Group elements for phi, chi, v elements_ch = (N - 1) * [ self._FE["phi"], ] + (N - 1) * [ self._FE["chi"], ] # NOTE: Elements for phi and chi are grouped together to avoid special # treatment of the case with N = 2. For example, if N == 2 and # phi would be represented as a vector with a single component # then a special treatment is needed to plot this single # component (UFL/DOLFIN ban to plot 1D function on a 2D mesh). elements = [] elements.append(MixedElement(elements_ch)) elements.append(VectorElement(self._FE["v"], dim=gdim)) # Append elements for p and th elements.append(self._FE["p"]) if self._FE["th"] is not None: elements.append(self._FE["th"]) # Build function spaces W = FunctionSpace(self._mesh, MixedElement(elements), constrained_domain=self._constrained_domain) self._ndofs["total"] = W.dim() self._subspace["phi"] = [W.sub(0).sub(i) for i in range(N - 1)] self._subspace["chi"] = [ W.sub(0).sub(i) for i in range(N - 1, 2 * (N - 1)) ] self._ndofs["phi"] = W.sub(0).sub(0).dim() self._ndofs["chi"] = W.sub(0).sub(N - 1).dim() if gdim == 1: self._subspace["v"] = [ W.sub(1), ] self._ndofs["v"] = W.sub(1).dim() else: self._subspace["v"] = [W.sub(1).sub(i) for i in range(gdim)] self._ndofs["v"] = W.sub(1).sub(0).dim() self._subspace["p"] = W.sub(2) self._ndofs["p"] = W.sub(2).dim() self._ndofs["th"] = 0 if W.num_sub_spaces() == 4: self._subspace["th"] = W.sub(3) self._ndofs["th"] = W.sub(3).dim() self._ndofs["CH"] = W.sub(0).dim() self._ndofs["NS"] = (gdim * self._ndofs["v"] + self._ndofs["p"] + self._ndofs["th"]) assert self._ndofs["total"] == self._ndofs["CH"] + self._ndofs["NS"] # Create solution variable at ctl w_ctl = (Function(W), ) w_ctl[0].rename("mono_ctl", "solution_mono_ctl") # Create solution variables at ptl w_ptl = [(Function(W), ) for i in range(self.parameters["PTL"])] for (i, f) in enumerate(w_ptl): f[0].rename("mono_ptl%i" % i, "solution_mono_ptl%i" % i) return (w_ctl, w_ptl)
plt.ylim(0.0, 0.015) plt.yticks([0.0, 0.005, 0.01, 0.015]) plt.colorbar(first) plt.show() second = plot(ca, title="Cation concentration, $c^+$") plt.xlim(0.0, 0.015) plt.xticks([0.0, 0.005, 0.01, 0.015]) plt.ylim(0.0, 0.015) plt.yticks([0.0, 0.005, 0.01, 0.015]) plt.colorbar(second) plt.show() third = plot(psi, title="Electric potential, $\psi$") plt.xlim(0.0, 0.015) plt.xticks([0.0, 0.005, 0.01, 0.015]) plt.ylim(0.0, 0.015) plt.yticks([0.0, 0.005, 0.01, 0.015]) plt.colorbar(third) plt.show() File('an_ES.pvd') << an File('ca_ES.pvd') << ca File('psi_ES.pvd') << psi totime = aftersolveT - startime #print("Start time is : " + str(round(startime, 2))) #print("After solve time : " + str(round(aftersolveT, 2))) print("Number of DOFs: {}".format(ME.dim())) print("Total time for Simulation : " + str(round(totime)) + "s")
class TestLumpedMass(unittest.TestCase): def setUp(self): mesh = UnitSquareMesh(5, 5, 'crossed') self.V = FunctionSpace(mesh, 'Lagrange', 5) self.u = Function(self.V) self.uM = Function(self.V) self.uMdiag = Function(self.V) test = TestFunction(self.V) trial = TrialFunction(self.V) m = test*trial*dx self.M = assemble(m) self.solver = LUSolver() self.solver.parameters['reuse_factorization'] = True self.solver.parameters['symmetric'] = True self.solver.set_operator(self.M) self.ones = np.ones(self.V.dim()) def test00(self): """ Create a lumped solver """ myobj = LumpedMatrixSolver(self.V) def test01_set(self): """ Set operator """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) def test01_entries(self): """ Lump matrix """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) err = 0.0 for index, ii in enumerate(self.M.array()): err += abs(ii.sum() - myobj.Mdiag[index]) self.assertTrue(err < index*1e-16) def test02(self): """ Invert lumped matrix """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) err = 0.0 for ii in range(len(myobj.Mdiag.array())): err += abs(1./myobj.Mdiag[ii] - myobj.invMdiag[ii]) self.assertTrue(err < ii*1e-16) def test03_basic(self): """ solve """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) myobj.solve(self.uMdiag.vector(), myobj.Mdiag) diff = (myobj.one - self.uMdiag.vector()).array() self.assertTrue(np.linalg.norm(diff)/np.linalg.norm(myobj.one.array()) < 1e-14) def test04_mult(self): """ overloaded * operator """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) self.uMdiag.vector().axpy(1.0, myobj*myobj.one) diff = (myobj.Mdiag - self.uMdiag.vector()).array() self.assertTrue(np.linalg.norm(diff)/np.linalg.norm(myobj.Mdiag.array()) < 1e-14) def test10(self): """ Create a lumped solver """ myobj = LumpedMatrixSolverS(self.V) def test11_set(self): """ Set operator """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) def test11_entries(self): """ Lump matrix """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) Msum = np.dot(self.ones, self.M.array().dot(self.ones)) err = abs(myobj.Mdiag.array().dot(self.ones) - \ Msum) / Msum self.assertTrue(err < 1e-14, err) def test12(self): """ Invert lumped matrix """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) err = 0.0 for ii in range(len(myobj.Mdiag.array())): err += abs(1./myobj.Mdiag[ii] - myobj.invMdiag[ii]) self.assertTrue(err < ii*1e-16) def test13_basic(self): """ solve """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) myobj.solve(self.uMdiag.vector(), myobj.Mdiag) diff = myobj.one.array() - self.uMdiag.vector().array() self.assertTrue(np.linalg.norm(diff)/np.linalg.norm(myobj.one.array()) < 1e-14) def test14_mult(self): """ overloaded * operator """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) self.uMdiag.vector().axpy(1.0, myobj*myobj.one) diff = (myobj.Mdiag - self.uMdiag.vector()).array() self.assertTrue(np.linalg.norm(diff)/np.linalg.norm(myobj.Mdiag.array()) < 1e-14)
def test_fenics_vector_inner(): mesh = UnitSquare(3, 3) fs = FunctionSpace(mesh, "CG", 1) vec = FEniCSVector(Function(fs)) vec.coeffs = np.array(range(fs.dim())) assert_equal(vec.__inner__(vec), 1240)
def run_simulation( filepath, topology_info: int = None, top_bc: int = None, bot_bc: int = None, left_bc: int = None, right_bc: int = None, geometry: dict = None, kappa=3, #only if geometry is None show=True, save_solution=False): from dolfin import (Mesh, XDMFFile, MeshValueCollection, cpp, FunctionSpace, TrialFunction, TestFunction, DirichletBC, Constant, Measure, inner, nabla_grad, Function, solve, plot, File) mesh = Mesh() with XDMFFile("%s_triangle.xdmf" % filepath.split('.')[0]) as infile: infile.read(mesh) # read the complete mesh mvc_subdo = MeshValueCollection("size_t", mesh, mesh.geometric_dimension() - 1) with XDMFFile("%s_triangle.xdmf" % filepath.split('.')[0]) as infile: infile.read(mvc_subdo, "subdomains") # read the diferent subdomians subdomains = cpp.mesh.MeshFunctionSizet(mesh, mvc_subdo) mvc = MeshValueCollection("size_t", mesh, mesh.geometric_dimension() - 2) with XDMFFile("%s_line.xdmf" % filepath.split('.')[0]) as infile: infile.read(mvc, "boundary_conditions") #read the boundary conditions boundary = cpp.mesh.MeshFunctionSizet(mesh, mvc) # Define function space and basis functions V = FunctionSpace(mesh, "CG", 1) u = TrialFunction(V) v = TestFunction(V) # Boundary conditions bcs = [] for bc_id in topology_info.keys(): if bc_id[-2:] == "bc": if bot_bc is not None and bc_id[:3] == "bot": bcs.append( DirichletBC(V, Constant(bot_bc), boundary, topology_info[bc_id])) elif left_bc is not None and bc_id[:4] == "left": bcs.append( DirichletBC(V, Constant(left_bc), boundary, topology_info[bc_id])) elif top_bc is not None and bc_id[:3] == "top": bcs.append( DirichletBC(V, Constant(top_bc), boundary, topology_info[bc_id])) elif right_bc is not None and bc_id[:5] == "right": bcs.append( DirichletBC(V, Constant(right_bc), boundary, topology_info[bc_id])) else: print(bc_id + " Not assigned as boundary condition ") # raise NotImplementedError # Define new measures associated with the interior domains and # exterior boundaries dx = Measure("dx", subdomain_data=subdomains) ds = Measure("ds", subdomain_data=boundary) f = Constant(0) g = Constant(0) if geometry is not None: # run multipatch implementation (Multiple domains) a = [] L = [] for patch_id in geometry.keys(): kappa = geometry[patch_id].get("kappa") a.append( inner(Constant(kappa) * nabla_grad(u), nabla_grad(v)) * dx(topology_info[patch_id])) L.append(f * v * dx(topology_info[patch_id])) a = sum(a) L = sum(L) else: a = inner(Constant(kappa) * nabla_grad(u), nabla_grad(v)) * dx L = f * v * dx ## Redefine u as a function in function space V for the solution u = Function(V) # Solve solve(a == L, u, bcs) u.rename('u', 'Temperature') # Save solution to file in VTK format print(' [+] Output to %s_solution.pvd' % filepath.split('.')[0]) vtkfile = File('%s_solution.pvd' % filepath.split('.')[0]) vtkfile << u if show: import matplotlib matplotlib.use("Qt5Agg") # Plot solution and gradient plot(u, title="Temperature") plt.gca().view_init(azim=-90, elev=90) plt.show() dofs = V.tabulate_dof_coordinates().reshape( V.dim(), mesh.geometry().dim()) #coordinates of nodes vals = u.vector().get_local() #temperature at nodes if save_solution: from dolfin import HDF5File, MPI output_file = HDF5File(MPI.comm_world, filepath.split('.')[0] + "_solution_field.h5", "w") output_file.write(u, "solution") output_file.close() u.set_allow_extrapolation(True) return dofs, vals, mesh, u
class TestLumpedMass(unittest.TestCase): def setUp(self): mesh = UnitSquareMesh(5, 5, 'crossed') self.V = FunctionSpace(mesh, 'Lagrange', 5) self.u = Function(self.V) self.uM = Function(self.V) self.uMdiag = Function(self.V) test = TestFunction(self.V) trial = TrialFunction(self.V) m = test * trial * dx self.M = assemble(m) self.solver = LUSolver() self.solver.parameters['reuse_factorization'] = True self.solver.parameters['symmetric'] = True self.solver.set_operator(self.M) self.ones = np.ones(self.V.dim()) def test00(self): """ Create a lumped solver """ myobj = LumpedMatrixSolver(self.V) def test01_set(self): """ Set operator """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) def test01_entries(self): """ Lump matrix """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) err = 0.0 for index, ii in enumerate(self.M.array()): err += abs(ii.sum() - myobj.Mdiag[index]) self.assertTrue(err < index * 1e-16) def test02(self): """ Invert lumped matrix """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) err = 0.0 for ii in range(len(myobj.Mdiag.array())): err += abs(1. / myobj.Mdiag[ii] - myobj.invMdiag[ii]) self.assertTrue(err < ii * 1e-16) def test03_basic(self): """ solve """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) myobj.solve(self.uMdiag.vector(), myobj.Mdiag) diff = (myobj.one - self.uMdiag.vector()).array() self.assertTrue( np.linalg.norm(diff) / np.linalg.norm(myobj.one.array()) < 1e-14) def test04_mult(self): """ overloaded * operator """ myobj = LumpedMatrixSolver(self.V) myobj.set_operator(self.M) self.uMdiag.vector().axpy(1.0, myobj * myobj.one) diff = (myobj.Mdiag - self.uMdiag.vector()).array() self.assertTrue( np.linalg.norm(diff) / np.linalg.norm(myobj.Mdiag.array()) < 1e-14) def test10(self): """ Create a lumped solver """ myobj = LumpedMatrixSolverS(self.V) def test11_set(self): """ Set operator """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) def test11_entries(self): """ Lump matrix """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) Msum = np.dot(self.ones, self.M.array().dot(self.ones)) err = abs(myobj.Mdiag.array().dot(self.ones) - \ Msum) / Msum self.assertTrue(err < 1e-14, err) def test12(self): """ Invert lumped matrix """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) err = 0.0 for ii in range(len(myobj.Mdiag.array())): err += abs(1. / myobj.Mdiag[ii] - myobj.invMdiag[ii]) self.assertTrue(err < ii * 1e-16) def test13_basic(self): """ solve """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) myobj.solve(self.uMdiag.vector(), myobj.Mdiag) diff = myobj.one.array() - self.uMdiag.vector().array() self.assertTrue( np.linalg.norm(diff) / np.linalg.norm(myobj.one.array()) < 1e-14) def test14_mult(self): """ overloaded * operator """ myobj = LumpedMatrixSolverS(self.V) myobj.set_operator(self.M) self.uMdiag.vector().axpy(1.0, myobj * myobj.one) diff = (myobj.Mdiag - self.uMdiag.vector()).array() self.assertTrue( np.linalg.norm(diff) / np.linalg.norm(myobj.Mdiag.array()) < 1e-14)
class PiecewiseEllipse: def __init__(self, centers, J, n): self.centers = centers self.J = J self.target = 0.002 self.J /= self.target # dir_path = os.path.dirname(os.path.realpath(__file__)) # with open(os.path.join(dir_path, '../colorio/data/gamut_triangulation.yaml')) as f: # data = yaml.safe_load(f) # self.points = numpy.column_stack([ # data['points'], numpy.zeros(len(data['points'])) # ]) # self.cells = numpy.array(data['cells']) # self.points, self.cells = colorio.xy_gamut_mesh(0.15) self.points, self.cells = meshzoo.triangle(n, corners=numpy.array( [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]])) # https://bitbucket.org/fenics-project/dolfin/issues/845/initialize-mesh-from-vertices editor = MeshEditor() mesh = Mesh() editor.open(mesh, "triangle", 2, 2) editor.init_vertices(self.points.shape[0]) editor.init_cells(self.cells.shape[0]) for k, point in enumerate(self.points): editor.add_vertex(k, point) for k, cell in enumerate(self.cells): editor.add_cell(k, cell) editor.close() self.V = FunctionSpace(mesh, "CG", 1) self.Vgrad = VectorFunctionSpace(mesh, "DG", 0) # self.ux0 = Function(self.V) # self.uy0 = Function(self.V) # 0 starting guess # ax = numpy.zeros(self.V.dim()) # ay = numpy.zeros(self.V.dim()) # Use F(x, y) = (x, y) as starting guess self.ux0 = project(Expression("x[0]", degree=1), self.V) self.uy0 = project(Expression("x[1]", degree=1), self.V) ax = self.ux0.vector().get_local() ay = self.uy0.vector().get_local() # Note that alpha doesn't contain the values in the order that one might expect, # see # <https://www.allanswered.com/post/awevg/projectexpressionx0-v-vector-get_local-not-in-order/>. self.alpha = numpy.concatenate([ax, ay]) self.num_f_eval = 0 # Build L as scipy.csr_matrix u = TrialFunction(self.V) v = TestFunction(self.V) L = assemble(dot(grad(u), grad(v)) * dx) Lmat = as_backend_type(L).mat() indptr, indices, data = Lmat.getValuesCSR() size = Lmat.getSize() self.L = sparse.csr_matrix((data, indices, indptr), shape=size) self.LT = self.L.getH() self.dx, self.dy = build_grad_matrices(self.V, centers) self.dxT = self.dx.getH() self.dyT = self.dy.getH() return def apply_M(self, ax, ay): """Linear operator that converts ax, ay to abcd.""" jac = numpy.array([[self.dx.dot(ax), self.dy.dot(ax)], [self.dx.dot(ay), self.dy.dot(ay)]]) # jacs and J are of shape (2, 2, k). M must be of the same shape and # contain the result of the k 2x2 dot products. Perhaps there's a # dot() for this. M = numpy.einsum("ijl,jkl->ikl", jac, self.J) # M = numpy.array([ # [ # jac[0][0]*self.J[0][0] + jac[0][1]*self.J[1][0], # jac[0][0]*self.J[0][1] + jac[0][1]*self.J[1][1], # ], # [ # jac[1][0]*self.J[0][0] + jac[1][1]*self.J[1][0], # jac[1][0]*self.J[0][1] + jac[1][1]*self.J[1][1], # ], # ]) # One could use # # M = numpy.moveaxis(M, -1, 0) # _, sigma, _ = numpy.linalg.svd(M) # # but computing the singular values explicitly via # <https://scicomp.stackexchange.com/a/14103/3980> is faster and more # explicit. a = (M[0, 0] + M[1, 1]) / 2 b = (M[0, 0] - M[1, 1]) / 2 c = (M[1, 0] + M[0, 1]) / 2 d = (M[1, 0] - M[0, 1]) / 2 return a, b, c, d def apply_M_alt(self, ax, ay): X = numpy.array([ self.dx.dot(ax), self.dy.dot(ax), self.dx.dot(ay), self.dy.dot(ay) ]) Y = numpy.array([ X[0] * self.J[0][0] + X[1] * self.J[1][0], X[0] * self.J[0][1] + X[1] * self.J[1][1], X[2] * self.J[0][0] + X[3] * self.J[1][0], X[2] * self.J[0][1] + X[3] * self.J[1][1], ]) Z = 0.5 * numpy.array( [Y[0] + Y[3], Y[0] - Y[3], Y[2] + Y[1], Y[2] - Y[1]]) return Z def apply_MT(self, abcd): a, b, c, d = abcd X = 0.5 * numpy.array([a + b, c - d, c + d, a - b]) Y = numpy.array([ X[0] * self.J[0][0] + X[1] * self.J[0][1], X[0] * self.J[1][0] + X[1] * self.J[1][1], X[2] * self.J[0][0] + X[3] * self.J[0][1], X[2] * self.J[1][0] + X[3] * self.J[1][1], ]) Z = numpy.array([ self.dxT.dot(Y[0]) + self.dyT.dot(Y[1]), self.dxT.dot(Y[2]) + self.dyT.dot(Y[3]), ]) return Z def get_q2_r2(self, ax, ay): a, b, c, d = self.apply_M(ax, ay) # From the square roots of q2 and r2, the ellipse axes can be computed, # namely # # s1 = q + r # s2 = q - r # q2 = a**2 + d**2 r2 = b**2 + c**2 return q2, r2 def jac_q2_r2(self, ax, ay, bx, by): a, b, c, d = self.apply_M(ax, ay) # e, f, g, h = self.apply_M(bx, by) out1 = 2 * (a * e + d * h) out2 = 2 * (b * f + c * g) return out1, out2 def jacT_q2_r2(self, ax, ay, out1, out2): a, b, c, d = self.apply_M(ax, ay) # X = 2 * numpy.array([a * out1, b * out2, c * out2, d * out1]) Y = self.apply_MT(X) return Y def get_ellipse_axes(self, alpha): ax, ay = numpy.split(alpha, 2) q, r = numpy.sqrt(self.get_q2_r2(ax, ay)) sigma = numpy.array([q + r, q - r]) * self.target return sigma def cost_ls(self, alpha): n = self.V.dim() ax = alpha[:n] ay = alpha[n:] # res_x, res_y = self.L.dot(numpy.column_stack([ax, ay])).T res_x = self.L.dot(ax) res_y = self.L.dot(ay) q2, r2 = self.get_q2_r2(ax, ay) # Some word on the (absence of) weights here. # Weights on the residuals are not required: The residual entries are integrals # with the test functions, so they'll naturally decrease in absolute value as # the cell size decreases. # One idea for scaling q2 and r2 would be to divide by the number of measurement # points (or rather the sqrt thereof). This would ensure that, if more measure # points are added, they as a set aren't weighted more than the other quality # indicators, e.g., the smoothness in x and y. On the other hand, by omitting # an explicit weight that depends on the number of data points, one asserts that # additional measurements do not decrease the weights on the other measurements. # As consequence, more measurements as a set take a higher relative weight in # the cost function. This is what we want. out = numpy.array([res_x, res_y, q2 - 1.0, r2]) self.num_f_eval += 1 if self.num_f_eval % 100 == 0: cost = numpy.array([numpy.dot(ot, ot) for ot in out]) print("{:7d} {:e} {:e} {:e} {:e}".format( self.num_f_eval, *cost)) return numpy.concatenate(out) def jac_ls(self, alpha): m = 2 * self.V.dim() + 2 * self.centers.shape[0] n = alpha.shape[0] d = self.V.dim() c = self.centers.shape[0] assert 2 * d == n ax = alpha[:d] ay = alpha[d:] jac_alpha = numpy.array([[self.dx.dot(ax), self.dy.dot(ax)], [self.dx.dot(ay), self.dy.dot(ay)]]) M_alpha = numpy.einsum("ijl,jkl->ikl", jac_alpha, self.J) a_alpha = (M_alpha[0, 0] + M_alpha[1, 1]) / 2 b_alpha = (M_alpha[0, 0] - M_alpha[1, 1]) / 2 c_alpha = (M_alpha[1, 0] + M_alpha[0, 1]) / 2 d_alpha = (M_alpha[1, 0] - M_alpha[0, 1]) / 2 def matvec(phi): if len(phi.shape) > 1: assert len(phi.shape) == 2 assert phi.shape[1] == 1 phi = phi[:, 0] # Laplace part (it's linear, so this is easy) ax = phi[:d] ay = phi[d:] res_x = self.L.dot(ax) res_y = self.L.dot(ay) # q2, r2 part jac_phi = numpy.array([[self.dx.dot(ax), self.dy.dot(ax)], [self.dx.dot(ay), self.dy.dot(ay)]]) M_phi = numpy.einsum("ijl,jkl->ikl", jac_phi, self.J) a_phi = M_phi[0, 0] + M_phi[1, 1] b_phi = M_phi[0, 0] - M_phi[1, 1] c_phi = M_phi[1, 0] + M_phi[0, 1] d_phi = M_phi[1, 0] - M_phi[0, 1] dq2_phi = a_alpha * a_phi + d_alpha * d_phi dr2_phi = b_alpha * b_phi + c_alpha * c_phi return numpy.concatenate([res_x, res_y, dq2_phi, dr2_phi]) def rmatvec(vec): res_x = vec[:d] res_y = vec[d:2 * d] dq2_phi = vec[2 * d:2 * d + c] dr2_phi = vec[2 * d + c:] X = numpy.array([ a_alpha * dq2_phi, b_alpha * dr2_phi, c_alpha * dr2_phi, d_alpha * dq2_phi, ]) Y = numpy.array( [X[0] + X[1], X[2] - X[3], X[2] + X[3], X[0] - X[1]]) Z = numpy.array([ self.J[0][0] * Y[0] + self.J[0][1] * Y[1], self.J[1][0] * Y[0] + self.J[1][1] * Y[1], self.J[0][0] * Y[2] + self.J[0][1] * Y[3], self.J[1][0] * Y[2] + self.J[1][1] * Y[3], ]) return numpy.concatenate([ self.LT.dot(res_x) + self.dxT.dot(Z[0]) + self.dyT.dot(Z[1]), self.LT.dot(res_y) + self.dxT.dot(Z[2]) + self.dyT.dot(Z[3]), ]) # # test matvec # u = alpha # numpy.random.seed(0) # du = numpy.random.rand(n) # # du = numpy.zeros(n) # # du[0] = 1.0 # eps = 1.0e-10 # fupdu = self.cost(u + eps*du) # fumdu = self.cost(u - eps*du) # fu = self.cost(u) # ndiff1 = (fupdu - fu) / eps # ndiff2 = (fu - fumdu) / eps # ndiff3 = (fupdu - fumdu) / (2*eps) # jdiff1 = matvec(du) # jdiff2 = numpy.dot(matrix, du) # print() # d = self.V.dim() # print(ndiff1[-4:]) # print(ndiff2[-4:]) # print(ndiff3[-4:]) # print(jdiff1[-4:]) # print(jdiff2[-4:]) # print() return LinearOperator([m, n], matvec=matvec, rmatvec=rmatvec) def cost_min(self, alpha): n = self.V.dim() ax = alpha[:n] ay = alpha[n:] Lax = self.L * ax Lay = self.L * ay q2, r2 = self.get_q2_r2(ax, ay) out = [ 0.5 * numpy.dot(Lax, Lax), 0.5 * numpy.dot(Lay, Lay), 0.5 * numpy.dot(q2 - 1, q2 - 1), 0.5 * numpy.dot(r2, r2), ] if self.num_f_eval % 10000 == 0: print("{:7d} {:e} {:e} {:e} {:e}".format( self.num_f_eval, *out)) self.num_f_eval += 1 return numpy.sum(out) def grad_min(self, alpha, assert_equality=False): n = self.V.dim() if assert_equality: M = [] for k in range(30): e = numpy.zeros(30) e[k] = 1.0 ax = e[:n] ay = e[n:] M.append(numpy.concatenate(self.apply_M_alt(ax, ay))) M = numpy.column_stack(M) MT = [] for k in range(100): e = numpy.zeros(100) e[k] = 1.0 abcd = numpy.array([e[:25], e[25:50], e[50:75], e[75:]]) MT.append(numpy.concatenate(self.apply_MT(abcd))) MT = numpy.column_stack(MT) assert numpy.all(abs(M.T - MT) < 1.0e-13) if assert_equality: M = [] for k in range(30): e = numpy.zeros(30) e[k] = 1.0 bx = e[:n] by = e[n:] M.append(numpy.concatenate(self.jac_q2_r2(ax, ay, bx, by))) M = numpy.column_stack(M) MT = [] for k in range(50): e = numpy.zeros(50) e[k] = 1.0 out1 = e[:25] out2 = e[25:] MT.append( numpy.concatenate(self.jacT_q2_r2(ax, ay, out1, out2))) MT = numpy.column_stack(MT) assert numpy.all(abs(M.T - MT) < 1.0e-13) ax = alpha[:n] ay = alpha[n:] q2, r2 = self.get_q2_r2(ax, ay) j = self.jacT_q2_r2(ax, ay, q2 - 1, r2) out = [ self.LT.dot(self.L.dot(ax)) + j[0], self.LT.dot(self.L.dot(ay)) + j[1] ] if assert_equality: n = len(alpha) g = [] for k in range(n): e = numpy.zeros(n) e[k] = 1.0 eps = 1.0e-5 f0 = self.cost_min(alpha - eps * e) f1 = self.cost_min(alpha + eps * e) g.append((f1 - f0) / (2 * eps)) # print(numpy.array(g)) # print(numpy.concatenate(out)) assert numpy.all( abs(numpy.array(g) - numpy.concatenate(out)) < 1.0e-5) return numpy.concatenate(out) def cost_min2(self, alpha): """Residual formulation, Hessian is a low-rank update of the identity.""" n = self.V.dim() ax = alpha[:n] ay = alpha[n:] # ml = pyamg.ruge_stuben_solver(self.L) # # ml = pyamg.smoothed_aggregation_solver(self.L) # print(ml) # print() # print(self.L) # print() # x = ml.solve(ax, tol=1e-10) # print('residual: {}'.format(numpy.linalg.norm(ax - self.L*x))) # print() # print(ax) # print() # print(x) # exit(1) # x = sparse.linalg.spsolve(self.L, ax) # print('residual: {}'.format(numpy.linalg.norm(ax - self.L*x))) # exit(1) q2, r2 = self.get_q2_r2(ax, ay) Lax = self.L * ax Lay = self.L * ay out = [ 0.5 * numpy.dot(Lax, Lax), 0.5 * numpy.dot(Lay, Lay), 0.5 * numpy.dot(q2 - 1, q2 - 1), 0.5 * numpy.dot(r2, r2), ] if self.num_f_eval % 10000 == 0: print("{:7d} {:e} {:e} {:e} {:e}".format( self.num_f_eval, *out)) self.num_f_eval += 1 return numpy.sum(out) def get_u(self, alpha): n = self.V.dim() ax = alpha[:n] ay = alpha[n:] ux = Function(self.V) ux.vector().set_local(ax) ux.vector().apply("") uy = Function(self.V) uy.vector().set_local(ay) uy.vector().apply("") return ux, uy
class Problem(object): def __init__(self, coarse_mesh, nref, p_coarse, p_fine, sym=False): """ :param dolfin.cpp.mesh.Mesh coarse_mesh: :param int nref: :param int p_coarse: :param int p_fine: :param bool sym: :return: """ print0("Creating approximation spaces") self.V_coarse = FunctionSpace(coarse_mesh, "CG", p_coarse) self.ndof_coarse = self.V_coarse.dim() refined_mesh = coarse_mesh for ref in xrange(nref): refined_mesh = refine(refined_mesh) # creates a new Mesh, initial coarse mesh is unchanged self.V_fine = FunctionSpace(refined_mesh, "CG", p_fine) self.ndof_fine = self.V_fine.dim() H = coarse_mesh.hmax() h = refined_mesh.hmax() self.alpha = log(H)/log(h) self.beta = p_fine + 1 if comm.rank == 0: prop = Table("Approximation properties") prop.set("ndof", "coarse", self.ndof_coarse) prop.set("ndof", "fine", self.ndof_fine) prop.set("h", "coarse", H) prop.set("h", "fine", h) info(prop) print "alpha = {}, beta = {}".format(self.alpha, self.beta) self.bc_coarse = None self.A_fine = PETScMatrix() self.B_fine = PETScMatrix() self.A_coarse = PETScMatrix() self.B_coarse = PETScMatrix() self.sym = sym self.switch_gep_matrices = False def identity_at_coarse_level(self): I = PETScMatrix() u = TrialFunction(self.V_coarse) v = TestFunction(self.V_coarse) assemble(Constant(0)*u*v*dx, tensor=I) I.ident_zeros() return I def residual_norm(self, vec, lam, norm_type='l2', A=None, B=None): if A is None: A = self.A_fine B = self.B_fine r = PETScVector() A.mult(vec, r) if B.size(0) > 0: y = PETScVector() B.mult(vec, y) else: y = 1 r -= lam*y return norm(r,norm_type) def rayleigh_quotient(self, vec, A=None, B=None): if A is None: A = self.A_fine B = self.B_fine r = PETScVector() A.mult(vec, r) nom = MPI_sum( numpy.dot(r, vec) ) if B.size(0) > 0: B.mult(vec, r) denom = MPI_sum( numpy.dot(r, vec) ) else: denom = sqr(norm(r, norm_type='l2')) return nom/denom
class Discretization(object): def __init__(self, problem, verbosity=0): """ :param ProblemData problem: :param int verbosity: :return: """ self.parameters = parameters["discretization"] self.verb = verbosity self.vis_folder = os.path.join(problem.out_folder, "MESH") self.core = problem.core self.G = problem.G if self.verb > 1: print pid+"Loading mesh" t_load = Timer("DD: Data loading") if not problem.mesh_module: if self.verb > 1: print pid + " mesh data" self.mesh = Mesh(problem.mesh_files.mesh) if self.verb > 1: print pid + " physical data" self.cell_regions_fun = MeshFunction("size_t", self.mesh, problem.mesh_files.physical_regions) if self.verb > 1: print pid + " boundary data" self.boundaries = MeshFunction("size_t", self.mesh, problem.mesh_files.facet_regions) else: self.mesh = problem.mesh_module.mesh self.cell_regions_fun = problem.mesh_module.regions try: self.boundaries = problem.mesh_module.boundaries except AttributeError: self.boundaries = None assert self.mesh assert self.boundaries is None or self.boundaries.array().size > 0 if self.verb > 2: print pid+" mesh info: " + str(self.mesh) if self.verb > 1: print0("Defining function spaces" ) self.t_spaces = Timer("DD: Function spaces construction") # Spaces that must be specified by the respective subclasses self.V = None # solution space self.Vphi1 = None # 1-g scalar flux space # XS / TH space self.V0 = FunctionSpace(self.mesh, "DG", 0) self.ndof0 = self.V0.dim() dofmap = self.V0.dofmap() self.local_ndof0 = dofmap.local_dimension("owned") self.cell_regions = self.cell_regions_fun.array() assert self.cell_regions.size == self.local_ndof0 def __create_cell_dof_mapping(self, dofmap): """ Generate cell -> dof mapping for all cells of current partition. Note: in DG(0) space, there is one dof per element and no ghost cells. :param GenericDofMap dofmap: DG(0) dofmap """ if self.verb > 2: print0("Constructing cell -> dof mapping") timer = Timer("DD: Cell->dof construction") code = \ ''' #include <dolfin/mesh/Cell.h> namespace dolfin { void fill_in(Array<int>& local_cell_dof_map, const Mesh& mesh, const GenericDofMap& dofmap) { std::size_t local_dof_range_start = dofmap.ownership_range().first; int* cell_dof_data = local_cell_dof_map.data(); for (CellIterator c(mesh); !c.end(); ++c) *cell_dof_data++ = dofmap.cell_dofs(c->index())[0] - local_dof_range_start; } } ''' cell_mapping_module = compile_extension_module(code) cell_dof_array = IntArray(self.local_ndof0) cell_mapping_module.fill_in(cell_dof_array, self.mesh, dofmap) self._local_cell_dof_map = cell_dof_array.array() timer.stop() def __create_cell_layers_mapping(self): """ Generate a cell -> axial layer mapping for all cells of current partition. Note that keys are ordered by the associated DG(0) dof, not by the cell index in the mesh. """ if self.verb > 2: print0("Constructing cell -> layer mapping") timer = Timer("DD: Cell->layer construction") code = \ ''' #include <dolfin/mesh/Cell.h> namespace dolfin { void fill_in(Array<int>& local_cell_layers, const Mesh& mesh, const Array<int>& cell_dofs, const Array<double>& layer_boundaries) { std::size_t num_layers = layer_boundaries.size() - 1; unsigned int layer; for (CellIterator c(mesh); !c.end(); ++c) { double midz = c->midpoint().z(); for (layer = 0; layer < num_layers; layer++) if (layer_boundaries[layer] <= midz && midz <= layer_boundaries[layer+1]) break; int dof = cell_dofs[c->index()]; local_cell_layers[dof] = layer; } } } ''' cell_mapping_module = compile_extension_module(code) cell_layers_array = IntArray(self.local_ndof0) cell_mapping_module.fill_in(cell_layers_array, self.mesh, self.local_cell_dof_map, self.core.layer_boundaries) self._local_cell_layers = cell_layers_array.array() timer.stop() def __create_cell_vol_mapping(self): """ Generate cell -> volume mapping for all cells of current partition. Note that keys are ordered by the associated DG(0) dof, not by the cell index in the mesh. This map is required for calculating various densities from total region integrals (like cell power densities from cell-integrated powers). """ if self.verb > 2: print0("Constructing cell -> volume mapping") timer = Timer("DD: Cell->vol construction") code = \ ''' #include <dolfin/mesh/Cell.h> namespace dolfin { void fill_in(Array<double>& cell_vols, const Mesh& mesh, const Array<int>& cell_dofs) { for (CellIterator c(mesh); !c.end(); ++c) cell_vols[cell_dofs[c->index()]] = c->volume(); } } ''' cell_mapping_module = compile_extension_module(code) cell_vol_array = DoubleArray(self.local_ndof0) cell_mapping_module.fill_in(cell_vol_array, self.mesh, self.local_cell_dof_map) self._local_cell_volumes = cell_vol_array.array() timer.stop() @property def local_cell_dof_map(self): try: self._local_cell_dof_map except AttributeError: self.__create_cell_dof_mapping(self.V0.dofmap()) return self._local_cell_dof_map @property def local_cell_volumes(self): try: self._local_cell_volumes except AttributeError: self.__create_cell_vol_mapping() return self._local_cell_volumes @property def local_cell_layers(self): try: self._local_cell_layers except AttributeError: self.__create_cell_layers_mapping() return self._local_cell_layers def visualize_mesh_data(self): timer = Timer("DD: Mesh data visualization") if self.verb > 2: print0("Visualizing mesh data") File(os.path.join(self.vis_folder, "mesh.pvd"), "compressed") << self.mesh if self.boundaries: File(os.path.join(self.vis_folder, "boundaries.pvd"), "compressed") << self.boundaries File(os.path.join(self.vis_folder, "mesh_regions.pvd"), "compressed") << self.cell_regions_fun # Create MeshFunction to hold cell process rank processes = CellFunction('size_t', self.mesh, MPI.rank(comm)) File(os.path.join(self.vis_folder, "mesh_partitioning.pvd"), "compressed") << processes def print_diagnostics(self): print "\nDiscretization diagnostics" print MPI.rank(comm), self.mesh.num_entities(self.mesh.topology().dim()) dofmap = self.V0.dofmap() print MPI.rank(comm), dofmap.ownership_range() print MPI.rank(comm), numpy.min(dofmap.collapse(self.mesh)[1].values()), \ numpy.max(dofmap.collapse(self.mesh)[1].values()) print "#Owned by {}: {}".format(MPI.rank(comm), dofmap.local_dimension("owned")) print "#Unowned by {}: {}".format(MPI.rank(comm), dofmap.local_dimension("unowned"))
print('-- p = {0}, N = {1} --------'.format(p, Ne)) filen_data = 'data/t%d_d%d_Nm%d_p%.2d_Ne%.3d' % (problem, dim, Ne_max, p, Ne) if dim == 2: mesh = UnitSquareMesh(Ne, Ne) Amat = Expression("1+10*exp(x[0])*exp(x[1])", degree=2) elif dim == 3: mesh = UnitCubeMesh(Ne, Ne, Ne) Amat = Expression("1+100*exp(x[0])*exp(x[1])*x[2]*x[1]", degree=3) mesh.coordinates()[:] += 0.1 * np.random.random( mesh.coordinates().shape) # mesh perturbation V = FunctionSpace(mesh, 'CG', p) print('V.dim = {0}'.format(V.dim())) if calculate in [1, -1]: ut, vt = TrialFunction(V), TestFunction(V) print('generating matrices A, Ad, A_T') if problem == 0: AG = assemble(Amat * ut * vt * dx, tensor=EigenMatrix()) A_T = get_A_T_empty(V, problem=problem, full=False) else: AG = assemble(inner(Amat * grad(ut), grad(vt)) * dx, tensor=EigenMatrix()) A_T = get_A_T_empty(V, problem=problem, full=False) print('generating matrices B, B0...') B0 = get_Bhat(dim=dim, pol_order=p, problem=problem)
from dolfin import XDMFFile, inner, grad, dx, assemble from interpreter import Eval # Build a monomial basis for x, y, x**2, xy, y**2, ... try: from pydmd import DMD # https://github.com/mathLab/PyDMD except ImportError: from xcalc.dmdbase import DMD deg = 4 mesh = UnitSquareMesh(3, 3) V = FunctionSpace(mesh, 'CG', 1) f = interpolate(Expression('x[0]+x[1]', degree=1), V).vector().get_local() A = np.diag(np.random.rand(V.dim())) basis = [] for i in range(deg): for j in range(deg): f = A.dot(f) Af = Function(V); Af.vector().set_local(f) basis.append(Af) # NOTE: skipping 1 bacause Eval of it is not a Function dmd_ = DMD(svd_rank=-1, exact=False) energy, pod_basis = dmd(basis[1:], dmd_) print np.linalg.norm(dmd_.snapshots - dmd_.reconstructed_data.real) print len(pod_basis), len(basis[1:])
def _evaluateLocalEstimator(cls, mu, w, coeff_field, pde, f, quadrature_degree, epsilon=1e-5): """Evaluation of patch local equilibrated estimator.""" # prepare numerical flux and f sigma_mu, f_mu = evaluate_numerical_flux(w, mu, coeff_field, f) # ################### # ## MIXED PROBLEM ## # ################### # get setup data for mixed problem V = w[mu]._fefunc.function_space() mesh = V.mesh() mesh.init() degree = element_degree(w[mu]._fefunc) # data for nodal bases V_dm = V.dofmap() V_dofs = dict([(i, V_dm.cell_dofs(i)) for i in range(mesh.num_cells())]) V1 = FunctionSpace(mesh, 'CG', 1) # V1 is to define nodal base functions phi_z = Function(V1) phi_coeffs = np.ndarray(V1.dim()) vertex_dof_map = V1.dofmap().vertex_to_dof_map(mesh) # vertex_dof_map = vertex_to_dof_map(V1) dof_list = vertex_dof_map.tolist() # DG0 localisation DG0 = FunctionSpace(mesh, 'DG', 0) DG0_dofs = dict([(c.index(),DG0.dofmap().cell_dofs(c.index())[0]) for c in cells(mesh)]) dg0 = TestFunction(DG0) # characteristic function of patch xi_z = Function(DG0) xi_coeffs = np.ndarray(DG0.dim()) # mesh data h = CellSize(mesh) n = FacetNormal(mesh) cf = CellFunction('size_t', mesh) # setup error estimator vector eq_est = np.zeros(DG0.dim()) # setup global equilibrated flux vector DG = VectorFunctionSpace(mesh, "DG", degree) DG_dofmap = DG.dofmap() # define form functions tau = TrialFunction(DG) v = TestFunction(DG) # define global tau tau_global = Function(DG) tau_global.vector()[:] = 0.0 # iterate vertices for vertex in vertices(mesh): # get patch cell indices vid = vertex.index() patch_cid, FF_inner, FF_boundary = get_vertex_patch(vid, mesh, layers=1) # set nodal base function phi_coeffs[:] = 0 phi_coeffs[dof_list.index(vid)] = 1 phi_z.vector()[:] = phi_coeffs # set characteristic function and mark patch cf.set_all(0) xi_coeffs[:] = 0 for cid in patch_cid: xi_coeffs[DG0_dofs[int(cid)]] = 1 cf[int(cid)] = 1 xi_z.vector()[:] = xi_coeffs # determine local dofs lDG_cell_dofs = dict([(cid, DG_dofmap.cell_dofs(cid)) for cid in patch_cid]) lDG_dofs = [cd.tolist() for cd in lDG_cell_dofs.values()] lDG_dofs = list(iter.chain(*lDG_dofs)) # print "\nlocal DG subspace has dimension", len(lDG_dofs), "degree", degree, "cells", len(patch_cid), patch_cid # print "local DG_cell_dofs", lDG_cell_dofs # print "local DG_dofs", lDG_dofs # create patch measures dx = Measure('dx')[cf] dS = Measure('dS')[FF_inner] # define forms alpha = Constant(1 / epsilon) / h a = inner(tau,v) * phi_z * dx(1) + alpha * div(tau) * div(v) * dx(1) + avg(alpha) * jump(tau,n) * jump(v,n) * dS(1)\ + avg(alpha) * jump(xi_z * tau,n) * jump(v,n) * dS(2) L = -alpha * (div(sigma_mu) + f) * div(v) * phi_z * dx(1)\ - avg(alpha) * jump(sigma_mu,n) * jump(v,n) * avg(phi_z)*dS(1) # print "L2 f + div(sigma)", assemble((f + div(sigma)) * (f + div(sigma)) * dx(0)) # assemble forms lhs = assemble(a, form_compiler_parameters={'quadrature_degree': quadrature_degree}) rhs = assemble(L, form_compiler_parameters={'quadrature_degree': quadrature_degree}) # convert DOLFIN representation to scipy sparse arrays rows, cols, values = lhs.data() lhsA = sps.csr_matrix((values, cols, rows)).tocoo() # slice sparse matrix and solve linear problem lhsA = coo_submatrix_pull(lhsA, lDG_dofs, lDG_dofs) lx = spsolve(lhsA, rhs.array()[lDG_dofs]) # print ">>> local solution lx", type(lx), lx local_tau = Function(DG) local_tau.vector()[lDG_dofs] = lx # print "div(tau)", assemble(inner(div(local_tau),div(local_tau))*dx(1)) # add up local fluxes tau_global.vector()[lDG_dofs] += lx # evaluate estimator # maybe TODO: re-define measure dx eq_est = assemble( inner(tau_global, tau_global) * dg0 * (dx(0)+dx(1)),\ form_compiler_parameters={'quadrature_degree': quadrature_degree}) # reorder according to cell ids eq_est = eq_est[DG0_dofs.values()].array() global_est = np.sqrt(np.sum(eq_est)) # eq_est_global = assemble( inner(tau_global, tau_global) * (dx(0)+dx(1)), form_compiler_parameters={'quadrature_degree': quadrature_degree} ) # global_est2 = np.sqrt(np.sum(eq_est_global)) return global_est, FlatVector(np.sqrt(eq_est))#, tau_global
def test_multiplication(self): print( '== testing multiplication of system matrix for problem of weighted projection ====' ) for dim, pol_order in itertools.product([2, 3], [1, 2]): N = 2 # no. of elements print('dim={0}, pol_order={1}, N={2}'.format(dim, pol_order, N)) # creating MESH and defining MATERIAL if dim == 2: mesh = UnitSquareMesh(N, N) m = Expression("1+10*16*x[0]*(1-x[0])*x[1]*(1-x[1])", degree=4) # material coefficients elif dim == 3: mesh = UnitCubeMesh(N, N, N) m = Expression("1+10*16*x[0]*(1-x[0])*(1-x[1])*x[2]", degree=1) # material coefficients mesh.coordinates()[:] += 0.1 * np.random.random( mesh.coordinates().shape) # mesh perturbation V = FunctionSpace(mesh, "CG", pol_order) # original FEM space W = FunctionSpace(mesh, "DG", 2 * (pol_order - 1)) # double-grid space print('assembling local matrices for DoGIP...') Bhat = get_Bhat( dim, pol_order, problem=1 ) # interpolation between V on W on a reference element AT_dogip = get_A_T(m, V, W, problem=1) dofmapV = V.dofmap() def system_multiplication_DoGIP(AT_dogip, Bhat, u_vec): # matrix-vector mutliplication in DoGIP Au = np.zeros_like(u_vec) for ii, cell in enumerate(cells(mesh)): ind = dofmapV.cell_dofs(ii) # local to global map Bu = Bhat.dot(u_vec[ind]) ABu = np.einsum('rsj,sj->rj', AT_dogip[ii], Bu) Au[ind] += np.einsum('rjl,rj->l', Bhat, ABu) return Au print('assembling system matrix for FEM') u, v = TrialFunction(V), TestFunction(V) Asp = assemble(m * inner(grad(u), grad(v)) * dx, tensor=EigenMatrix()) Asp = Asp.sparray() # sparse FEM matrix print('multiplication...') ur = Function(V) # creating random vector ur_vec = 10 * np.random.random(V.dim()) ur.vector().set_local(ur_vec) Au_DoGIP = system_multiplication_DoGIP( AT_dogip, Bhat, ur_vec) # DoGIP multiplication Auex = Asp.dot(ur_vec) # FEM multiplication with sparse matrix # testing the difference between DoGIP and FEniCS self.assertAlmostEqual(0, np.linalg.norm(Auex - Au_DoGIP)) print('...ok')