Caution
While this repository remains unarchived, I do not plan to continue development. Java, is not the optimal tool for this project. The code is available for anyone interested in exploring or building upon it.
APSiS was initially developed as a personal project to aid my coursework, leveraging Java as the language I was most familiar with at the time. This software was never meant to be a comprehensive, production-level solution but rather a functional exploration of advanced computational physics concepts.
- Element Topologies: Line, quadrilateral, and hexahedron.
- Efficient Mapping: Utilizes axis-aligned bounding boxes for fast Jacobian evaluations and high-order Lagrange interpolation for complex shapes.
-
Polynomial Approximation: Anisotropic high-order polynomial approximation up to
$p = 62$ based on integrated Legendre polynomials. -
Adaptive Mesh Refinement: Supports arbitrary local
$h$ -refinements using the multi-level hp method. - Advanced Quadrature: Implements quadrature rules suitable for immersed boundary computations as outlined in the Finite Cell Method.
- Boundary Conditions: Lacks weak boundary condition implementations for Dirichlet constraints within elements.
- Mesh I/O: Does not include mesh input/output capabilities, as FCM does not require them.
- PDE Solvers: APSiS is a framework for implementing PDE solvers but does not include any pre-built equations.
| Immersed Boundary Methods | High-Order Elements | Adaptive Mesh Refinement |
![]() |
![]() |
![]() |
gradle buildNo third-party libraries are required.
This example demonstrates how to use APSiS to solve the Laplace equation on a unit square
Solve:
with boundary conditions:
- Homogeneous Dirichlet conditions on the left, right, and bottom.
-
$u = \sin( \pi,x_0 )$ on the top boundary for$x_1 = 1$ .
- Define the Domain:
final var no_elements_x = 3;
final var no_elements_y = 3;
final var domain = new RectDomain(no_elements_x, no_elements_y, 0.0, 0.0, 1.0, 1.0);- Create the Approximation Field:
final var element_degree_x = 8;
final var element_degree_y = 8;
final var element_degrees = new int[][] { { element_degree_x, element_degree_y } };
final var field_u = new PieceWiseHighOrder("u", domain, 1, 1, true, element_degrees);- Apply Dirichlet Boundary Conditions:
final var dirichlet = new DirichletGlobalL2Projection();
dirichlet.apply(field_u, x -> new Vector(0.0), domain.boundary(RectDomain.LEFT), 0);
dirichlet.apply(field_u, x -> new Vector(0.0), domain.boundary(RectDomain.BOTTOM), 0);
dirichlet.apply(field_u, x -> new Vector(0.0), domain.boundary(RectDomain.RIGHT), 0);
dirichlet.apply(field_u, x -> new Vector(Math.sin(x.component(0) * Math.PI)), domain.boundary(RectDomain.TOP), 0);- Define the Bilinear Form:
final Bilinear bilinear = (v, u, x, q, Q, JxW, s) -> s[0][0] += v.gradient(q).dot(u.gradient(q)) * JxW;- Set Up Integration:
final var integrator = new BasicGaussLegendre(domain, element_degree_x + 1, element_degree_y + 1);
integrator.generate_quadrature_points();- Create Local System of Equations:
final var local_soe = new LocalSOE(field_u, StorageScheme.SYMMETRIC_DENSE);
integrator.integrate(bilinear, local_soe);- Assemble the Global System:
field_u.create_dof_enumerator();
field_u.dof_enumerator().enumerate();
final var N = field_u.dof_enumerator().no_unconstrained_dofs();
final var A = new SparseMatrix(N, N);
final var b = new Vector(N);
final var x = new Vector(N);
local_soe.assemble_system_matrix(A, false, false);
local_soe.assemble_system_vector(b, false, true);- Solve the System:
final var precond = new JacobiPreconditioner();
final var solver = new SolverPCG(1000, 1E-12, true, precond);
if (!solver.solve(A, b, x)) {
throw new RuntimeException("Solver did not converge!");
}
field_u.insert_solution(x);- Post-Process Results:
final var vtu_post = new VTUPostProcessor(domain, Math.max(element_degree_x, element_degree_y), 1, false, true, "solution.vtu");
vtu_post.add_point_processor(new SolutionProcessor(field_u));
vtu_post.add_point_processor(new SolutionGradientProcessor(field_u));
vtu_post.post_process();

Solution warped by factor 0.5 normal to the surface.
- Compute solution’s relative energy error:
final var reference_energy = 1.576674047468559;
final var numeric_energy = local_soe.energy();
final var relative_energy_error = sqrt(abs(reference_energy - numeric_energy) / abs(reference_energy)) * 100.0;For the given parameters this evaluates to



