def fenics_solve(f): u = fn.Function(V, name="State") v = fn.TestFunction(V) F = (ufl.inner(ufl.grad(u), ufl.grad(v)) - f * v) * ufl.dx bcs = [fn.DirichletBC(V, 0.0, "on_boundary")] fn.solve(F == 0, u, bcs) return u, F, bcs
def project_gradient_neumann( f0, degree=None, mesh=None, solver_type='gmres', preconditioner_type='default' ): """Find an approximation to f0 that has the same gradient The resulting function also satisfies homogeneous Neumann boundary conditions. Parameters: f0: the function to approximate mesh=None: the mesh on which to approximate it If not provided, the mesh is extracted from f0. degree=None: degree of the polynomial approximation. extracted from f0 if not provided. solver_type='gmres': The linear solver type to use. preconditioner_type='default': Preconditioner type to use """ if not mesh: mesh = f0.function_space().mesh() element = f0.ufl_element() if not degree: degree = element.degree() CE = FiniteElement('CG', mesh.ufl_cell(), degree) CS = FunctionSpace(mesh, CE) DE = FiniteElement('DG', mesh.ufl_cell(), degree) DS = FunctionSpace(mesh, DE) CVE = VectorElement('CG', mesh.ufl_cell(), degree - 1) CV = FunctionSpace(mesh, CVE) RE = FiniteElement('R', mesh.ufl_cell(), 0) R = FunctionSpace(mesh, RE) CRE = MixedElement([CE, RE]) CR = FunctionSpace(mesh, CRE) f = fe.project(f0, CS, solver_type=solver_type, preconditioner_type=preconditioner_type) g = fe.project(fe.grad(f), CV, solver_type=solver_type, preconditioner_type=preconditioner_type) lf = fe.project(fe.nabla_div(g), CS, solver_type=solver_type, preconditioner_type=preconditioner_type) tf, tc = TrialFunction(CR) wf, wc = TestFunctions(CR) dx = Measure('dx', domain=mesh, metadata={'quadrature_degree': min(degree, 10)}) a = (fe.dot(fe.grad(tf), fe.grad(wf)) + tc * wf + tf * wc) * dx L = (f * wc - lf * wf) * dx igc = Function(CR) fe.solve(a == L, igc, solver_parameters={'linear_solver': solver_type, 'preconditioner': preconditioner_type} ) ig, c = igc.sub(0), igc.sub(1) igd = fe.project(ig, DS, solver_type=solver_type, preconditioner_type=preconditioner_type) return igd
def Newton_manual(F, vd, bcs, J, atol, rtol, max_it, lmbda\ , vd_res): #Reset counters Iter = 0 residual = 1 rel_res = residual while rel_res > rtol and residual > atol and Iter < max_it: A = assemble(J, keep_diagonal = True) A.ident_zeros() b = assemble(-F) [bc.apply(A, b, vd.vector()) for bc in bcs] #solve(A, vd_res.vector(), b, "superlu_dist") #solve(A, vd_res.vector(), b, "mumps") solve(A, vd_res.vector(), b) vd.vector().axpy(1., vd_res.vector()) [bc.apply(vd.vector()) for bc in bcs] rel_res = norm(vd_res, 'l2') residual = b.norm('l2') if MPI.rank(mpi_comm_world()) == 0: print "Newton iteration %d: r (atol) = %.3e (tol = %.3e), r (rel) = %.3e (tol = %.3e) " \ % (Iter, residual, atol, rel_res, rtol) Iter += 1 #Reset residual = 1 rel_res = residual Iter = 0 return vd
def Newton_manual(F, udp, bcs, atol, rtol, max_it, lmbda, udp_res, VVQ): #Reset counters Iter = 0 residual = 1 rel_res = residual dw = TrialFunction(VVQ) Jac = derivative(F, udp, dw) # Jacobi while rel_res > rtol and residual > atol and Iter < max_it: A = assemble(Jac) A.ident_zeros() b = assemble(-F) [bc.apply(A, b, udp.vector()) for bc in bcs] #solve(A, udp_res.vector(), b, "superlu_dist") solve(A, udp_res.vector(), b) #, "mumps") udp.vector()[:] = udp.vector()[:] + lmbda * udp_res.vector()[:] #udp.vector().axpy(1., udp_res.vector()) [bc.apply(udp.vector()) for bc in bcs] rel_res = norm(udp_res, 'l2') residual = b.norm('l2') if MPI.rank(mpi_comm_world()) == 0: print "Newton iteration %d: r (atol) = %.3e (tol = %.3e), r (rel) = %.3e (tol = %.3e) " \ % (Iter, residual, atol, rel_res, rtol) Iter += 1 return udp
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 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 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 solve(self, **arguments): t_start = time.clock() # definig Function space on this mesh using Lagrange #polynoimals of degree 1. H = FunctionSpace(self.mesh, "CG", 1) # Setting up the variational problem v = TrialFunction(H) w = TestFunction(H) epsilon = Constant(arguments[Components().Diffusion]) f = Constant(0) a = (epsilon * inner(grad(v), grad(w)) + inner(v, w)) * dx #Still have to figure it how to use a Neumann Condition here L = f * w * dx # solving the variational problem. v = Function(H) solve(a == L, v) self.solution.extend(v.vector().array()) return [self.solution, time.clock() - t_start]
def __call__(self, u_test, return_sol=False, return_permeability=False): # Variables x, y = sym.symbols('x[0], x[1]', real=True, positive=True) # Diffusivities diff_1 = np.exp(u_test[0]) diff_2 = np.exp(u_test[1]) # Interfaces ix = u_test[2] iy = u_test[3] # Diffusivity diff = sym.Piecewise((sym.Piecewise( (diff_1, y <= iy), (diff_2, True)), x <= ix), (diff_2, True)) # if return_permeability: # return sym.lambdify((x, y), diff) ccode_coeff = sym.ccode(diff) diff = fen.Expression(ccode_coeff, degree=2) if return_permeability: return diff # Define bilinear form in variational problem a_bil = diff * fen.dot(fen.grad(self.trial_f), fen.grad( self.test_f)) * fen.dx # Compute solution sol = fen.Function(self.f_space) fen.solve(a_bil == self.lin_func, sol, self.bound_cond) evaluations = [sol(xi, yi) for xi, yi in zip(self.x_obs, self.y_obs)] return sol if return_sol else np.array(evaluations)
def solve_pde(self): u = fe.Function(self.function_space) v = fe.TestFunction(self.function_space) u_old = fe.project(self.u_0, self.function_space) # Todo: Average right hand side if we choose it non-constant flux = self.dt * fe.dot( self.composed_diff_coef * (fe.grad(u) + self.drift_function(u)), fe.grad(v)) * fe.dx bilin_part = u * v * fe.dx + flux funtional_part = self.rhs * v * self.dt * fe.dx + u_old * v * fe.dx full_form = bilin_part - funtional_part num_steps = int(self.T / self.dt) + 1 bc = fe.DirichletBC(self.function_space, self.u_boundary, MembraneSimulator.full_boundary) for n in range(num_steps): print("Step %d" % n) self.time += self.dt fe.solve(full_form == 0, u, bc) # fe.plot(u) # plt.show() # print(fe.errornorm(u_old, u)) u_old.assign(u) self.file << (u, self.time) f = fe.plot(u) plt.rc('text', usetex=True) plt.colorbar(f, format='%.0e') plt.title(r'Macroscopic density profile of $u(x,t)$ at $t=1$') plt.xlabel(r'$x_1$') plt.ylabel(r'$x_2$') plt.show()
def run(self, fields: Fields): # res = fenics.assemble(self.L_form) # self.boundary_conditions[0].apply(res) # self.solver.solve(self.K, fields.u_new.vector(), res) # print('a') fenics.solve(self.a_form == self.L_form, fields.u_new, self.boundary_conditions[0])
def solver_nonlinear(G, d_, w_, wd_, bcs, T, dt, action=None, **namespace): dis_x = []; dis_y = []; time = [] solver_parameters = {"newton_solver": \ {"relative_tolerance": 1E-8, "absolute_tolerance": 1E-8, "maximum_iterations": 100, "relaxation_parameter": 1.0}} t = 0 while t <= T: solve(G == 0, wd_["n"], bcs, solver_parameters=solver_parameters) # Update solution times = ["n-3", "n-2", "n-1", "n"] for i, t_tmp in enumerate(times[:-1]): wd_[t_tmp].vector().zero() wd_[t_tmp].vector().axpy(1, wd_[times[i+1]].vector()) w_[t_tmp], d_[t_tmp] = wd_[t_tmp].split(True) # Get displacement if callable(action): action(wd_, t) t += dt if MPI.rank(mpi_comm_world()) == 0: print "Time: ", t
def solve(self, **arguments): t_start = time.clock() # definig Function space on this mesh using Lagrange #polynoimals of degree 1. H = FunctionSpace(self.mesh, "CG", 1) # Setting up the variational problem v = TrialFunction(H) w = TestFunction(H) epsilon = Constant(arguments[Components().Diffusion]) f = Expression("(1 - epsilon*4*pow(pi,2))*cos(2*pi*x[0])",\ epsilon=epsilon, degree=1) a = (epsilon * inner(grad(v), grad(w)) + inner(v, w)) * dx L = f * w * dx # solving the variational problem. v = Function(H) solve(a == L, v) self.solution.extend(v.vector().array()) return [self.solution, time.clock() - t_start]
def solve_problem(self): ''' Boundary conditions ''' fe.solve(self.bilinear_form == self.rhs,\ self.u, self.boundary_conditions)
def solver_nonlinear(G, d_, w_, wd_, bcs, T, dt, action=None, **namespace): dis_x = []; dis_y = []; time = [] solver_parameters = {"newton_solver": \ {"relative_tolerance": 1E-8, "absolute_tolerance": 1E-8, "maximum_iterations": 100, #"krylov_solver": {"monitor_convergence": True}, #"linear_solver": {"monitor_convergence": True}, "relaxation_parameter": 0.9}} t = 0 while t < (T - dt*DOLFIN_EPS): solve(G == 0, wd_["n"], bcs, solver_parameters=solver_parameters) # Update solution times = ["n-3", "n-2", "n-1", "n"] for i, t_tmp in enumerate(times[:-1]): wd_[t_tmp].vector().zero() wd_[t_tmp].vector().axpy(1, wd_[times[i+1]].vector()) w_[t_tmp], d_[t_tmp] = wd_[t_tmp].split(True) # Get displacement if callable(action): action(wd_, t) t += dt if MPI.rank(mpi_comm_world()) == 0: print "Time: ",t #,"dis_x: ", d(coord)[0], "dis_y: ", d(coord)[1] return dis_x, dis_y, time
def run_fokker_planck(nx, num_steps, t_0 = 0, t_final=10): # define mesh mesh = IntervalMesh(nx, -200, 200) # define function space. V = FunctionSpace(mesh, "Lagrange", 1) # Homogenous Neumann BCs don't have to be defined as they are the default in dolfin # define parameters. dt = (t_final-t_0) / num_steps # set mu and sigma mu = Constant(-1) D = Constant(1) # define initial conditions u_0 u_0 = Expression('x[0]', degree=1) # set U_n to be the interpolant of u_0 over the function space V. Note that # u_n is the value of u at the previous timestep, while u is the current value. u_n = interpolate(u_0, V) # Define variational problem u = TrialFunction(V) v = TestFunction(V) F = u*v*dx + dt*inner(D*grad(u), grad(v))*dx + dt*mu*grad(u)[0]*v*dx - inner(u_n, v)*dx # isolate the bilinear and linear forms. a, L = lhs(F), rhs(F) # initialize function to capture solution. t = 0 u_h = Function(V) plt.figure(figsize=(15, 15)) # time-stepping section for n in range(num_steps): t += dt # compute solution solve(a == L, u_h) u_n.assign(u_h) # Plot solutions intermittently if n % (num_steps // 10) == 0 and num_steps > 0: plot(u_h, label='t = %s' % t) plt.legend() plt.grid() plt.title("Finite Element Solutions to Fokker-Planck Equation with $\mu(x, t) = -(x+1)$ , $D(x, t) = e^t x^2$, $t_n$ = %s" % t_final) plt.ylabel("$u(x, t)$") plt.xlabel("x") plt.savefig("fpe/fokker-planck-solutions-mu.png") plt.clf() # return the approximate solution evaluated on the coordinates, and the actual coordinates. return u_n.compute_vertex_values(), mesh.coordinates()
def fenics_solve(u_prev, timestep): # Define and solve one step of the Burgers equation u = fn.Function(V) F = ( Dt(u, u_prev, timestep) * v + a * u * u.dx(0) * v + nu * u.dx(0) * v.dx(0) ) * ufl.dx fn.solve(F == 0, u, bcs) return u, F, bcs
def impl_dyn(w0, dt=1.e-5, t_end=1.e-4, show_plots=False): (u0, p0, v0) = fe.split(w0) bcs_u, bcs_p, bcs_v = load_2d_muscle_bc(V_upv.sub(0), V_upv.sub(1), V_upv.sub(2), boundaries) # Lagrange function (without constraint) (u1, p1, v1) = fe.TrialFunctions(V_upv) (eta, q, xi) = fe.TestFunctions(V_upv) F = deformation_grad(u1) I_1, I_2, J = invariants(F) F_iso = isochronic_deformation_grad(F, J) #I_1_iso, I_2_iso = invariants(F_iso)[0:2] W = material_mooney_rivlin(I_1, I_2, c_10, c_01) g = incompr_constr(J) L = -W P = first_piola_stress(L, F) G = incompr_stress(g, F) a_dyn_u = inner(u1 - u0, eta) * dx - dt * inner(v1, eta) * dx a_dyn_p = inner(g, q) * dx a_dyn_v = rho * inner(v1 - v0, xi) * dx + dt * (inner( P, grad(xi)) * dx + inner(p1 * G, grad(xi)) * dx - inner(B, xi) * dx) a = a_dyn_u + a_dyn_p + a_dyn_v w1 = fe.Function(V_upv) sol = [] t = 0 while t < t_end: print("progress: %f" % (100. * t / t_end)) fe.solve(a == 0, w1, bcs_u + bcs_p + bcs_v) if fe.norm(w1.vector()) > 1e7: print('ERROR: norm explosion') break # update initial values for next step w0.assign(w1) t += dt if show_plots: # plot result fe.plot(w0.sub(0), mode='displacement') plt.show() # save solutions sol.append(Solution(t=t)) sol[-1].upv.assign(w0) return sol, W, kappa
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 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 test_DoGIP_vs_FEniCS(self): print( '\n== testing DoGIP vs. FEniCS for problem of weighted projection ====' ) for dim, pol_order in itertools.product([2, 3], [1, 2]): print('dim={}; pol_order={}'.format(dim, pol_order)) N = 2 # creating MESH, defining MATERIAL and SOURCE if dim == 2: mesh = UnitSquareMesh(N, N) m = Expression("1+10*16*x[0]*(1-x[0])*x[1]*(1-x[1])", degree=3) # material coefficients f = Expression("x[0]*x[0]*x[1]", degree=2) elif dim == 3: mesh = UnitCubeMesh(N, N, N) m = Expression("1+100*x[0]*(1-x[0])*x[1]*x[2]", degree=2) # material coefficients f = Expression("(1-x[0])*x[1]*x[2]", degree=2) mesh.coordinates()[:] += 0.1 * np.random.random( mesh.coordinates().shape) # mesh perturbation ## standard approach with FEniCS ############################################# V = FunctionSpace(mesh, "CG", pol_order) # original FEM space u, v = TrialFunction(V), TestFunction(V) u_fenics = Function(V) solve(m * u * v * dx == m * f * v * dx, u_fenics) ## DoGIP - double-grid integration with interpolation-projection ############# W = FunctionSpace(mesh, "CG", 2 * pol_order) # double-grid space w = TestFunction(W) A_dogip = assemble( m * w * dx).get_local() # diagonal matrix of material coefficients b = assemble(m * f * v * dx) # vector of right-hand side # assembling interpolation-projection matrix B B = get_B(V, W, problem=0) # # linear solver on double grid, standard Afun = lambda x: B.T.dot(A_dogip * B.dot(x)) Alinoper = linalg.LinearOperator((V.dim(), V.dim()), matvec=Afun, dtype=np.float) x, info = linalg.cg(Alinoper, b.get_local(), x0=np.zeros(V.dim()), tol=1e-10, maxiter=1e3, callback=None) # testing the difference between DoGIP and FEniCS self.assertAlmostEqual( 0, np.linalg.norm(u_fenics.vector().get_local() - x)) print('...ok')
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 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 _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 solve(self, **arguments): t_start = time.clock() # definig Function space on this mesh using Lagrange #polynoimals of degree 1. H = FunctionSpace(self.mesh, "CG", 1) # Setting up the variational problem v = TrialFunction(H) w = TestFunction(H) coeff_dx2 = Constant(1) coeff_v = Constant(1) f = Expression("(4*pow(pi,2))*exp(-(1/coeff_v)*t)*sin(2*pi*x[0])", {'coeff_v': coeff_v}, degree=2) v0 = Expression("sin(2*pi*x[0])", degree=2) f.t = 0 def boundary(x, on_boundary): return on_boundary bc = DirichletBC(H, v0, boundary) v1 = interpolate(v0, H) dt = self.steps.time a = (dt * inner(grad(v), grad(w)) + dt * coeff_v * inner(v, w)) * dx L = (f * dt - coeff_v * v1) * w * dx A = assemble(a) v = Function(H) T = self.domain.time[-1] t = dt # solving the variational problem. while t <= T: b = assemble(L, tensor=b) vo.t = t bc.apply(A, b) solve(A, v.vector(), b) t += dt v1.assign(v) self.solution.extend(v.vector().array()) return [self.solution, time.clock() - t_start]
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 = fn.Function(V) F = L - ufl.action(a, u) fn.solve(a == L, u, bcs) return u, F, bcs
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 dynamic_solver_func(ncells=10, # количество узлов на заданном итервале init_time=0, # начальный момент времени end_time=10, # конечный момент времени dxdphi=1, # производная от потенциала по х dydphi=1, # производня от потенциала по у x0=0, # начальное положение по оси х vx0=1, # проекция начальной скорости на ось х y0=0, # начальное положение по оси у vy0=1): # проекция начальной скорости на ось у """ Функция на вход которой подается производная от потенциала гравитационного поля, возвращающая координаты смещенных материальных точек (частиц). """ # генерация сетки на заданном интервале времени mesh = fen.IntervalMesh(ncells, 0, end_time-init_time) welm = fen.MixedElement([fen.FiniteElement('Lagrange', fen.interval, 2), fen.FiniteElement('Lagrange', fen.interval, 2), fen.FiniteElement('Lagrange', fen.interval, 2), fen.FiniteElement('Lagrange', fen.interval, 2)]) # генерация функционального рростаанства W = fen.FunctionSpace(mesh, welm) # постановка начальных условий задачи bcsys = [fen.DirichletBC(W.sub(0), fen.Constant(x0), 'near(x[0], 0)'), fen.DirichletBC(W.sub(1), fen.Constant(vx0), 'near(x[0], 0)'), fen.DirichletBC(W.sub(2), fen.Constant(y0), 'near(x[0], 0)'), fen.DirichletBC(W.sub(3), fen.Constant(vy0), 'near(x[0], 0)')] # опееделение тестовых функций для решения задачи up = fen.Function(W) x_cor, v_x, y_cor, v_y = fen.split(up) v1, v2, v3, v4 = fen.split(fen.TestFunction(W)) # постановка задачи drdt = v; dvdt = - grad(phi) в проекциях на оси системы координат weak_form = (x_cor.dx(0) - v_x) * v1 * fen.dx + (v_x.dx(0) + dxdphi) * v2 * fen.dx \ + (y_cor.dx(0) - v_y) * v3 * fen.dx + (v_y.dx(0) + dydphi) * v4 * fen.dx # решние поставленной задачи fen.solve(weak_form == 0, up, bcs=bcsys) # определение момента времени time = fen.Point(end_time - init_time) # расчет координат и скоростей x_end_time = up(time.x())[0] vx_end_time = up(time.x())[1] y_end_time = up(time.x())[2] vy_end_time = up(time.x())[3] return x_end_time, y_end_time, vx_end_time, vy_end_time
def solve(self): """Evoke FEniCS FEM solver. Returns ------- uij : (Ni,) ndarray potential at Ni grid points nij : (M,Nij) ndarray concentrations of M species at Ni grid points lamj: (L,) ndarray value of L Lagrange multipliers """ # weak form and FEM scheme: # in the weak form, u and v are the trial and test functions associated # with the Poisson part, p and q the trial and test functions associated # with the Nernst-Planck part. lam and mu are trial and test fuctions # associated to constraints introduced via Lagrange multipliers. # w is the whole set of trial functions [u,p,lam] # W is the space all w live in. rho = 0 for i in range(self.M): rho += self.z[i] * self.p[i] source = -0.5 * rho * self.v * fn.dx laplace = fn.dot(fn.grad(self.u), fn.grad(self.v)) * fn.dx poisson = laplace + source nernst_planck = 0 for i in range(self.M): nernst_planck += fn.dot( -fn.grad(self.p[i]) - self.z[i] * self.p[i] * fn.grad(self.u), fn.grad(self.q[i])) * fn.dx # constraints set up elsewhere F = poisson + nernst_planck + self.constraints fn.solve(F == 0, self.w, self.boundary_conditions) # store results: wij = np.array([self.w(x) for x in self.X]).T self.uij = wij[0, :] # potential self.nij = wij[1:(self.M + 1), :] # concentrations self.lamj = wij[(self.M + 1):] # Lagrange multipliers return self.uij, self.nij, self.lamj
def determine_gradient(V_g, u, flux): """ compute flux following http://hplgit.github.io/INF5620/doc/pub/fenics_tutorial1.1/tu2.html#tut-poisson-gradu :param mesh :param u: solution where gradient is to be determined :return: """ w = TrialFunction(V_g) v = TestFunction(V_g) a = inner(w, v) * dx L = inner(grad(u), v) * dx solve(a == L, flux)
def main(): """Main function. Organizes workflow.""" fname = str(INPUTS['filename']) term = Terminal() print( term.yellow + "Working on file {}.".format(fname) + term.normal ) # Load mesh and physical domains from file. mesh = fe.Mesh(fname + ".xml") if INPUTS['saving']['mesh']: fe.File(fname + "_mesh.pvd") << mesh if INPUTS['plotting']['mesh']: fe.plot(mesh, title='Mesh') subdomains = fe.MeshFunction( 'size_t', mesh, fname + '_physical_region.xml') if INPUTS['saving']['subdomains']: fe.File(fname + "_subdomains.pvd") << subdomains if INPUTS['plotting']['subdomains']: fe.plot(subdomains, title='Subdomains') # function space for temperature/concentration func_space = fe.FunctionSpace( mesh, INPUTS['element_type'], INPUTS['element_degree'], constrained_domain=PeriodicDomain() ) # discontinuous function space for visualization dis_func_space = fe.FunctionSpace( mesh, 'DG', INPUTS['element_degree'], constrained_domain=PeriodicDomain() ) if ARGS['--verbose']: print('Number of cells:', mesh.num_cells()) print('Number of faces:', mesh.num_faces()) print('Number of edges:', mesh.num_edges()) print('Number of vertices:', mesh.num_vertices()) print('Number of DOFs:', len(func_space.dofmap().dofs())) # temperature/concentration field field = fe.TrialFunction(func_space) # test function test_func = fe.TestFunction(func_space) # function, which is equal to 1 everywhere unit_function = fe.Function(func_space) unit_function.assign(fe.Constant(1.0)) # assign material properties to each domain if INPUTS['mode'] == 'conductivity': mat_prop = SubdomainConstant( subdomains, fe.Constant(INPUTS['conductivity']['gas']), fe.Constant(INPUTS['conductivity']['solid']), degree=0 ) elif INPUTS['mode'] == 'diffusivity': mat_prop = SubdomainConstant( subdomains, fe.Constant(INPUTS['diffusivity']['gas']), fe.Constant(INPUTS['diffusivity']['solid']) * fe.Constant(INPUTS['solubility'] * gas_constant * INPUTS['temperature']), degree=0 ) # assign 1 to gas domain, and 0 to solid domain gas_content = SubdomainConstant( subdomains, fe.Constant(1.0), fe.Constant(0.0), degree=0 ) # define structure of foam over whole domain structure = fe.project(unit_function * gas_content, dis_func_space) # calculate porosity and wall thickness porosity = fe.assemble(structure * fe.dx) / ((XMAX - XMIN) * (YMAX - YMIN) * (ZMAX - ZMIN)) print('Porosity: {0}'.format(porosity)) dwall = wall_thickness( porosity, INPUTS['morphology']['cell_size'], INPUTS['morphology']['strut_content']) print('Wall thickness: {0} m'.format(dwall)) # calculate effective conductivity/diffusivity by analytical model if INPUTS['mode'] == 'conductivity': eff_prop = analytical_conductivity( INPUTS['conductivity']['gas'], INPUTS['conductivity']['solid'], porosity, INPUTS['morphology']['strut_content']) print('Analytical model: {0} W/(mK)'.format(eff_prop)) elif INPUTS['mode'] == 'diffusivity': eff_prop = analytical_diffusivity( INPUTS['diffusivity']['solid'] * INPUTS['solubility'], INPUTS['solubility'], porosity, INPUTS['morphology']['cell_size'], dwall, INPUTS['temperature'], INPUTS['morphology']['enhancement_par']) print('Analytical model: {0} m^2/s'.format(eff_prop)) # create system matrix system_matrix = -mat_prop * \ fe.inner(fe.grad(field), fe.grad(test_func)) * fe.dx left_side, right_side = fe.lhs(system_matrix), fe.rhs(system_matrix) # define boundary conditions bcs = [ fe.DirichletBC(func_space, fe.Constant( INPUTS['boundary_conditions']['top']), top_bc), fe.DirichletBC(func_space, fe.Constant( INPUTS['boundary_conditions']['bottom']), bottom_bc) ] # compute solution field = fe.Function(func_space) fe.solve(left_side == right_side, field, bcs) # output temperature/concentration at the boundaries if ARGS['--verbose']: print('Checking periodicity:') print('Value at XMIN:', field(XMIN, (YMIN + YMAX) / 3, (ZMIN + ZMAX) / 3)) print('Value at XMAX:', field(XMAX, (YMIN + YMAX) / 3, (ZMIN + ZMAX) / 3)) print('Value at YMIN:', field((XMIN + XMAX) / 3, YMIN, (ZMIN + ZMAX) / 3)) print('Value at YMAX:', field((XMIN + XMAX) / 3, YMAX, (ZMIN + ZMAX) / 3)) print('Value at ZMIN:', field((XMIN + XMAX) / 3, (YMIN + YMAX) / 3, ZMIN)) print('Value at ZMAX:', field((XMIN + XMAX) / 3, (YMIN + YMAX) / 3, ZMAX)) # calculate flux, and effective properties vec_func_space = fe.VectorFunctionSpace( mesh, INPUTS['element_type'], INPUTS['element_degree'] ) flux = fe.project(-mat_prop * fe.grad(field), vec_func_space) divergence = fe.project(-fe.div(mat_prop * fe.grad(field)), func_space) flux_x, flux_y, flux_z = flux.split() av_flux = fe.assemble(flux_z * fe.dx) / ((XMAX - XMIN) * (YMAX - YMIN)) eff_prop = av_flux * (ZMAX - ZMIN) / ( INPUTS['boundary_conditions']['top'] - INPUTS['boundary_conditions']['bottom'] ) if INPUTS['mode'] == 'conductivity': print('Numerical model: {0} W/(mK)'.format(eff_prop)) elif INPUTS['mode'] == 'diffusivity': print('Numerical model: {0} m^2/s'.format(eff_prop)) # projection of concentration has to be in discontinuous function space if INPUTS['mode'] == 'diffusivity': sol_field = SubdomainConstant( subdomains, fe.Constant(1.0), fe.Constant(INPUTS['solubility'] * gas_constant * INPUTS['temperature']), degree=0 ) field = fe.project(field * sol_field, dis_func_space) # save results with open(fname + "_eff_prop.csv", 'w') as textfile: textfile.write('eff_prop\n') textfile.write('{0}\n'.format(eff_prop)) fe.File(fname + "_solution.pvd") << field fe.File(fname + "_structure.pvd") << structure if INPUTS['saving']['flux']: fe.File(fname + "_flux.pvd") << flux if INPUTS['saving']['flux_divergence']: fe.File(fname + "_flux_divergence.pvd") << divergence if INPUTS['saving']['flux_components']: fe.File(fname + "_flux_x.pvd") << flux_x fe.File(fname + "_flux_y.pvd") << flux_y fe.File(fname + "_flux_z.pvd") << flux_z # plot results if INPUTS['plotting']['solution']: fe.plot(field, title="Solution") if INPUTS['plotting']['flux']: fe.plot(flux, title="Flux") if INPUTS['plotting']['flux_divergence']: fe.plot(divergence, title="Divergence") if INPUTS['plotting']['flux_components']: fe.plot(flux_x, title='x-component of flux (-kappa*grad(u))') fe.plot(flux_y, title='y-component of flux (-kappa*grad(u))') fe.plot(flux_z, title='z-component of flux (-kappa*grad(u))') if True in INPUTS['plotting'].values(): fe.interactive() print( term.yellow + "End." + term.normal )
def solve(self): # TODO: when FEniCS ported to Python3, this should be exist_ok try: os.makedirs('results') except OSError: pass z, w = (self.z, self.w) u0 = d.Constant(0.0) # Define the linear and bilinear forms L = u0 * w * dx # Define useful functions cond = d.Function(self.DV) U = d.Function(self.V) # Initialize the max_e vector, that will store the cumulative max e values max_e = d.Function(self.V) max_e.vector()[:] = 0.0 max_e.rename("max_E", "Maximum energy deposition by location") max_e_file = d.File("results/%s-max_e.pvd" % input_mesh) max_e_per_step = d.Function(self.V) max_e_per_step_file = d.File("results/%s-max_e_per_step.pvd" % input_mesh) self.es = {} self.max_es = {} fi = d.File("results/%s-cond.pvd" % input_mesh) potential_file = d.File("results/%s-potential.pvd" % input_mesh) # Loop through the voltages and electrode combinations for i, (anode, cathode, voltage) in enumerate(v.electrode_triples): print("Electrodes %d (%lf) -> %d (0)" % (anode, voltage, cathode)) cond = d.project(self.sigma_start, V=self.DV) # Define the Dirichlet boundary conditions on the active needles uV = d.Constant(voltage) term1_bc = d.DirichletBC(self.V, uV, self.patches, v.needles[anode]) term2_bc = d.DirichletBC(self.V, u0, self.patches, v.needles[cathode]) e = d.Function(self.V) e.vector()[:] = max_e.vector() # Re-evaluate conductivity self.increase_conductivity(cond, e) for j in range(v.max_restarts): # Update the bilinear form a = d.inner(d.nabla_grad(z), cond * d.nabla_grad(w)) * dx # Solve again print(" [solving...") d.solve(a == L, U, bcs=[term1_bc, term2_bc]) print(" ....solved]") # Extract electric field norm for k in range(len(U.vector())): if N.isnan(U.vector()[k]): U.vector()[k] = 1e5 e_new = d.project(d.sqrt(d.dot(d.grad(U), d.grad(U))), self.V) # Take the max of the new field and the established electric field e.vector()[:] = N.array([max(*X) for X in zip(e.vector(), e_new.vector())]) # Re-evaluate conductivity fi << cond self.increase_conductivity(cond, e) potential_file << U # Save the max e function to a VTU max_e_per_step.vector()[:] = e.vector()[:] max_e_per_step_file << max_e_per_step # Store this electric field norm, for this triple, for later reference self.es[i] = e # Store the max of this electric field norm and that for all previous triples max_e_array = N.array([max(*X) for X in zip(max_e.vector(), e.vector())]) max_e.vector()[:] = max_e_array # Create a new max_e function for storage, or it will be overwritten by the next iteration max_e_new = d.Function(self.V) max_e_new.vector()[:] = max_e_array # Store this max e function for the cumulative coverage curve calculation later self.max_es[i] = max_e_new # Save the max e function to a VTU max_e_file << max_e self.max_e_count = i