src-local/diagnostics.h
diagnostics.h
Statistics and output helpers for drop impact simulations.
Provides
- File handle management (open once, write many)
- Statistics calculations (kinetic energy, etc.)
- Snapshot management
- Extension hooks for additional diagnostics
Author
Vatsal Sanjay ([email protected]) CoMPhy Lab, Durham University
#ifndef DIAGNOSTICS_H
#define DIAGNOSTICS_H
#include "params.h"
// Global file handles (kept open for performance)
static FILE *log_fp = NULL;open_log_files()
Open log files and write headers. The log file stays open for the entire simulation to avoid repeated open/close overhead.
Parameters
p: parameter structure
Returns
0on success-1on error
static inline int open_log_files(const struct SimulationParams *p) {
// Create intermediate directory for snapshots
char intermediate_dir[512];
snprintf(intermediate_dir, sizeof(intermediate_dir), "%s/intermediate", p->output_dir);
create_output_directory(intermediate_dir);
// Open main log file
char log_path[512];
snprintf(log_path, sizeof(log_path), "%s/log", p->output_dir);
log_fp = fopen(log_path, "w");
if (!log_fp) {
fprintf(stderr, "ERROR: Cannot open log file: %s\n", log_path);
return -1;
}
// Write header with full parameter information
fprintf(log_fp, "# Drop Impact Simulation Log\n");
fprintf(log_fp, "# Parameters:\n");
fprintf(log_fp, "# We = %g, Ohd = %g, Ohs = %g\n", p->We, p->Ohd, p->Ohs);
fprintf(log_fp, "# rho_ratio = %g, Re = %g\n", p->rho_ratio, sqrt(p->We) / p->Ohd);
fprintf(log_fp, "# Ldomain = %g, MAXlevel = %d, MINlevel = %d\n",
p->Ldomain, p->MAXlevel, p->MINlevel);
fprintf(log_fp, "# drop_position = (%g, %g), radius = %g\n",
p->drop_x, p->drop_y, p->drop_radius);
fprintf(log_fp, "# impact_velocity = %g, tmax = %g\n", p->impact_velocity, p->tmax);
fprintf(log_fp, "# Columns: iteration dt time kinetic_energy\n");
fflush(log_fp);
fprintf(stderr, "Log file opened: %s\n", log_path);
return 0;
}calculate_kinetic_energy()
Return total kinetic energy integrated over the domain.
For axisymmetric flow:
KE = ∫ 2πy * 0.5 ρ (u_x^2 + u_y^2) dV
static inline double calculate_kinetic_energy(void) {
double ke = 0.0;
foreach(reduction(+:ke)) {
// Axisymmetric volume element: 2πy * Δx * Δy
// Density from VOF field f
double rho_local = rho(f[]);
double u_mag_sq = sq(u.x[]) + sq(u.y[]);
ke += 2.0 * M_PI * y * (0.5 * rho_local * u_mag_sq) * sq(Delta);
}
return ke;
}write_statistics()
Write iteration, timestep, time, and kinetic energy to the log file. The file handle stays open for performance.
Parameters
iter: current iteration numbertime: current simulation timetimestep: current timestep sizep: parameter structure
static inline void write_statistics(int iter, double time, double timestep,
const struct SimulationParams *p) {
if (!log_fp) {
fprintf(stderr, "ERROR: Log file not open\n");
return;
}
// Calculate statistics
double ke = calculate_kinetic_energy();
// Write to log file
fprintf(log_fp, "%d %g %g %g\n", iter, timestep, time, ke);
fflush(log_fp); // Ensure data is written
// Also write to stderr for monitoring
if (iter == 0 || iter % 100 == 0) {
fprintf(stderr, "i=%d t=%g dt=%g KE=%g\n", iter, time, timestep, ke);
}
}save_snapshot()
Save simulation snapshots for restart and post-processing.
Parameters
time: current simulation timep: parameter structure
static inline void save_snapshot(double time, const struct SimulationParams *p) {
char filename[512];
// Save restart file in output directory
snprintf(filename, sizeof(filename), "%s/restart", p->output_dir);
dump(file = filename);
// Save numbered snapshot in intermediate directory
snprintf(filename, sizeof(filename), "%s/intermediate/snapshot-%5.4f", p->output_dir, time);
dump(file = filename);
fprintf(stderr, "Snapshot saved at t = %g\n", time);
}close_log_files()
Close any open log files at the end of the simulation.
static inline void close_log_files(void) {
if (log_fp) {
fclose(log_fp);
log_fp = NULL;
fprintf(stderr, "Log file closed\n");
}
}Optional Diagnostics (ENABLE_ADVANCED_DIAGNOSTICS)
Placeholder routines for future extensions: - Drop spreading radius - Contact line position - Interface area - Pressure forces - Energy dissipation
#ifdef ENABLE_ADVANCED_DIAGNOSTICScalculate_spreading_radius()
Return the maximum radial extent of the drop.
static inline double calculate_spreading_radius(void) {
double r_max = 0.0;
foreach(reduction(max:r_max)) {
if (f[] > 0.5) { // Inside drop
if (x > r_max) r_max = x;
}
}
return r_max;
}calculate_contact_line_y()
Return the contact line y-position (placeholder implementation).
static inline double calculate_contact_line_y(void) {
double y_contact = 0.0;
// Implementation depends on surface definition
// Placeholder for future development
return y_contact;
}calculate_interface_area()
Return total interface area (2D: length, 3D: area).
static inline double calculate_interface_area(void) {
double area = 0.0;
foreach(reduction(+:area)) {
// Interface area proportional to |∇f|
double grad_f_mag = sqrt(sq((f[1,0] - f[-1,0])/(2.0*Delta)) +
sq((f[0,1] - f[0,-1])/(2.0*Delta)));
if (grad_f_mag > 0.1) { // Near interface
area += 2.0 * M_PI * y * grad_f_mag * sq(Delta);
}
}
return area;
}
#endif // ENABLE_ADVANCED_DIAGNOSTICS
#endif // DIAGNOSTICS_H