Direct numerical simulation infrastructure for the two-dimensional evolution of a liquid coating on a rotating cylinder. The implementation is based on Basilisk C and combines adaptive mesh refinement, volume-of-fluid interface tracking, two-phase Navier--Stokes dynamics, surface tension, gravity, automated parameter sweeps, performance profiling, and publication-oriented post-processing.
This repository is intended to provide a compact and reproducible computational companion to the associated study available at https://doi.org/10.1017/jfm.2020.421, bringing together mathematical modelling, asymptotic analysis, reduced-dimensional modelling calculations and direct numerical simulation towards resolving the delicate interplay between forces found in the (highly nonlinear) dynamics of a liquid film coating a rotating cylinder, inspired by the so-called honey dipper problem elegantly presented by H. K. Moffatt in 1977. It supports collaborative work with Dr. Alexander W. Wray at the University of Strathclyde, whom I am grateful to for bringing this problem to my attention back in 2018 and for fantastic discussions on this topic since then.
Note
This implementation was built and adapted a posteriori, following an initial effort in Gerris in 2019, which underpinned the results in the publication itself. For more details on the original implementation, please refer to Appendix A.3 within the respective study. While some workflow details have been adapted, the overall structure and parametric setup was intentionally kept closely linked with the published contribution - see Figure 6(b) and Table 1 in particular as foundations for the example figure above and the broader configuration of the reference case in this repository itself.
β
Two-dimensional incompressible two-phase Navier--Stokes solver
β
Volume-of-fluid representation of the liquid--gas interface
β
Surface tension, gravity, density contrast, and viscosity contrast
β
Rotating unit-radius cylinder with an initially prescribed coating thickness
β
Adaptive quadtree refinement with configurable maximum AMR level
β
Automated sweeps over film radius, rotation coefficient, and resolution
β
Centre-of-mass convergence criterion for automatic run termination
β
Persistent liquid-film rupture diagnostic based on connected components
β
Interface, diagnostic, snapshot, and animation output
β
Optional Basilisk TRACE and Linux perf profiling
β
Python post-processing for coating thickness and spatial trajectories
β
Reproducibility metadata, timing information, exit status, and source checksum
The principal simulation is contained in CoatedCylinder.c. It models a liquid film coating the exterior of a rotating circular cylinder in a surrounding gas. The flow is solved using Basilisk's centred incompressible Navier--Stokes formulation together with volume-of-fluid interface tracking and surface tension.
The principal runtime parameters are:
- film-radius parameter
fRadius; - dimensionless cylinder-rotation coefficient
cV; - maximum adaptive-mesh level
MAX_LEVEL.
The cylinder radius is nondimensionalised to unity. The calculation uses adaptive quadtree refinement and tracks the liquid centre of mass, coating-thickness extrema, connected liquid components, and saved interfaces throughout the run.
The simulation workflow requires:
- Basilisk C with
qcc; - a C compiler with OpenMP support;
- GNU
make; /usr/bin/time;- optional visualisation utilities such as
ffmpeg, ImageMagick, andgnuplot; - optional Linux
perffor hardware-counter profiling.
On a Debian/Ubuntu-like system, useful supporting packages include:
sudo apt install build-essential gnuplot imagemagick ffmpeggit clone https://github.com/rcsc-group/CoatedRotatingCylinder2D
cd CoatedRotatingCylinder2DFollow the official Basilisk installation instructions.
The supplied runner expects the BASILISK environment variable to point to the Basilisk source directory and qcc to be available on PATH. A typical setup is:
export BASILISK=$HOME/basilisk/src
export PATH=$PATH:$BASILISKIt is convenient to place these lines in ~/.bashrc or the equivalent startup file for your shell.
Move to the driver-code directory:
cd DriverCodeA standard production run at maximum AMR level 10 can be launched with:
TRACE_LEVEL=0 \
USE_PERF=0 \
OMP_NUM_THREADS=4 \
MAX_LEVEL=10 \
sh run_cylinder.shWhitespace-separated values are interpreted as parameter lists:
TRACE_LEVEL=0 \
USE_PERF=0 \
OMP_NUM_THREADS=4 \
MAX_LEVEL="7 8 9 10 11" \
OUTROOT="output" \
sh run_cylinder_sweep.shThe source is compiled once and one simulation is launched for each requested resolution.
The same mechanism applies to the film radius and cylinder velocity:
FRADIUS="1.25 1.5 1.75" \
CV="0.5 1.0" \
MAX_LEVEL="8 9 10" \
TRACE_LEVEL=0 \
USE_PERF=0 \
OMP_NUM_THREADS=4 \
OUTROOT="output" \
sh run_cylinder.shThis executes the Cartesian product of all supplied values.
Each case is written to a directory of the form
fR_<fRadius>_cV_<cV>_L_<MAX_LEVEL>
for example:
fR_1.5_cV_1.0_L_10
| Variable | Purpose | Typical production value |
|---|---|---|
FRADIUS |
Film-radius value or whitespace-separated sweep | 1.5 |
CV |
Cylinder-rotation coefficient or sweep | 1.0 |
MAX_LEVEL |
Maximum AMR level or sweep | 10 |
OMP_NUM_THREADS |
Number of OpenMP threads | machine/problem dependent |
OUTROOT |
Root simulation-output directory | output |
TRACE_LEVEL |
Basilisk event/function tracing | 0 |
USE_PERF |
Linux hardware-counter collection | 0 |
For profiling runs:
TRACE_LEVEL=2 USE_PERF=auto sh run_cylinder.shFor clean production timing:
TRACE_LEVEL=0 USE_PERF=0 sh run_cylinder.shUSE_PERF=1 can be used when hardware counters are required and the run should fail rather than silently continue when perf is unavailable.
Note
OpenMP scaling is problem- and resolution-dependent. Small adaptive grids may not benefit from a large thread count. Benchmark representative cases before selecting the production value of OMP_NUM_THREADS.
Note
Compiler optimisation flags are configurable through the runner. If -march=native is enabled, compile the executable on a machine with the same CPU architecture as the machine on which it will run.
.
βββ CoatedCylinder.c
βββ run_cylinder.sh
βββ run_cylinder_sweep.sh
β
βββ plot_com_trajectory.py
βββ plot_com_trajectory_resolution.py
βββ plot_thickness.py
βββ plot_thickness_resolution.py
βββ postprocess_common.py
β
βββ output/
β βββ fR_1.5_cV_1.0_L_10/
β βββ ...
β
βββ LICENSE
βββ README.md
The repository is deliberately kept compact:
CoatedCylinder.ccontains the Basilisk simulation.run_cylinder.shprovides the standard single-case/benchmark workflow.run_cylinder_sweep.shmanages parameter and resolution sweeps.postprocess_common.pycontains the shared Python analysis utilities.plot_*.pyscripts generate single-case and resolution-comparison figures.output/contains a representative simulation output using the same directory convention produced by the sweep workflow.
The files in this repository and their organisation represent a minimal working version of the implementation, which encompasses the necessary ingredients for reproducibility, as well as sample output (in the sense of only a subset of the files being uploaded while trying to strike the balance between the framework being informative and compact). Once familiarity with the codebase has been reached, the following structure for the codebase is recommended:
.
βββ DriverCode/
β βββ CoatedCylinder.c
β βββ run_cylinder.sh
β
βββ PostProcessing/
β βββ postprocess_common.py
β βββ plot_thickness.py
β βββ plot_thickness_resolution.py
β βββ plot_com_trajectory.py
β βββ plot_com_trajectory_resolution.py
β βββ README.md
β
βββ Figures/
β βββ ...
β
βββ SupplementaryMovies/
β βββ ...
β
βββ LICENSE
βββ README.md
DriverCode/ contains the simulation and execution workflow. PostProcessing/ contains the reusable Python analysis suite. Figures/ and SupplementaryMovies/ are natural locations for representative visualisations or outward-facing material in general.
A parameter sweep produces a top-level output directory containing the compiled executable, build metadata, a sweep summary, and one directory per parameter combination:
output/
βββ CoatedCylinder
βββ build-metadata.txt
βββ sweep-summary.tsv
β
βββ fR_1.5_cV_1.0_L_9/
β βββ Animations/
β βββ Interfaces/
β βββ Slices/
β βββ logdroplets.dat
β βββ logstats.dat
β βββ logvol.dat
β βββ perfs
β βββ rupture.flag
β βββ stdout.log
β βββ stderr.log
β βββ time.txt
β βββ event-profile.txt
β βββ exit-status.txt
β βββ metadata.txt
β
βββ fR_1.5_cV_1.0_L_10/
βββ ...
The most useful diagnostic outputs are:
logvol.datβ film-volume and minimum/maximum thickness diagnostics;logdroplets.datβ connected-component and centre-of-mass diagnostics;Interfaces/β saved liquid-interface coordinates;rupture.flagβ persistent0/1indicator recording whether multiple connected liquid components were detected;perfsβ Basilisk performance history;time.txtβ GNUtime -vresource summary;event-profile.txtβ BasiliskTRACE=2profile when enabled;metadata.txtβ case-level parameters and execution settings;exit-status.txtβ simulation process exit status.
At sweep level, sweep-summary.tsv provides a compact overview of the parameter combination, exit status, and rupture classification for each case.
The Python suite reconstructs coating-thickness histories, centre-of-mass trajectories, tracked maximum-thickness trajectories, final liquid interfaces, and resolution comparisons.
From the PostProcessing/ directory, create a local virtual environment:
python3 -m venv .venv
. .venv/bin/activateInstall the required Python packages:
python3 -m pip install --upgrade pip
python3 -m pip install numpy matplotlib pylustratorThe environment only needs to be created once. In later sessions:
. .venv/bin/activateTo leave it:
deactivateFor a single resolution:
python3 plot_thickness.py --level 10
python3 plot_com_trajectory.py --level 10For a resolution study:
python3 plot_thickness_resolution.py --levels 7 8 9 10 11
python3 plot_com_trajectory_resolution.py --levels 7 8 9 10 11A different simulation root can be supplied explicitly:
python3 plot_thickness_resolution.py \
--output-root /path/to/output \
--levels 7 8 9 10 11For non-interactive execution:
python3 plot_thickness.py --level 10 --save-onlyIf external LaTeX rendering is unavailable:
python3 plot_thickness.py --level 10 --save-only --no-texThe plotting scripts export publication-quality PDF files together with high-resolution PNG versions.
The execution workflow records the numerical case parameters together with compiler, OpenMP, tracing, timing, and source-version information. Useful metadata include:
- compiler and optimisation flags;
- OpenMP thread count and placement settings;
- requested parameter sweep;
- source SHA-256 checksum;
- tracing and hardware-counter configuration.
Performance measurements should distinguish between:
- production timing β
TRACE_LEVEL=0,USE_PERF=0; - Basilisk hotspot profiling β
TRACE_LEVEL=2; - hardware-counter profiling β
USE_PERF=1.
Instrumentation can affect runtime, so profiling and clean timing results should not be treated as directly interchangeable.
If you use this code or associated data in your work, please cite the accompanying publication:
Wray, A. W., & Cimpeanu, R. (2020). Reduced-order modelling of thick inertial flows around rotating cylinders. Journal of Fluid Mechanics, 898, A1.
BibTeX:
@article{wray2020reduced,
title={Reduced-order modelling of thick inertial flows around rotating cylinders},
author={Wray, Alexander W and Cimpeanu, Radu},
journal={Journal of Fluid Mechanics},
volume={898},
pages={A1},
year={2020},
publisher={Cambridge University Press}
}Contributions and reproducibility feedback are welcome. Please feel free to:
- open an issue for bugs, portability problems, or questions;
- fork the repository;
- submit a pull request for a well-tested improvement.
For numerical changes, please document any modifications to solver tolerances, mesh-adaptation criteria, physical parameters, compiler settings, or stopping conditions that may affect reproducibility.