A Java 17 repository focused on numerical simulation and visualization of: partial differential equations (PDEs) and ordinary differential equations (ODEs). The project includes two complete, end-to-end examples implemented in pure Java:
- PDE: 2D heat-conduction (diffusion) equation solved with an explicit finite-difference method (FTCS), generating heatmap snapshots and summary plots via JFreeChart (PNG, 300 DPI metadata).
- ODE + Control: a nonlinear cart–pole (inverted pendulum) system stabilized using Sliding Mode Control (SMC), with frame-by-frame rendering using Java2D/Swing, time-series plots via JFreeChart (PNG, 300 DPI metadata), and optional MP4 encoding using FFmpeg.
Build system: Maven • Plotting: JFreeChart • Animation: Java2D + Swing • Optional video encoding: FFmpeg
- About this repository
- What are ODEs and PDEs?
- Example 1 (PDE): 2D Heat Equation
- Example 2 (ODE): Inverted Pendulum with Sliding Mode Control
- Sliding Mode Control (SMC) theory
- Numerical methods used in this repo
- Plots and animations (JFreeChart, Java2D/Swing, FFmpeg)
- Dependencies and installation
- Building the project
- Running the programs and generating results
- Repository file guide (full explanation)
- Operating system guides (Windows / macOS / Linux)
- Troubleshooting
- Implementation tutorial video
This repository is designed as a practical reference for implementing numerical solvers in modern Java (Java 17):
- A PDE workflow that starts from a physical diffusion model (heat conduction), discretizes it, runs a time-marching solver, and produces publication-quality plots and image snapshots.
- An ODE + control workflow that implements a nonlinear plant (cart–pole), injects disturbances, runs a robust controller (Sliding Mode Control), generates simulation plots, and produces an animation/video.
The focus is intentionally “end-to-end engineering,” not only the core math:
- stable time stepping (explicit stability constraints),
- clean logging to CSV (reproducibility),
- plot generation (analysis),
- high-resolution images with 300 DPI metadata (documentation/publication),
- animation frames and optional MP4 video (communication and debugging),
- portable builds and execution via Maven (cross-platform).
com.mohammadijoo.odepde.heat2d.Heat2DMain→ solves the 2D heat equation and writes results intooutput/heat2d/com.mohammadijoo.odepde.pendulum_smc.CartPoleSMCMain→ simulates a cart–pole + SMC controller and writes results intooutput/pendulum_sliding_mode/
An ODE models time evolution of one or more state variables with respect to a single independent variable (usually time):
where:
-
$\mathbf{x}(t)$ is the state (e.g., cart position, pole angle, velocities), -
$\mathbf{u}(t)$ is an input (e.g., a control force), -
$\mathbf{f}(\cdot)$ encodes the physics/dynamics.
In this repository, the inverted pendulum example is a nonlinear ODE system integrated in time using RK4 with sub-stepping for stable animation rendering.
A PDE involves partial derivatives with respect to two or more independent variables (e.g., time and space). A canonical example is the heat (diffusion) equation:
where:
-
$T(x,y,t)$ is temperature, -
$\alpha$ is thermal diffusivity, -
$(x,y)$ are spatial coordinates, -
$t$ is time.
In this repository, the heat equation is discretized in space using finite differences and integrated forward in time using an explicit FTCS method.
The PDE solved in src/main/java/com/mohammadijoo/odepde/heat2d/Heat2DMain.java is:
Interpretation:
- heat conduction in a 2D plate,
- no internal heat sources,
- constant isotropic diffusivity
$\alpha$ , - fixed temperature boundaries (Dirichlet BCs).
The boundary conditions implemented in the Java code are:
- left boundary held at
$T=100$ , - right/top/bottom held at
$T=0$ ,
which creates a diffusion front moving from the left boundary into the interior.
The solver uses:
- uniform grid in
$x$ and$y$ , - second-order central differences for
$\partial^2 T/\partial x^2$ and$\partial^2 T/\partial y^2$ , - explicit time stepping (Forward Euler in time).
At interior grid nodes
The implementation uses a 1D flattened array for cache efficiency. The mapping:
is used throughout.
Explicit diffusion is stable only if the time step satisfies a constraint. A commonly used sufficient condition is:
The code computes this as dtStable and uses a conservative factor (0.80) to avoid operating near the stability limit.
When you run Heat2DMain, you will find:
- heatmap snapshots:
output/heat2d/heat_t*.png - final centerline profile:
output/heat2d/centerline_final.png - center temperature vs time:
output/heat2d/center_point_vs_time.png - CSV log:
output/heat2d/heat2d_log.csv
All PNG images are rendered at high resolution (e.g., 2400×2000 for heatmaps) and written with 300 DPI metadata (PNG pHYs chunk)
to preserve intended print/export quality.
The second example (src/main/java/com/mohammadijoo/odepde/pendulum_smc/CartPoleSMCMain.java) simulates a nonlinear cart–pole system with disturbances and stabilizes it using Sliding Mode Control (SMC).
The code uses the following state:
-
$x$ is cart position (meters), -
$\theta$ is pole angle (radians) with$\theta=0$ being upright, - the angle is wrapped into
$[-\pi,\pi]$ to avoid numeric drift.
Two disturbance pulses are injected as an external torque about the pole pivot:
- pulse 1: starts at
$t=0.5,\text{s}$ , positive torque (“push right”) - pulse 2: starts at
$t=5.0,\text{s}$ , negative torque (“push left”)
Each pulse uses a smooth half-sine profile over a duration
For visualization/logging, the code reports an “equivalent bob force”:
The disturbance arrow is shown for 0.5 seconds after each pulse begins.
This example is intentionally complete:
- integrate nonlinear dynamics (RK4),
- render each frame using the current integrated state (Java2D),
- save frames to disk as PNG,
- generate time-series plots (JFreeChart) and save them as PNG (300 DPI metadata),
- save a CSV log,
- optionally encode an MP4 using FFmpeg.
Outputs include:
output/pendulum_sliding_mode/frames/frame_000000.png... etc.output/pendulum_sliding_mode/cartpole_log.csv- multiple plots: cart position, pole angle, control force, disturbance torque, equivalent bob force, sliding surface
- MP4 video (if FFmpeg is available):
output/pendulum_sliding_mode/pendulum_smc_10s_6000f.mp4
Sliding Mode Control is a robust nonlinear control method designed to enforce a chosen “sliding manifold” (sliding surface) in the state space, even in the presence of disturbances and model uncertainties.
For a general second-order tracking problem, a common sliding surface is:
where
In an inverted pendulum, the balancing objective is
Interpretation:
-
$\lambda_{\theta}$ defines how strongly the controller penalizes angular error, -
$\alpha$ couples cart motion into the balancing objective (moving the cart is the actuation mechanism), -
$\lambda_x$ introduces a cart-centering tendency.
A classical sufficient reaching condition uses the Lyapunov function:
Then:
If the controller enforces:
then
A standard ideal reaching law is:
leading to:
The discontinuity in
and apply:
where
This repository uses parameters:
k(gain),phi(boundary layer).
For the cart–pole dynamics, deriving an explicit closed-form expression for
Instead, the Java code uses a pragmatic engineering approach:
- Define the desired sliding surface derivative:
$\dot{s}_{\mathrm{des}}=-k,\mathrm{sat}\left(\frac{s}{\phi}\right).$ - Approximate
$\dot{s}(u)$ locally as an affine function:$\dot{s}(u)\approx a,u+b.$ - Estimate
$a$ and$b$ numerically using two evaluations of the nominal dynamics:$a\approx \dot{s}(1)-\dot{s}(0),\qquad b\approx \dot{s}(0).$ - Solve for the control:
$u_{\mathrm{smc}}=\frac{\dot{s}_{\mathrm{des}}-b}{a}.$ - Apply actuator saturation:
$u=\mathrm{clamp}(u_{\mathrm{smc}}+u_{\mathrm{hold}},-u_{\max},u_{\max}).$
This is a common pattern in applied nonlinear control: use model evaluations to avoid algebraic inversion, while still enforcing a valid reaching law.
To prevent long-term drift, a cart-centering PD term is added, but only when the pendulum is near upright. The term:
uses a gating function
Effect:
- if
$|\theta|$ is large →$g(\theta)\approx 0$ (prioritize balancing), - if
$|\theta|$ is small →$g(\theta)\approx 1$ (recenter the cart).
The heat solver is a canonical explicit diffusion integrator:
- space: central difference (2nd order),
- time: forward Euler (1st order).
Strengths:
- straightforward implementation,
- cheap per time step,
- easy to extend/parallelize later.
Limitations:
- explicit diffusion stability constraints may enforce small
$\Delta t$ for fine grids, - implicit methods (Crank–Nicolson, ADI) are preferable for stiff regimes (future extension).
The cart–pole uses classical Runge–Kutta 4th order (RK4). To generate smooth animation frames:
- choose a frame step
$\Delta t_{\mathrm{frame}}=\frac{T}{N_{\mathrm{frames}}}$ , - integrate using smaller physics steps:
$\Delta t_{\mathrm{phys}}=\frac{\Delta t_{\mathrm{frame}}}{N_{\mathrm{substeps}}}.$
This keeps integration stable while preserving a deterministic “one frame → one PNG” pipeline.
This repository uses JFreeChart for:
- time-series plots (position, angle, control, etc.),
- heatmap visualization (via
XYBlockRendererand anXYZDataset), - exporting PNG images.
Key implementation details you may care about:
- axis tick formatting is forced to English digits via
Locale.US+DecimalFormatSymbols, - tick density is explicitly controlled via
NumberTickUnit, - plot fonts and strokes are increased for visibility on high-resolution canvases (e.g., 2400×1800),
- a PNG
pHYschunk is written so the images carry 300 DPI metadata.
The inverted pendulum animation uses Java2D drawing primitives on a BufferedImage:
- cart, wheels, pole, bob, track, and disturbance arrow are drawn each frame,
- the frame is saved to
output/pendulum_sliding_mode/frames/asframe_%06d.png, - optional preview window (Swing) can be enabled with
--preview.
If FFmpeg is available on your PATH, the pendulum program automatically calls it using ProcessBuilder:
- input: PNG frames,
- codec: H.264 (
libx264), - pixel format:
yuv420p(compatible with most players).
If FFmpeg is not installed, you still get all frames and plots, and you can encode manually (see OS guides below).
- Java Development Kit: JDK 17 (or compatible; project targets Java 17 via Maven)
- Apache Maven: 3.8+ recommended
- Git (recommended)
- JFreeChart (
org.jfree:jfreechart:1.5.6)
- FFmpeg (only required for MP4 encoding; frames and plots are generated without it)
All Java dependencies are defined in pom.xml. Maven will download and cache them automatically:
- on Windows: typically under
%USERPROFILE%.m2\repository - on macOS/Linux: under
~/.m2/repository
From the repository root:
mvn -DskipTests clean packageWhat this does:
- cleans the
target/folder, - compiles with Java 17,
- packages a JAR under
target/.
The project uses Maven’s Exec plugin to run the two main classes.
mvn -DskipTests exec:java -Dexec.mainClass="com.mohammadijoo.odepde.heat2d.Heat2DMain"Outputs:
output/heat2d/heat_t*.pngoutput/heat2d/centerline_final.pngoutput/heat2d/center_point_vs_time.pngoutput/heat2d/heat2d_log.csv
mvn -DskipTests exec:java -Dexec.mainClass="com.mohammadijoo.odepde.pendulum_smc.CartPoleSMCMain"Outputs:
- frames:
output/pendulum_sliding_mode/frames/frame_*.png - plots:
output/pendulum_sliding_mode/*.png - CSV:
output/pendulum_sliding_mode/cartpole_log.csv - MP4 (if FFmpeg is installed):
output/pendulum_sliding_mode/pendulum_smc_10s_6000f.mp4
The pendulum program supports optional flags:
--preview: show a Swing preview window while still saving frames--frames N: override default frame count (default: 6000)--no-mp4: skip FFmpeg encoding step
Example:
mvn -DskipTests exec:java -Dexec.mainClass="com.mohammadijoo.odepde.pendulum_smc.CartPoleSMCMain" -Dexec.args="--frames 3000 --no-mp4"This section explains the key files and their roles.
This file implements a complete 2D heat-diffusion workflow:
- Grid + discretization
- Uniform grid:
nx,ny, withdxanddy. - Flattened storage:
double[] Tanddouble[] Tnew. - Index helper:
idx(i,j,nx) = j*nx + i.
- Boundary conditions
- Dirichlet boundaries (fixed temperatures).
- Left boundary is “hot” (100); others are 0.
- Re-applied at every time step for correctness.
- Stability-aware time step
- Computes the explicit FTCS stable limit
dtStable. - Uses
dt = 0.80 * dtStablefor margin.
- Output strategy
- Uses
snapshotEveryto throttle snapshots (avoid thousands of PNGs). - Saves heatmap snapshots (high resolution) as the simulation progresses.
- Logs a center temperature trace and exports CSV.
- Visualization details
- Heatmaps are produced using
DefaultXYZDataset+XYBlockRenderer. - Color mapping uses a custom
ThermalPaintScale(blue → cyan → green → yellow → red). - Plot fonts and strokes are intentionally increased for high-resolution exports.
- Tick labels are enforced in English using
Locale.USformatting. - PNG images include 300 DPI metadata via the PNG
pHYschunk.
This is the most comprehensive file in the repository: it includes plant modeling, control design, numerical integration, rendering, logging, plotting, and optional MP4 encoding.
Main components:
- Plant model
PoleModelcomputes center of mass and inertia for a rod + bob.CartPoleParamsstores masses, gravity, and damping.dynamics(...)computes derivatives given a control force and external torque.
- Numerical integration
- RK4 is implemented in
rk4Step. - Sub-stepping (
substeps) integrates multiple physics steps per video frame. - Angle normalization via
wrapToPi.
- Controller (SMC)
slidingSurfacedefines the manifold:s = thetaDot + lambdaTheta*theta + alpha*(xDot + lambdaX*x).computeControlenforces a reaching law using a saturation-based boundary layer.- Includes a gated cart-centering PD term (
uHold) to prevent drift. - Applies actuator saturation (
uMax) to keep forces realistic.
- Disturbances
Disturbanceinjects exactly two torque pulses at fixed times.- Uses a half-sine profile to avoid discontinuities.
- Arrow visualization is enabled for a fixed duration after each pulse start.
- Rendering pipeline (frames)
- Each frame is rendered into a
BufferedImageusing Java2D. - Cart/pole geometry and arrow are drawn with anti-aliasing enabled.
- Frames are saved to disk as PNG using a deterministic filename scheme.
- Plots and logs
- Time-series plots are generated with JFreeChart and saved as 300-DPI PNGs.
- Signals logged:
x,theta,u,tau_ext,F_eq,s. - CSV log is written to
output/pendulum_sliding_mode/cartpole_log.csv.
- MP4 encoding (optional)
- The program checks if
ffmpegis available on PATH. - If available, it encodes frames into H.264 MP4 automatically.
- If not, you still have frames and can encode manually.
Key responsibilities:
- configures project coordinates (
groupId,artifactId,version), - sets Java version via
<maven.compiler.release>17</maven.compiler.release>, - declares plotting dependency:
org.jfree:jfreechart:1.5.6
- includes Maven plugins:
maven-compiler-pluginto compile with the configured releaseexec-maven-pluginto run main classes from Maven
This repository is Maven-based, so the most reliable Windows setup is:
- install JDK 17,
- install Maven,
- run from Git Bash or Command Prompt,
- optionally use Visual Studio Code for editing/debugging.
- JDK 17: Install Temurin (Adoptium) or Oracle JDK, and verify
java -versionreturns 17.x. - Maven: Install Apache Maven and verify
mvn -version. - Git: Recommended (and provides Git Bash).
- FFmpeg (optional): Needed only if you want MP4 output; verify
ffmpeg -version.
git clone <YOUR_REPO_URL>
cd ode-pde-javaUse exactly these commands (as requested):
mvn -DskipTests clean packagemvn -DskipTests exec:java -Dexec.mainClass="com.mohammadijoo.odepde.heat2d.Heat2DMain"mvn -DskipTests exec:java -Dexec.mainClass="com.mohammadijoo.odepde.pendulum_smc.CartPoleSMCMain"The phrase “start from a blank solution” is typically associated with Visual Studio; however, Java development is most commonly done in Visual Studio Code, IntelliJ IDEA, or Eclipse. The workflow below uses Visual Studio Code while still keeping the project as a Maven repo.
- Install Visual Studio Code and Java tooling:
- Install the Extension Pack for Java (Microsoft).
- Install Maven for Java extension (if not included).
- Open the repository:
- File → Open Folder → select the repository root (the folder containing
pom.xml).
- Maven import and dependency sync:
- VS Code will detect
pom.xmland download dependencies automatically. - If it does not, open the Command Palette and run: “Maven: Reload project”.
- Create “two run configurations” (Heat2D and Pendulum):
- In the Explorer panel, expand “Maven” and locate the
exec:javagoals. - Or create tasks in
.vscode/tasks.jsonthat call the exact Maven commands above.
- Debugging (optional):
- You can run with the Java debugger by creating a launch configuration for each main class.
- Because the project is Maven-based, most users simply run via Maven and inspect outputs in
output/.
- Install prerequisites:
brew update
brew install openjdk@17 maven ffmpeg- Confirm versions:
java -version
mvn -version
ffmpeg -version- Build and run:
mvn -DskipTests clean package
mvn -DskipTests exec:java -Dexec.mainClass="com.mohammadijoo.odepde.heat2d.Heat2DMain"
mvn -DskipTests exec:java -Dexec.mainClass="com.mohammadijoo.odepde.pendulum_smc.CartPoleSMCMain"Manual MP4 encoding (if you choose to encode yourself):
ffmpeg -y -framerate 600 -i output/pendulum_sliding_mode/frames/frame_%06d.png \
-c:v libx264 -pix_fmt yuv420p output/pendulum_sliding_mode/pendulum_manual.mp4- Install prerequisites:
sudo apt-get update
sudo apt-get install -y openjdk-17-jdk maven ffmpeg- Build and run:
mvn -DskipTests clean package
mvn -DskipTests exec:java -Dexec.mainClass="com.mohammadijoo.odepde.heat2d.Heat2DMain"
mvn -DskipTests exec:java -Dexec.mainClass="com.mohammadijoo.odepde.pendulum_smc.CartPoleSMCMain"Manual MP4 encoding (optional):
ffmpeg -y -framerate 600 -i output/pendulum_sliding_mode/frames/frame_%06d.png \
-c:v libx264 -pix_fmt yuv420p output/pendulum_sliding_mode/pendulum_manual.mp4- Verify
java -versionprints 17.x. - Verify
mvn -versionshows Maven using the intended Java home. - If Maven uses another Java version, set
JAVA_HOMEto your JDK 17 installation.
- JFreeChart renders using Java2D fonts. Ensure a standard font is available (the code uses
SansSerif). - If you run on a headless environment, consider using the JVM option:
-Djava.awt.headless=true
- MP4 generation happens only if
ffmpegis available on PATH. - If auto-encoding is skipped, encode manually using the commands in the OS sections.
- Writing 6000 PNG frames can be IO-heavy.
- Reduce the frame count:
--frames 3000(or lower)
- Ensure you run on an SSD and avoid network folders.
At the end of the workflow, you can watch the full implementation and walkthrough on YouTube.