Spaces:
Sleeping
Sleeping
| """2D Poisson Equation Solver - 100% VENDOR IMPLEMENTATION | |
| Solves: -∆u = f in Ω, u = 0 on ∂Ω | |
| Using ONLY vendor libraries: | |
| - skfem: FE assembly | |
| - scipy.sparse: Linear algebra | |
| - matplotlib: Visualization | |
| ZERO custom FEM code. | |
| """ | |
| import numpy as np | |
| from scipy.sparse.linalg import spsolve | |
| import matplotlib.pyplot as plt | |
| # VENDOR: scikit-fem for ALL FEM operations | |
| import skfem | |
| from skfem.helpers import dot, grad | |
| def solve_poisson_vendor(): | |
| """Solve 2D Poisson using pure vendor APIs.""" | |
| print("=" * 60) | |
| print("2D Poisson Solver - VENDOR-ONLY Implementation") | |
| print("="*60) | |
| # STEP 1: Create mesh (skfem vendor) | |
| print("\n[1/5] Generating mesh with skfem.MeshTri...") | |
| mesh = skfem.MeshTri() | |
| mesh = mesh.refined(4) # Refine 4 times | |
| print(f" Nodes: {mesh.p.shape[1]}") | |
| print(f" Elements: {mesh.t.shape[1]}") | |
| # STEP 2: Define weak form (skfem vendor decorators) | |
| print("\n[2/5] Defining weak forms with @skfem.BilinearForm...") | |
| def laplacian(u, v, _): | |
| """Weak form of Laplacian using skfem.helpers.""" | |
| return dot(grad(u), grad(v)) | |
| def load(v, w): | |
| """Right-hand side f=1.""" | |
| return 1.0 * v | |
| # STEP 3: Assemble system (skfem vendor) | |
| print("\n[3/5] Assembling system with skfem.Basis...") | |
| basis = skfem.Basis(mesh, skfem.ElementTriP1()) | |
| K = laplacian.assemble(basis) # Returns scipy.sparse.csr_matrix | |
| F = load.assemble(basis) # Returns numpy array | |
| print(f" Stiffness matrix K: {K.shape}, nnz={K.nnz}") | |
| print(f" Load vector F: {F.shape}") | |
| # STEP 4: Apply BCs and solve (skfem + scipy vendors) | |
| print("\n[4/5] Applying BCs and solving with scipy.sparse.linalg...") | |
| # Get boundary DOFs (skfem vendor) | |
| dofs = basis.get_dofs() # All boundary nodes | |
| # Solve with BCs (skfem.condense + scipy.spsolve vendors) | |
| u = skfem.solve(*skfem.condense(K, F, D=dofs)) | |
| print(f" Solution u: min={u.min():.6f}, max={u.max():.6f}") | |
| # STEP 5: Visualize (matplotlib + skfem.visuals vendors) | |
| print("\n[5/5] Visualizing with skfem.visuals.matplotlib...") | |
| fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5)) | |
| # Plot solution using skfem vendor visualization | |
| skfem.visuals.matplotlib.plot( | |
| basis, u, ax=ax1, shading='gouraud', colorbar=True | |
| ) | |
| ax1.set_title('Solution u') | |
| ax1.set_xlabel('x') | |
| ax1.set_ylabel('y') | |
| # Plot mesh using skfem vendor | |
| skfem.visuals.matplotlib.draw(mesh, ax=ax2) | |
| ax2.set_title(f'Mesh ({mesh.t.shape[1]} elements)') | |
| ax2.set_xlabel('x') | |
| ax2.set_ylabel('y') | |
| plt.tight_layout() | |
| plt.savefig('poisson_solution_vendor.png', dpi=150) | |
| print(" Saved: poisson_solution_vendor.png") | |
| print("\n" + "="*60) | |
| print("SUCCESS: Solved using 100% vendor libraries") | |
| print(" - skfem: Mesh, basis, assembly, BCs") | |
| print(" - scipy.sparse: Linear solver") | |
| print(" - matplotlib: Visualization") | |
| print("="*60) | |
| return mesh, u, basis | |
| if __name__ == "__main__": | |
| mesh, u, basis = solve_poisson_vendor() | |
| # Additional vendor-based analysis | |
| print("\nVendor-based Analysis:") | |
| print(f" L2 norm of solution: {np.linalg.norm(u):.6f}") | |
| print(f" Mesh quality (min angle): {mesh.quality().min():.3f}") | |
| print(f" Basis dimension: {basis.N}") | |