postProcess/getFootPrint.c
getFootPrint
Extract the maximum interface height along the substrate from a Basilisk VOF snapshot by scanning reconstructed facets within an x cutoff.
Output
CSV streamed to stderr:
t,y_maxUsage
./getFootPrint <snapshot-file> <xCutoff>Notes
- Uses PLIC/MYC facet reconstruction to locate the interface.
- Searches only for cells with
0 < f < 1andx < xCutoff.
Author
Vatsal Sanjay ([email protected]) CoMPhy Lab, Durham University Last updated: Nov 17, 2025
#include "utils.h"
#include "output.h"
#include "fractions.h"
#include <stdbool.h>
scalar f[];
typedef struct {
char snapshot[256];
double x_cutoff;
} footprint_config;
static int parse_arguments(int argc, char const *argv[],
footprint_config *cfg);
static void restore_snapshot(const footprint_config *cfg);
static void configure_vof_boundary(void);
static double compute_maximum_interface_height(double x_cutoff);
static inline bool interface_cell(double vof_value);
static inline double segment_midpoint(double cell_center, double delta,
double end0, double end1);
static void emit_footprint(double timestamp, double y_max);
int main(int argc, char const *argv[])
{
footprint_config cfg;
if (!parse_arguments(argc, argv, &cfg))
return 1;
restore_snapshot(&cfg);
configure_vof_boundary();
double y_max = compute_maximum_interface_height(cfg.x_cutoff);
emit_footprint(t, y_max);
return 0;
}
static int parse_arguments(int argc, char const *argv[],
footprint_config *cfg)
{Validate CLI input and capture the snapshot filename and search window.
if (argc != 3) {
fprintf(stderr, "Error: Expected 2 arguments\n");
fprintf(stderr,
"Usage: %s <snapshot-file> <xCutoff>\n",
argv[0]);
return 0;
}
snprintf(cfg->snapshot, sizeof(cfg->snapshot), "%s", argv[1]);
cfg->x_cutoff = atof(argv[2]);
if (cfg->x_cutoff <= 0.) {
fprintf(stderr, "Error: xCutoff must be positive.\n");
return 0;
}
return 1;
}
static void restore_snapshot(const footprint_config *cfg)
{Each invocation handles a single snapshot; restoring is a one-liner.
restore (file = cfg->snapshot);
}
static void configure_vof_boundary(void)
{Boundary: no fluid at the axis (left) with proper VOF
prolongation. Keeping it in one routine avoids repeated
f[...] ceremony.
f[left] = dirichlet(0.);
f.prolongation = fraction_refine;
f.dirty = true;
}
static inline bool interface_cell(double vof_value)
{
const double eps = 1e-6;
return (vof_value > eps) && (vof_value < 1. - eps);
}
static inline double segment_midpoint(double cell_center, double delta,
double end0, double end1)
{
return cell_center + 0.5*delta*(end0 + end1);
}
static double compute_maximum_interface_height(double x_cutoff)
{Search x<x_cutoff for the highest facet midpoint.
facets returns up to two points per cell,
which we immediately collapse to a midpoint.
double y_max = 0.;
face vector s = {{-1}};
foreach (reduction(max:y_max)) {
if (x >= x_cutoff || !interface_cell(f[]))
continue;
coord n = facet_normal(point, f, s);
double alpha = plane_alpha(f[], n);
coord segment[2];
if (facets(n, alpha, segment) != 2)
continue;
double y_mid = segment_midpoint(y, Delta,
segment[0].y, segment[1].y);
if (y_mid > y_max)
y_max = y_mid;
}
return y_max;
}
static void emit_footprint(double timestamp, double y_max)
{Stream CSV to stderr; consumer scripts read via pipes.
FILE * fp = ferr;
fprintf(fp, "%g,%g\n", timestamp, y_max);
fflush (fp);
fclose (fp);
}