def vjp_solve_eval_impl( g: np.array, fenics_solution: fenics.Function, fenics_residual: ufl.Form, fenics_inputs: List[FenicsVariable], bcs: List[fenics.DirichletBC], ) -> Tuple[np.array]: """Computes the gradients of the output with respect to the inputs.""" # Convert tangent covector (adjoint) to a FEniCS variable adj_value = numpy_to_fenics(g, fenics_solution) adj_value = adj_value.vector() F = fenics_residual u = fenics_solution V = u.function_space() dFdu = fenics.derivative(F, u) adFdu = ufl.adjoint( dFdu, reordered_arguments=ufl.algorithms.extract_arguments(dFdu) ) u_adj = fenics.Function(V) adj_F = ufl.action(adFdu, u_adj) adj_F = ufl.replace(adj_F, {u_adj: fenics.TrialFunction(V)}) adj_F_assembled = fenics.assemble(adj_F) if len(bcs) != 0: for bc in bcs: bc.homogenize() hbcs = bcs for bc in hbcs: bc.apply(adj_F_assembled) bc.apply(adj_value) fenics.solve(adj_F_assembled, u_adj.vector(), adj_value) fenics_grads = [] for fenics_input in fenics_inputs: if isinstance(fenics_input, fenics.Function): V = fenics_input.function_space() dFdm = fenics.derivative(F, fenics_input, fenics.TrialFunction(V)) adFdm = fenics.adjoint(dFdm) result = fenics.assemble(-adFdm * u_adj) if isinstance(fenics_input, fenics.Constant): fenics_grad = fenics.Constant(result.sum()) else: # fenics.Function fenics_grad = fenics.Function(V, result) fenics_grads.append(fenics_grad) # Convert FEniCS gradients to jax array representation jax_grads = ( None if fg is None else np.asarray(fenics_to_numpy(fg)) for fg in fenics_grads ) jax_grad_tuple = tuple(jax_grads) return jax_grad_tuple
def __init__(me, V, max_smooth_vectors=50): R = fenics.FunctionSpace(V.mesh(), 'R', 0) u_trial = fenics.TrialFunction(V) v_test = fenics.TestFunction(V) c_trial = fenics.TrialFunction(R) d_test = fenics.TestFunction(R) a11 = fenics.inner(fenics.grad(u_trial), fenics.grad(v_test)) * fenics.dx a12 = c_trial * v_test * fenics.dx a21 = u_trial * d_test * fenics.dx A11 = convert_fenics_csr_matrix_to_scipy_csr_matrix( fenics.assemble(a11)) A12 = convert_fenics_csr_matrix_to_scipy_csr_matrix( fenics.assemble(a12)) A21 = convert_fenics_csr_matrix_to_scipy_csr_matrix( fenics.assemble(a21)) me.A = sps.bmat([[A11, A12], [A21, None]]).tocsc() solve_A = spla.factorized(me.A) m = u_trial * v_test * fenics.dx me.M = convert_fenics_csr_matrix_to_scipy_csr_matrix( fenics.assemble(m)).tocsc() solve_M = spla.factorized(me.M) def solve_neumann(f_vec): fe_vec = np.concatenate([f_vec, np.array([0])]) ue_vec = solve_A(fe_vec) u_vec = ue_vec[:-1] return u_vec me.solve_neumann_linop = spla.LinearOperator((V.dim(), V.dim()), matvec=solve_neumann) me.solve_M_linop = spla.LinearOperator((V.dim(), V.dim()), matvec=solve_M) ee, UU = spla.eigsh(me.solve_neumann_linop, k=max_smooth_vectors - 1, M=me.solve_M_linop, which='LM') me.U_smooth = np.zeros((V.dim(), max_smooth_vectors)) const_fct = np.ones(V.dim()) me.U_smooth[:, 0] = const_fct / np.sqrt( np.dot(const_fct, me.M * const_fct)) me.U_smooth[:, 1:] = solve_M(UU[:, ::-1]) me.k = 0
def __init__(self, K): # Variables x, y = sym.symbols('x[0], x[1]', real=True, positive=True) f = sym.Function('f')(x, y) grid = np.linspace(0, 1, K + 2)[1:-1] x_obs, y_obs = np.meshgrid(grid, grid) self.x_obs, self.y_obs = x_obs.reshape(K * K), y_obs.reshape(K * K) # --- THIS PART USED TO NOT BE PARALELLIZABLE --- # # Create mesh and define function space n_mesh = 80 self.mesh = fen.UnitSquareMesh(n_mesh, n_mesh) self.f_space = fen.FunctionSpace(self.mesh, 'P', 2) # Define boundary condition # u_boundary = fen.Expression('x[0] + x[1]', degree=2) u_boundary = fen.Expression('0', degree=2) self.bound_cond = fen.DirichletBC(self.f_space, u_boundary, lambda x, on_boundary: on_boundary) # Define variational problem self.trial_f = fen.TrialFunction(self.f_space) self.test_f = fen.TestFunction(self.f_space) rhs = fen.Constant(50) self.lin_func = rhs * self.test_f * fen.dx
def __setup_decrease_computation(self): """Initializes attributes and solver for the frobenius norm check. Returns ------- None """ if not self.angle_change > 0: raise ConfigError('MeshQuality', 'angle_change', 'This parameter has to be positive.') options = [[['ksp_type', 'preonly'], ['pc_type', 'jacobi'], ['pc_jacobi_type', 'diagonal'], ['ksp_rtol', 1e-16], ['ksp_atol', 1e-20], ['ksp_max_it', 1000]]] self.ksp_frobenius = PETSc.KSP().create() _setup_petsc_options([self.ksp_frobenius], options) self.trial_dg0 = fenics.TrialFunction(self.form_handler.DG0) self.test_dg0 = fenics.TestFunction(self.form_handler.DG0) if not (self.angle_change == float('inf')): self.search_direction_container = fenics.Function( self.form_handler.deformation_space) self.a_frobenius = self.trial_dg0 * self.test_dg0 * self.dx self.L_frobenius = fenics.sqrt( fenics.inner(fenics.grad(self.search_direction_container), fenics.grad(self.search_direction_container)) ) * self.test_dg0 * self.dx
def run(self): domain = self._create_domain() mesh = generate_mesh(domain, MESH_PTS) # fe.plot(mesh) # plt.show() self._create_boundary_expression() Omega = fe.FiniteElement("Lagrange", mesh.ufl_cell(), 1) R = fe.FiniteElement("Real", mesh.ufl_cell(), 0) W = fe.FunctionSpace(mesh, Omega*R) Theta, c = fe.TrialFunction(W) v, d = fe.TestFunctions(W) sigma = self.conductivity LHS = (sigma * fe.inner(fe.grad(Theta), fe.grad(v)) + c*v + Theta*d) * fe.dx RHS = self.boundary_exp * v * fe.ds w = fe.Function(W) fe.solve(LHS == RHS, w) Theta, c = w.split() print(c(0, 0)) # fe.plot(Theta, "solution", mode='color', vmin=-3, vmax=3) # plt.show() plot(fe.interpolate(Theta, fe.FunctionSpace(mesh, Omega)), mode='color') plt.show()
def eva(self, num): # construct basis functions, Set num points corresponding to num basis functions basPoints = np.linspace(0, 1, num) dx = basPoints[1] - basPoints[0] aa, bb, cc = -dx, 0.0, dx for x_p in basPoints: self.theta.append( fe.interpolate( fe.Expression( 'x[0] < a || x[0] > c ? 0 : (x[0] >=a && x[0] <= b ? (x[0]-a)/(b-a) : 1-(x[0]-b)/(c-b))', degree=2, a=aa, b=bb, c=cc), self.Vc)) aa, bb, cc = aa + dx, bb + dx, cc + dx u_trial, u_test = fe.TrialFunction(self.Vu), fe.TestFunction(self.Vu) left = fe.inner(self.al * fe.nabla_grad(u_trial), fe.nabla_grad(u_test)) * fe.dx right = self.f * u_test * fe.dx def boundaryD(x, on_boundary): return on_boundary and fe.near(x[1], 1.0) for i in range(num): uH = fe.Function(self.Vu) bcD = fe.DirichletBC(self.Vu, self.theta[i], boundaryD) left_m, right_m = fe.assemble_system(left, right, bcD) fe.solve(left_m, uH.vector(), right_m) self.sol.append(uH)
def _assemble(self) -> Tuple[fenics.PETScMatrix, fenics.PETScMatrix]: """Construct matrices for generalized eigenvalue problem. Assemble the left and the right hand side of the eigenfunction equation into the corresponding matrices. Returns ------- A : fenics.PETScMatrix Matrix corresponding to the form $a(u, v)$. B : fenics.PETScMatrix Matrix corresponding to the form $b(u, v)$. """ V = self.vector_space u = fenics.TrialFunction(V) v = fenics.TestFunction(V) a, b = self._construct_eigenproblem(u, v) A = fenics.PETScMatrix() B = fenics.PETScMatrix() fenics.assemble(a * fenics.dx, tensor=A) fenics.assemble(b * fenics.dx, tensor=B) return A, B
def solver(f, u_D, bc_funs, ndim, length, nx, ny, nz=None, degree=1): """Fenics 求解器 Args: f (Expression): [description] u_D (Expression): [description] bc_funs (List[Callable]): [description] ndim (int): [description] length (float): [description] nx (int): [description] ny (int): [description] nz (int, optional): [description]. Defaults to None. degree (int, optional): [description]. Defaults to 1. Returns: Function: 解 u """ mesh = get_mesh(length, nx, ny, nz) V = fs.FunctionSpace(mesh, "P", degree) bcs = [fs.DirichletBC(V, u_D, bc) for bc in bc_funs] u = fs.TrialFunction(V) v = fs.TestFunction(V) FF = fs.dot(fs.grad(u), fs.grad(v)) * fs.dx - f * v * fs.dx a = fs.lhs(FF) L = fs.rhs(FF) u = fs.Function(V) fs.solve(a == L, u, bcs) return u
def generate_mesh(self, typ, order, resolution): self._mesh = mshr.generate_mesh(self._domain, resolution) self.input['mesh'] = self._mesh self._V = FEN.FunctionSpace(self._mesh, typ, order) self.input['V'] = self._V self._u = FEN.TrialFunction(self._V) self._v = FEN.TestFunction(self._V)
def _make_variational_problem(V): """ Formulate the variational problem a(u, v) = L(v). Parameters ---------- V: FEniCS.FunctionSpace Returns ------- a, L: FEniCS.Expression Variational forms. """ # Define trial and test functions u = F.TrialFunction(V) v = F.TestFunction(V) # Collect Neumann conditions ds = F.Measure("ds", domain=mesh, subdomain_data=boundary_markers) integrals_N = [] for i in boundary_conditions: if isinstance(boundary_conditions[i], dict): if "Neumann" in boundary_conditions[i]: if boundary_conditions[i]["Neumann"] != 0: g = boundary_conditions[i]["Neumann"] integrals_N.append(g[0] * v * ds(i)) # Define variational problem a = F.inner(u, v) * F.dx + (DT**2) * (C**2) * F.inner( F.grad(u), F.grad(v)) * F.dx L = ((DT**2) * f[0] + 2 * u_nm1 - u_nm2) * v * F.dx + (DT**2) * (C**2) * sum(integrals_N) return a, L
def __call__(self, mesh, V=None, Vc=None): boundaries, boundarymarkers, domainmarkers, dx, ds, V, Vc = SetupUnitMeshHelper( mesh, V, Vc) self._ds_markers = boundarymarkers self._dx_markers = domainmarkers self._dx = dx self._ds = ds self._boundaries = boundaries self._subdomains = self._boundaries u = df.TrialFunction(V) v = df.TestFunction(V) alpha = df.Function(Vc, name='conductivity') alpha.vector()[:] = 1 def set_alpha(x): alpha.vector()[:] = x self._set_alpha = set_alpha a = alpha * df.inner(df.grad(u), df.grad(v)) * dx return a, set_alpha, alpha, V, Vc
def setup_vectorspace(mesh): """setup""" V = fe.VectorFunctionSpace(mesh, "CG", 1, dim=3) v = fe.TestFunction(V) u = fe.TrialFunction(V) m = fe.Function(V) Heff = fe.Function(V) return m, Heff, u, v, V
def geneForwardMatrix(self, q_fun=fe.Constant(0.0), fR=fe.Constant(0.0), \ fI=fe.Constant(0.0)): if self.haveFunctionSpace == False: self.geneFunctionSpace() xx, yy, dPML, sig0_, p_ = self.domain.xx, self.domain.yy, self.domain.dPML,\ self.domain.sig0, self.domain.p # define the coefficents induced by PML sig1 = fe.Expression('x[0] > x1 && x[0] < x1 + dd ? sig0*pow((x[0]-x1)/dd, p) : (x[0] < 0 && x[0] > -dd ? sig0*pow((-x[0])/dd, p) : 0)', degree=3, x1=xx, dd=dPML, sig0=sig0_, p=p_) sig2 = fe.Expression('x[1] > x2 && x[1] < x2 + dd ? sig0*pow((x[1]-x2)/dd, p) : (x[1] < 0 && x[1] > -dd ? sig0*pow((-x[1])/dd, p) : 0)', degree=3, x2=yy, dd=dPML, sig0=sig0_, p=p_) sR = fe.as_matrix([[(1+sig1*sig2)/(1+sig1*sig1), 0.0], [0.0, (1+sig1*sig2)/(1+sig2*sig2)]]) sI = fe.as_matrix([[(sig2-sig1)/(1+sig1*sig1), 0.0], [0.0, (sig1-sig2)/(1+sig2*sig2)]]) cR = 1 - sig1*sig2 cI = sig1 + sig2 # define the coefficients with physical meaning angl_fre = self.kappa*np.pi angl_fre2 = fe.Constant(angl_fre*angl_fre) # define equations u_ = fe.TestFunction(self.V) du = fe.TrialFunction(self.V) u_R, u_I = fe.split(u_) duR, duI = fe.split(du) def sigR(v): return fe.dot(sR, fe.nabla_grad(v)) def sigI(v): return fe.dot(sI, fe.nabla_grad(v)) F1 = - fe.inner(sigR(duR)-sigI(duI), fe.nabla_grad(u_R))*(fe.dx) \ - fe.inner(sigR(duI)+sigI(duR), fe.nabla_grad(u_I))*(fe.dx) \ - fR*u_R*(fe.dx) - fI*u_I*(fe.dx) a2 = fe.inner(angl_fre2*q_fun*(cR*duR-cI*duI), u_R)*(fe.dx) \ + fe.inner(angl_fre2*q_fun*(cR*duI+cI*duR), u_I)*(fe.dx) \ # define boundary conditions def boundary(x, on_boundary): return on_boundary bc = [fe.DirichletBC(self.V.sub(0), fe.Constant(0.0), boundary), \ fe.DirichletBC(self.V.sub(1), fe.Constant(0.0), boundary)] a1, L1 = fe.lhs(F1), fe.rhs(F1) self.u = fe.Function(self.V) self.A1 = fe.assemble(a1) self.b1 = fe.assemble(L1) self.A2 = fe.assemble(a2) bc[0].apply(self.A1, self.b1) bc[1].apply(self.A1, self.b1) bc[0].apply(self.A2) bc[1].apply(self.A2) self.A = self.A1 + self.A2
def _solve_pde(self, diff_coef): # Actual PDE solver for any coefficient diff_coef u = fe.TrialFunction(self.function_space) v = fe.TestFunction(self.function_space) a = fe.dot(diff_coef * fe.grad(u), fe.grad(v)) * fe.dx L = self.f * v * fe.dx bc = fe.DirichletBC(self.function_space, self.bc_function, PoissonSolver.boundary) fe.solve(a == L, self.solution, bc)
def solve_problem_variational_form(self): u = fa.Function(self.V) du = fa.TrialFunction(self.V) v = fa.TestFunction(self.V) E = self._energy_density(u) * fa.dx dE = fa.derivative(E, u, v) jacE = fa.derivative(dE, u, du) fa.solve(dE == 0, u, self.bcs, J=jacE) return u
def fenics_p_electric(self, my_d): """ @description: Solve poisson equation to get potential and electric field @Modify: 2021/08/31 """ if "plugin3D" in self.det_model: bc_l = [] bc_l = self.boundary_definition_3D(my_d, "Possion") elif "planar3D" in self.det_model: bc_l = self.boundary_definition_2D(my_d, "Possion") u = fenics.TrialFunction(self.V) v = fenics.TestFunction(self.V) if self.det_dic['name'] == "lgad3D": if self.det_dic['part'] == 2: bond = self.det_dic['bond1'] doping_avalanche = self.f_value(my_d, self.det_dic['doping1']) doping = self.f_value(my_d, self.det_dic['doping2']) f = fenics.Expression('x[2] < width ? doping1 : doping2', degree=1, width=bond, doping1=doping_avalanche, doping2=doping) elif self.det_dic['part'] == 3: bond1 = self.det_dic['bond1'] bond2 = self.det_dic['bond2'] doping1 = self.f_value(my_d, self.det_dic['doping1']) doping2 = self.f_value(my_d, self.det_dic['doping2']) doping3 = self.f_value(my_d, self.det_dic['doping3']) f = fenics.Expression( 'x[2] < bonda ? dopinga : x[2] > bondb ? dopingc : dopingb', degree=1, bonda=bond1, bondb=bond2, dopinga=doping1, dopingb=doping2, dopingc=doping3) else: print("The structure of lgad is wrong.") else: f = fenics.Constant(self.f_value(my_d)) a = fenics.dot(fenics.grad(u), fenics.grad(v)) * fenics.dx L = f * v * fenics.dx # Compute solution self.u = fenics.Function(self.V) fenics.solve(a == L, self.u, bc_l, solver_parameters=dict(linear_solver='gmres', preconditioner='ilu')) #calculate electric field W = fenics.VectorFunctionSpace(self.mesh3D, 'P', 1) self.E_field = fenics.project( fenics.as_vector((self.u.dx(0), self.u.dx(1), self.u.dx(2))), W)
def forward(x): u = fn.TrialFunction(V) w = fn.TestFunction(V) sigma = lmbda * tr(sym(grad(u))) * Identity(2) + 2 * G * sym( grad(u)) # Stress R = simp(x) * inner(sigma, grad(w)) * dx - dot(b, w) * dx a, L = ufl.lhs(R), ufl.rhs(R) u = fa.Function(V) fa.solve(a == L, u, bcs) return u
def compute_operators(self): u = fa.TrialFunction(self.V) v = fa.TestFunction(self.V) form_a = fa.inner(fa.grad(u), fa.grad(v)) * fa.dx form_b = u * v * fa.dx A = da.assemble(form_a) B = da.assemble(form_b) A_np = np.array(A.array()) B_np = np.array(B.array()) return A_np, B_np
def test_empty_measure(): mesh, _, _, dx, ds, dS = cashocs.regular_mesh(5) V = fenics.FunctionSpace(mesh, 'CG', 1) dm = cashocs.utils.EmptyMeasure(dx) trial = fenics.TrialFunction(V) test = fenics.TestFunction(V) assert fenics.assemble(1 * dm) == 0.0 assert (fenics.assemble(test * dm).norm('linf')) == 0.0 assert (fenics.assemble(trial * test * dm).norm('linf')) == 0.0
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 create_bilinear_form_and_rhs(self): # Define variational problem u = fe.TrialFunction(self.function_space) v = fe.TestFunction(self.function_space) self.bilinear_form = (1 + self.lam * self.dt) *\ (u * v * fe.dx) + self.dt * self.diffusion_coefficient *\ (fe.dot(fe.grad(u), fe.grad(v)) * fe.dx) self.rhs = (self.u_n + self.dt * self.rhs_fun * self.u_n) * v * fe.dx
def _solve_cell_problems(self): # Solves the cell problems (one for each space dimension) w = fe.TrialFunction(self.function_space) v = fe.TestFunction(self.function_space) a = self.a_y * fe.dot(fe.grad(w), fe.grad(v)) * fe.dx for i in range(self.dim): L = fe.div(self.a_y * self.e_is[i]) * v * fe.dx bc = fe.DirichletBC(self.function_space, self.bc_function, PoissonSolver.boundary) fe.solve(a == L, self.cell_solutions[i], bc) fe.plot(self.cell_solutions[i])
def mesh_gen_default(self, intervals, typ='P', order=1): """ creates a square with sides of 1, divided by intervals by default the type of the volume associated with the mesh is considered to be Lagrangian, with order 1. """ self._mesh = FEN.UnitSquareMesh(intervals, intervals) self.input['mesh'] = self._mesh self._V = FEN.FunctionSpace(self._mesh, typ, order) self.input['V'] = self._V self._u = FEN.TrialFunction(self._V) self._v = FEN.TestFunction(self._V)
def calTrueSol(para): nx, ny = para['mesh_N'][0], para['mesh_N'][1] mesh = fe.UnitSquareMesh(nx, ny) Vu = fe.FunctionSpace(mesh, 'P', para['P']) Vc = fe.FunctionSpace(mesh, 'P', para['P']) al = fe.Constant(para['alpha']) f = fe.Expression(para['f'], degree=5) q1 = fe.interpolate(fe.Expression(para['q1'], degree=5), Vc) q2 = fe.interpolate(fe.Expression(para['q2'], degree=5), Vc) q3 = fe.interpolate(fe.Expression(para['q3'], degree=5), Vc) theta = fe.interpolate(fe.Expression(para['q4'], degree=5), Vc) class BoundaryX0(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[0], 0.0) class BoundaryX1(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[0], 1.0) class BoundaryY0(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[1], 0.0) class BoundaryY1(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[1], 1.0) boundaries = fe.MeshFunction('size_t', mesh, mesh.topology().dim() - 1) boundaries.set_all(0) bc0, bc1, bc2, bc3 = BoundaryX0(), BoundaryX1(), BoundaryY0(), BoundaryY1() bc0.mark(boundaries, 1) bc1.mark(boundaries, 2) bc2.mark(boundaries, 3) bc3.mark(boundaries, 4) domains = fe.MeshFunction("size_t", mesh, mesh.topology().dim()) domains.set_all(0) bcD = fe.DirichletBC(Vu, theta, boundaries, 4) dx = fe.Measure('dx', domain=mesh, subdomain_data=domains) ds = fe.Measure('ds', domain=mesh, subdomain_data=boundaries) u_trial, u_test = fe.TrialFunction(Vu), fe.TestFunction(Vu) u = fe.Function(Vu) left = fe.inner(al * fe.nabla_grad(u_trial), fe.nabla_grad(u_test)) * dx right = f * u_test * dx + (q1 * u_test * ds(1) + q2 * u_test * ds(2) + q3 * u_test * ds(3)) left_m, right_m = fe.assemble_system(left, right, bcD) fe.solve(left_m, u.vector(), right_m) return u
def solve_problem_weak_form(self): u = fa.Function(self.V) du = fa.TrialFunction(self.V) v = fa.TestFunction(self.V) F = fa.inner(fa.grad(u), fa.grad(v)) * fa.dx - self.source * v * fa.dx J = fa.derivative(F, u, du) # The problem in this case is indeed linear, but using a nonlinear # solver doesn't hurt problem = fa.NonlinearVariationalProblem(F, u, self.bcs, J) solver = fa.NonlinearVariationalSolver(problem) solver.solve() return u
def solve_poisson_problem(mesh, boundary_values_expression, forcing_function): """ Solve the Poisson problem with P2 elements. """ V = fenics.FunctionSpace(mesh, "P", 2) u, v = fenics.TrialFunction(V), fenics.TestFunction(V) solution = fenics.Function(V) fenics.solve( fenics.dot(fenics.grad(v), fenics.grad(u)) * fenics.dx == v * forcing_function * fenics.dx, solution, fenics.DirichletBC(V, boundary_values_expression, boundary)) return solution
def solve_problem_matrix_approach(self): u = fa.TrialFunction(self.V) v = fa.TestFunction(self.V) a = fa.inner(fa.grad(u), fa.grad(v)) * fa.dx L = self.source * v * fa.dx # equivalent to solve(a == L, U, b) A = fa.assemble(a) b = fa.assemble(L) [bc.apply(A, b) for bc in self.bcs] u = fa.Function(self.V) U = u.vector() fa.solve(A, U, b) return u
def __init__(self, N, K): # Variables x, y = sym.symbols('x[0], x[1]', real=True, positive=True) f = sym.Function('f')(x, y) # Precision (inverse covariance) operator, when α = 1 tau, alpha = 3, 2 precision = (-sym.diff(f, x, x) - sym.diff(f, y, y) + tau**2 * f) indices = [(m, n) for m in range(0, N) for n in range(0, N)] # indices = indices[:-1] self.indices = sorted(indices, key=max) eig_f = [ sym.cos(i[0] * sym.pi * x) * sym.cos(i[1] * sym.pi * y) for i in self.indices ] # Eigenvalues of the covariance operator self.eig_v = [ 1 / (precision.subs(f, e).doit() / e).simplify()**alpha for e in eig_f ] grid = np.linspace(0, 1, K + 2)[1:-1] x_obs, y_obs = np.meshgrid(grid, grid) self.x_obs, self.y_obs = x_obs.reshape(K * K), y_obs.reshape(K * K) # Basis_functions self.functions = [ f * np.sqrt(float(v)) for f, v in zip(eig_f, self.eig_v) ] # --- THIS PART USED TO NOT BE PARALELLIZABLE --- # # Create mesh and define function space n_mesh = 80 mesh = fen.UnitSquareMesh(n_mesh, n_mesh) self.f_space = fen.FunctionSpace(mesh, 'P', 2) # Define boundary condition # u_boundary = fen.Expression('x[0] + x[1]', degree=2) u_boundary = fen.Expression('0', degree=2) self.bound_cond = fen.DirichletBC(self.f_space, u_boundary, lambda x, on_boundary: on_boundary) # Define variational problem self.trial_f = fen.TrialFunction(self.f_space) self.test_f = fen.TestFunction(self.f_space) rhs = fen.Constant(50) # rhs = fen.Expression('sin(x[0])*sin(x[1])', degree=2) self.lin_func = rhs * self.test_f * fen.dx
def xest_second_tutorial(self): T = 2.0 # final time num_steps = 50 # number of time steps dt = T / num_steps # time step size # Create mesh and define function space nx = ny = 30 mesh = fenics.RectangleMesh(fenics.Point(-2, -2), fenics.Point(2, 2), nx, ny) V = fenics.FunctionSpace(mesh, 'P', 1) # Define boundary condition def boundary(x, on_boundary): return on_boundary bc = fenics.DirichletBC(V, fenics.Constant(0), boundary) # Define initial value u_0 = fenics.Expression('exp(-a*pow(x[0], 2) - a*pow(x[1], 2))', degree=2, a=5) u_n = fenics.interpolate(u_0, V) # Define variational problem u = fenics.TrialFunction(V) v = fenics.TestFunction(V) f = fenics.Constant(0) F = u * v * fenics.dx + dt * fenics.dot(fenics.grad(u), fenics.grad( v)) * fenics.dx - (u_n + dt * f) * v * fenics.dx a, L = fenics.lhs(F), fenics.rhs(F) # Create VTK file for saving solution vtkfile = fenics.File( os.path.join(os.path.dirname(__file__), 'output', 'heat_gaussian', 'solution.pvd')) # Time-stepping u = fenics.Function(V) t = 0 not_initialised = True for n in range(num_steps): # Update current time t += dt # Compute solution fenics.solve(a == L, u, bc) # Save to file and plot solution vtkfile << (u, t) # Here we'll need to call tripcolor ourselves to get access to the color range fenics.plot(u) animation_camera.snap() u_n.assign(u) animation = animation_camera.animate() animation.save( os.path.join(os.path.dirname(__file__), 'output', 'heat_gaussian.mp4'))
def solve_initial_problem_v2(self): V = fn.FunctionSpace(self.mesh, 'Lagrange', 2) # Define test and trial functions. v = fn.TestFunction(V) u = fn.TrialFunction(V) # Define radial coordinates. r = fn.SpatialCoordinate(self.mesh)[0] # Define the relative permittivity. class relative_perm(fn.UserExpression): def __init__(self, markers, subdomain_ids, **kwargs): super().__init__(**kwargs) self.markers = markers self.subdomain_ids = subdomain_ids def eval_cell(self, values, x, cell): if self.markers[cell.index] == self.subdomain_ids['Vacuum']: values[0] = 1. else: values[0] = 10. rel_perm = relative_perm(self.subdomains, self.subdomains_ids, degree=0) # Define the variational form. a = r * rel_perm * fn.inner(fn.grad(u), fn.grad(v)) * self.dx L = fn.Constant(0.) * v * self.dx # Define the boundary conditions. bc1 = fn.DirichletBC(V, fn.Constant(0.), self.boundaries, self.boundaries_ids['Bottom_Wall']) bc4 = fn.DirichletBC(V, fn.Constant(-10.), self.boundaries, self.boundaries_ids['Top_Wall']) bcs = [bc1, bc4] # Solve the problem. init_phi = fn.Function(V) fn.solve(a == L, init_phi, bcs) return Poisson.block_project(init_phi, self.mesh, self.restrictions_dict['vacuum_rtc'], self.subdomains, self.subdomains_ids['Vacuum'], space_type='scalar')