use eyre::eyre;
use nalgebra::Vector1;
use fenris::assembly::global::{
apply_homogeneous_dirichlet_bc_csr, apply_homogeneous_dirichlet_bc_rhs, CsrAssembler, VectorAssembler,
};
use fenris::assembly::local::{
ElementEllipticAssemblerBuilder, ElementSourceAssemblerBuilder, SourceFunction, UniformQuadratureTable,
};
use fenris::assembly::operators::{LaplaceOperator, Operator};
use fenris::io::vtk::FiniteElementMeshDataSetBuilder;
use fenris::mesh::procedural::create_unit_square_uniform_quad_mesh_2d;
use fenris::mesh::QuadMesh2d;
use fenris::nalgebra::{DMatrix, DVector, Point2, U1, U2};
use fenris::nalgebra_sparse::CsrMatrix;
use fenris::quadrature;
fn main() -> eyre::Result<()> {
let mesh: QuadMesh2d<f64> = create_unit_square_uniform_quad_mesh_2d(4);
let (a, b) = assemble_linear_system(&mesh)?;
let u = solve_linear_system(&a, &b)?;
FiniteElementMeshDataSetBuilder::from_mesh(&mesh)
.with_title("Poisson 2D")
.with_point_scalar_attributes("u", 1, u.as_slice())
.try_export("poisson2d.vtu")?;
Ok(())
}
fn assemble_linear_system(mesh: &QuadMesh2d<f64>) -> eyre::Result<(CsrMatrix<f64>, DVector<f64>)> {
let (weights, points) = quadrature::tensor::quadrilateral_gauss(2);
let quadrature = UniformQuadratureTable::from_points_and_weights(points, weights);
let u = DVector::<f64>::zeros(mesh.vertices().len());
let vector_assembler = VectorAssembler::<f64>::default();
let matrix_assembler = CsrAssembler::default();
let laplace_assembler = ElementEllipticAssemblerBuilder::new()
.with_finite_element_space(mesh)
.with_operator(&LaplaceOperator)
.with_quadrature_table(&quadrature)
.with_u(&u)
.build();
let mut a_global = matrix_assembler.assemble(&laplace_assembler)?;
let source_assembler = ElementSourceAssemblerBuilder::new()
.with_finite_element_space(mesh)
.with_quadrature_table(&quadrature)
.with_source(&PoissonProblemSourceFunction)
.build();
let mut b_global = vector_assembler.assemble_vector(&source_assembler)?;
let dirichlet_nodes: Vec<_> = mesh
.vertices()
.iter()
.enumerate()
.filter_map(|(idx, v)| (v.x < 1e-12).then(|| idx))
.collect();
apply_homogeneous_dirichlet_bc_csr(&mut a_global, &dirichlet_nodes, 1);
apply_homogeneous_dirichlet_bc_rhs(&mut b_global, &dirichlet_nodes, 1);
Ok((a_global, b_global))
}
fn solve_linear_system(matrix: &CsrMatrix<f64>, rhs: &DVector<f64>) -> eyre::Result<DVector<f64>> {
let matrix = DMatrix::from(matrix);
let cholesky = matrix
.cholesky()
.ok_or_else(|| eyre!("Failed to solve linear system"))?;
Ok(cholesky.solve(rhs))
}
struct PoissonProblemSourceFunction;
impl Operator<f64, U2> for PoissonProblemSourceFunction {
type SolutionDim = U1;
type Parameters = ();
}
impl SourceFunction<f64, U2> for PoissonProblemSourceFunction {
fn evaluate(&self, _coords: &Point2<f64>, _data: &Self::Parameters) -> Vector1<f64> {
Vector1::new(1.0)
}
}