def derivative(x: ndarray, basis1: GlobalBasis, basis0: GlobalBasis, i: Optional[int] = 0) -> ndarray: """Calculate the i'th partial derivative through projection. Parameters ---------- x The solution vector. basis1 The basis corresponding to the solution x (e.g. P_1). basis0 The basis corresponding to the derivative field (e.g. P_0). i Return i'th partial derivative. Returns ------- ndarray A new solution vector corresponding to the derivative. """ @bilinear_form def deriv(u, du, v, dv, w): return du[i] * v @bilinear_form def mass(u, du, v, dv, w): return u * v A = asm(deriv, basis1, basis0) M = asm(mass, basis0) return solve(M, A @ x)
def projection(fun, basis_to: Optional[Basis] = None, basis_from: Optional[Basis] = None, diff: Optional[int] = None, I: Optional[ndarray] = None, expand: bool = False) -> ndarray: """Perform projections onto a finite element basis. Parameters ---------- fun A solution vector or a function handle. basis_to The finite element basis to project to. basis_from The finite element basis to project from. diff Differentiate with respect to the given dimension. I Index set for limiting the projection to a subset. expand Passed to :func:`skfem.utils.condense`. Returns ------- ndarray The projected solution vector. """ @BilinearForm def mass(u, v, w): p = u * v return sum(p) if isinstance(basis_to.elem, ElementVector) else p @LinearForm def funv(v, w): p = fun(w.x) * v return sum(p) if isinstance(basis_to.elem, ElementVector) else p @BilinearForm def deriv(u, v, w): from skfem.helpers import grad du = grad(u) return du[diff] * v M = asm(mass, basis_to) if not isinstance(fun, ndarray): f = asm(funv, basis_to) else: if diff is not None: f = asm(deriv, basis_from, basis_to) @ fun else: f = asm(mass, basis_from, basis_to) @ fun if I is not None: return solve_linear(*condense(M, f, I=I, expand=expand)) return solve_linear(M, f)
def project(fun, basis_from: Basis = None, basis_to: Basis = None, diff: int = None, I: ndarray = None) -> ndarray: """Projection from one basis to another. Parameters ---------- fun A solution vector or a function handle. basis_from The finite element basis to project from. basis_to The finite element basis to project to. diff Differentiate with respect to the given dimension. I Index set for limiting the projection to a subset. Returns ------- ndarray The projected solution vector. """ @BilinearForm def mass(u, v, w): p = u * v return sum(p) if isinstance(basis_to.elem, ElementVectorH1) else p @LinearForm def funv(v, w): p = fun(*w.x) * v return sum(p) if isinstance(basis_to.elem, ElementVectorH1) else p @BilinearForm def deriv(u, v, w): from skfem.helpers import grad du = grad(u) return du[diff] * v M = asm(mass, basis_to) if not isinstance(fun, ndarray): f = asm(funv, basis_to) else: if diff is not None: f = asm(deriv, basis_from, basis_to) @ fun else: f = asm(mass, basis_from, basis_to) @ fun if I is not None: return solve(*condense(M, f, I=I, expand=False)) return solve(M, f)
def solve_problem1(m, element_type='P1', solver_type='pcg', intorder=6, tol=1e-8, epsilon=1e-6, basis_only=False): ''' switching to mgcg solver for problem 1 ''' if element_type == 'P1': element = {'w': ElementTriP1(), 'u': ElementTriMorley()} elif element_type == 'P2': element = {'w': ElementTriP2(), 'u': ElementTriMorley()} else: raise Exception("Element not supported") basis = { variable: InteriorBasis(m, e, intorder=intorder) for variable, e in element.items() } # intorder: integration order for quadrature if basis_only: return basis K1 = asm(laplace, basis['w']) f1 = asm(f_load, basis['w']) if solver_type == 'amg': wh = solve(*condense(K1, f1, D=basis['w'].find_dofs()), solver=solver_iter_pyamg(tol=tol)) elif solver_type == 'pcg': wh = solve(*condense(K1, f1, D=basis['w'].find_dofs()), solver=solver_iter_krylov(Precondition=True, tol=tol)) elif solver_type == 'mgcg': wh = solve(*condense(K1, f1, D=basis['w'].find_dofs()), solver=solver_iter_mgcg(tol=tol)) else: raise Exception("Solver not supported") K2 = epsilon**2 * asm(a_load, basis['u']) + asm(b_load, basis['u']) f2 = asm(wv_load, basis['w'], basis['u']) * wh if solver_type == 'amg': uh0 = solve(*condense(K2, f2, D=easy_boundary(m, basis['u'])), solver=solver_iter_pyamg(tol=tol)) elif solver_type == 'pcg': uh0 = solve(*condense(K2, f2, D=easy_boundary(m, basis['u'])), solver=solver_iter_krylov(Precondition=True, tol=tol)) elif solver_type == 'mgcg': uh0 = solve(*condense(K2, f2, D=easy_boundary(m, basis['u'])), solver=solver_iter_mgcg(tol=tol)) else: raise Exception("Solver not supported") return uh0, basis
def derivative(x, basis1, basis0, i=0): """Calculate the i'th partial derivative through projection.""" from skfem.assembly import asm, bilinear_form @bilinear_form def deriv(u, du, v, dv, w): return du[i] * v @bilinear_form def mass(u, du, v, dv, w): return u * v A = asm(deriv, basis1, basis0) M = asm(mass, basis0) return solve(M, A @ x)
def solve_problem2(m, element_type='P1', solver_type='pcg', intorder=6, tol=1e-8, epsilon=1e-6): ''' adding mgcg solver for problem 2 ''' if element_type == 'P1': element = {'w': ElementTriP1(), 'u': ElementTriMorley()} elif element_type == 'P2': element = {'w': ElementTriP2(), 'u': ElementTriMorley()} else: raise Exception("The element not supported") basis = { variable: InteriorBasis(m, e, intorder=intorder) for variable, e in element.items() } K1 = asm(laplace, basis['w']) f1 = asm(f_load, basis['w']) if solver_type == 'amg': wh = solve( *condense(K1, f1, D=basis['w'].find_dofs()), solver=solver_iter_pyamg(tol=tol)) elif solver_type == 'pcg': wh = solve(*condense(K1, f1, D=basis['w'].find_dofs()), solver=solver_iter_krylov(Precondition=True, tol=tol)) elif solver_type == 'mgcg': wh = solve( *condense(K1, f1, D=basis['w'].find_dofs()), solver=solver_iter_mgcg(tol=tol)) else: raise Exception("Solver not supported") fbasis = FacetBasis(m, element['u']) p1 = asm(penalty_1, fbasis) p2 = asm(penalty_2, fbasis) p3 = asm(penalty_3, fbasis) P = p1 + p2 + p3 K2 = epsilon**2 * asm(a_load, basis['u']) + \ epsilon**2 * P + asm(b_load, basis['u']) f2 = asm(wv_load, basis['w'], basis['u']) * wh if solver_type == 'amg': uh0 = solve(*condense(K2, f2, D=easy_boundary_penalty(m, basis['u'])), solver=solver_iter_pyamg(tol=tol)) elif solver_type == 'pcg': uh0 = solve(*condense(K2, f2, D=easy_boundary_penalty(m, basis['u'])), solver=solver_iter_krylov(Precondition=True, tol=tol)) elif solver_type == 'mgcg': uh0 = solve(*condense(K2, f2, D=easy_boundary_penalty(m, basis['u'])), solver=solver_iter_mgcg(tol=tol)) else: raise Exception("Solver not supported") return uh0, basis, fbasis
def L2_projection(fun, basis: GlobalBasis, ix: Optional[ndarray] = None) -> ndarray: """Initialize a solution vector with L2 projection. Parameters ---------- fun The function to project. basis The finite element basis ix Do the projection only on a subset of DOF's. Returns ------- ndarray The projected solution vector. """ if ix is None: ix = np.arange(basis.N) @bilinear_form def mass(u, du, v, dv, w): p = u * v return sum(p) if isinstance(basis.elem, ElementVectorH1) else p @linear_form def funv(v, dv, w): p = fun(*w.x) * v return sum(p) if isinstance(basis.elem, ElementVectorH1) else p M = asm(mass, basis) f = asm(funv, basis) return solve(*condense(M, f, I=ix))
def project(fun, basis_from: Basis = None, basis_to: Basis = None, diff: int = None, I: ndarray = None, expand: bool = False) -> ndarray: """Projection from one basis to another. Parameters ---------- fun A solution vector or a function handle. basis_from The finite element basis to project from. basis_to The finite element basis to project to. diff Differentiate with respect to the given dimension. I Index set for limiting the projection to a subset. expand Passed to :func:`skfem.utils.condense`. Returns ------- ndarray The projected solution vector. """ @BilinearForm def mass(u, v, w): p = u * v return sum(p) if isinstance(basis_to.elem, ElementVectorH1) else p @LinearForm def funv(v, w): if len(signature(fun).parameters) == 1: p = fun(w.x) * v else: warnings.warn( "The function provided to 'project' should " "take only one argument in the future.", DeprecationWarning) p = fun(*w.x) * v return sum(p) if isinstance(basis_to.elem, ElementVectorH1) else p @BilinearForm def deriv(u, v, w): from skfem.helpers import grad du = grad(u) return du[diff] * v M = asm(mass, basis_to) if not isinstance(fun, ndarray): f = asm(funv, basis_to) else: if diff is not None: f = asm(deriv, basis_from, basis_to) @ fun else: f = asm(mass, basis_from, basis_to) @ fun if I is not None: return solve(*condense(M, f, I=I, expand=expand)) return solve(M, f)