sandbox/ryang/surfactant/wave.c
This simulation studies the effect of surfactants on gravity-capillary wave based on breaking wave example wave.c and Marangoni flow package by Palas Kumar Farsoiya et al. farsoiya/marangoni_surfactant/.
/*
Requirement: redistance2.h, surfactant-transport.h
*/Breaking wave
We solve the two-phase Navier–Stokes equations with surface tension and using a momentum-conserving transport of each phase. Gravity is taken into account using the “reduced gravity approach” and the results are visualised using Basilisk view.
#include "navier-stokes/centered.h"
#include "two-phase-clsvof.h"
#include "integral.h"
#include "curvature.h"
#include "view.h"
#include "tag.h"
//Surfactants
#include "surfactant-transport.h"We log some profiling information.
#include "navier-stokes/perfs.h"
#include "profiling.h"
#include <sys/stat.h>
//Surfactants
double beta = 1.0;
double dsigma0 = 0.5;
double gamma0 = 1., gamma_inf = 1.;
scalar sigmaf[];
vector iforce[];The primary parameters are the wave steepness ak, the Bond and Reynolds numbers.
double ak = 0.3;
double BO = 10.;
double RE = 40000.;
double TEND = 1.0; // end of the simulationThe default maximum level of refinement depends on the dimension.
int LEVEL = dimension == 2 ? 8 : 6;The error on the components of the velocity field used for adaptive refinement.
double uemax = 0.005;The density and viscosity ratios are those of air and water.
#define RATIO (1./850.)
#define MURATIO (17.4e-6/8.9e-4)Define if we want to use a Dirac viscous layer initialization.
int DIRAC = 0;The wave number, fluid depth and acceleration of gravity are set to these values.
#define k_ (2.*pi)
#define h_ 0.5
#define g_ 1.
double MA = 1;The program takes optional arguments which are the level of refinement, steepness, Bond and Reynolds numbers, and optional Dirac initialisation.
int main (int argc, char * argv[])
{
if (argc > 1)
beta = atof (argv[1]);
if (argc > 2)
ak = atof(argv[2]);
if (argc > 3)
BO = atof(argv[3]);
if (argc > 4)
RE = atof(argv[4]);
if (argc > 5)
DIRAC = atof(argv[5]);
if (argc > 6)
LEVEL = atof(argv[6]);
if (argc > 7)
TEND = atof(argv[7]);
if (argc > 8)
dsigma0 = atof(argv[8]);
MA = beta / (BO * k_ * sqrt(k_)/RE);The domain is a cubic box centered on the origin and of length L0=1, periodic in the x- and z-directions.
Here we set the densities and viscosities corresponding to the parameters above.
rho1 = 1.;
rho2 = RATIO;
mu1 = 1.0/RE; //using wavelength as length scale
mu2 = 1.0/RE*MURATIO;
TOLERANCE = 1e-4;
D_s = 0.01; //Surface Diffusivity of surfactant D_s
surfactant = 1;
d.sigmaf = sigmaf;
tracers = list_concat(tracers, {c1, gamma2, d2, pfield});
reinit_skip_steps = 100; //this needs consideration if there are topological changesWhen we use adaptive refinement, we start with a coarse mesh which will be refined as required when initialising the wave.
#if TREE
N = 1 << LEVEL;
#else
N = 1 << LEVEL;
#endif
struct stat st = {0};
char name[80];
sprintf (name, "dat");
char newname[80];
sprintf (name, "dat");
if (stat(name, &st) == -1)
{
mkdir(name, 0700);
}
sprintf (name, "eta");
if (stat(name, &st) == -1)
{
mkdir(name, 0700);
}Preserve old stats restoring the simulation with a timestamp suffixed.
sprintf (name, "stats.dat");
if (stat(name, &st) == 0)
{
sprintf (newname, "stats-%ld.dat",time(0));
rename(name, newname);
}
sprintf (name, "perfs");
if (stat(name, &st) == 0)
{
sprintf (newname, "perfs-%ld",time(0));
rename(name, newname);
}
run();
}
//Surfactants (Gravity)
event acceleration (i++) {
face vector av = a;
foreach_face(y)
av.y[] += (-1. + alphav.y[]*rho1);
boundary ((scalar *){av});
}
//Surfactants (isotherm)
event stability (i++){
foreach(){
double deltas = (pfield[]*(1. - pfield[]))/EPSILON;
if (deltas > 1.e-1 && surfactant == 1){
double gamma = c1[]*4.*EPSILON;
sigmaf[] = 1.0/(BO*sq(k_))*(1. - dsigma0*tanh(MA/dsigma0 * BO * k_ * sqrt(k_)/RE * gamma/gamma0));
}
else
sigmaf[] = 1.0/(BO*sq(k_));
}
boundary({sigmaf});We first compute the minimum and maximum values of \alpha/f_m = 1/\rho, as well as \Delta_{min}.
double amin = HUGE, amax = -HUGE, dmin = HUGE;
foreach_face (reduction(min:amin) reduction(max:amax) reduction(min:dmin))
if (fm.x[] > 0.) {
if (alpha.x[]/fm.x[] > amax) amax = alpha.x[]/fm.x[];
if (alpha.x[]/fm.x[] < amin) amin = alpha.x[]/fm.x[];
if (Delta < dmin) dmin = Delta;
}
double rhom = (1./amin + 1./amax)/2.;The maximum timestep is set using the sum of surface tension coefficients.
for (scalar c in interfaces)
foreach(serial){
if (sigmaf[] > 0) {
double dt = sqrt (rhom*cube(dmin)/(pi*sigmaf[]))/10; //some prefactors maybe needed for stability
if (dt < dtmax)
dtmax = dt;
}
}
}
event test (i++){
if (i == 0)
{
foreach ()
{
double deltas = (pfield[] * (1. - pfield[])) / EPSILON;
// initially uniform surfactant concentration
if (deltas > 1.e-1 && surfactant == 1){
c1[] = gamma0 * deltas;
double gamma = c1[]*4.*EPSILON;
sigmaf[] = 1.0/(BO*sq(k_))*(1. - dsigma0*tanh(MA/dsigma0 * BO * k_ * sqrt(k_)/RE * gamma/gamma0));
}
else
sigmaf[] = 1./(BO*sq(k_));
}
}
}Initial conditions
These functions return the shape of a third-order Stokes wave with the wavenumber and steepness given by the parameters above (ak and _k_).
double wave (double x, double y) {
double a_ = ak/k_;
double eta1 = a_*cos(k_*x);
double alpa = 1./tanh(k_*h_);
double eta2 = 1./4.*alpa*(3.*sq(alpa) - 1.)*sq(a_)*k_*cos(2.*k_*x);
double eta3 = -3./8.*(cube(alpa)*alpa -
3.*sq(alpa) + 3.)*cube(a_)*sq(k_)*cos(k_*x) +
3./64.*(8.*cube(alpa)*cube(alpa) +
(sq(alpa) - 1.)*(sq(alpa) - 1.))*cube(a_)*sq(k_)*cos(3.*k_*x);
return eta1 + ak*eta2 + sq(ak)*eta3 - y;
}
double eta (double x, double y) {
double a_ = ak/k_;
double eta1 = a_*cos(k_*x);
double alpa = 1./tanh(k_*h_);
double eta2 = 1./4.*alpa*(3.*sq(alpa) - 1.)*sq(a_)*k_*cos(2.*k_*x);
double eta3 = -3./8.*(cube(alpa)*alpa -
3.*sq(alpa) + 3.)*cube(a_)*sq(k_)*cos(k_*x) +
3./64.*(8.*cube(alpa)*cube(alpa) +
(sq(alpa) - 1.)*(sq(alpa) - 1.))*cube(a_)*sq(k_)*cos(3.*k_*x);
return eta1 + ak*eta2 + sq(ak)*eta3;
}We also calculate an approximation to a Dirac distribution on the wave surface. This allows us to calculate a vortex sheet on the surface to provide a boundary layer in the air above the water surface.
double gaus (double y, double yc, double T){
double deltaw = sqrt(2.0/RE)/k_;
double deltaa = sqrt(2.0/RE*MURATIO/RATIO)/k_;
double r = y - yc;
return 2.0/(sqrt(2.0*pi*sq(deltaa)) + sqrt(2.0*pi*sq(deltaw))) *
(T*exp(-sq(r)/(2.0*sq(deltaw))) + (1.0 - T)*exp(-sq(r)/(2.0*sq(deltaa))));
}We either restart (if a “restart” file exists), or initialise the wave using the third-order Stokes wave solution.
# define POPEN(name, mode) fopen (name ".ppm", mode)
event init (i = 0)
{
if (!restore ("restart")) {
do {
foreach(){
d[] = wave(x,y);
}
fraction (f, wave(x,y));To initialise the velocity field, we first define the potential.
scalar Phi[];
foreach() {
double alpa = 1./tanh(k_*h_);
double a_ = ak/k_;
double sgma = sqrt(g_*k_*tanh(k_*h_)*
(1. + k_*k_*a_*a_*(9./8.*(sq(alpa) - 1.)*
(sq(alpa) - 1.) + sq(alpa))));
double A_ = a_*g_/sgma;
double phi1 = A_*cosh(k_*(y + h_))/cosh(k_*h_)*sin(k_*x);
double phi2 = 3.*ak*A_/(8.*alpa)*(sq(alpa) - 1.)*(sq(alpa) - 1.)*
cosh(2.0*k_*(y + h_))*sin(2.0*k_*x)/cosh(2.0*k_*h_);
double phi3 = 1./64.*(sq(alpa) - 1.)*(sq(alpa) + 3.)*
(9.*sq(alpa) - 13.)*
cosh(3.*k_*(y + h_))/cosh(3.*k_*h_)*a_*a_*k_*k_*A_*sin(3.*k_*x);
Phi[] = phi1 + ak*phi2 + ak*ak*phi3;
}
boundary ({Phi});
if (DIRAC) {We calculate the vorticity in the Dirac layer. We need a separate foreach here because we need the derivative of the potential phi.
scalar vort2[];
scalar psi[];
foreach() {
vort2[] = -2.0*gaus(y,wave(x,y)+y,f[])*(Phi[1,0]-Phi[-1,0])/(2.*Delta);
psi[] = 0.0;
}
boundary ({vort2,psi});
psi[top] = dirichlet(0.);
psi[bottom] = dirichlet(0.);Solve the Poisson problem for the streamfunction psi given the vorticity field.
poisson (psi, vort2);And then define the velocity field using centered-differencing of the streamfunction.
foreach() {
u.x[] = (psi[0,1] - psi[0,-1])/(2.*Delta);
u.y[] = -(psi[1] - psi[-1])/(2.*Delta);
}
}
else {If we choose not to use the Dirac layer, instead initialize in the water only according to the potential already calculated.
foreach()
foreach_dimension()
u.x[] = (Phi[1] - Phi[-1])/(2.0*Delta) * f[];
//u.x[] = f[]*10;
}
boundary ((scalar *){u});
//Surfactants
event("properties2"); //call this so that pfield can be populated and then c1 can be initialized
foreach(){
double deltas = (pfield[]*(1. - pfield[]))/EPSILON; //
// double gamma0 = gamma_inf*0.01;
c1[] = gamma0*deltas; //convert volume to surface
if (deltas > 1.e-2){
double gamma = c1[]*4.*EPSILON;
sigmaf[] = 1.0/(BO*sq(k_))*(1. - dsigma0*tanh(MA/dsigma0 * BO * k_ * sqrt(k_)/RE * gamma/gamma0));
}
else
sigmaf[] = 1./(BO*sq(k_));
}
boundary({sigmaf});
}On trees, we repeat this initialisation until mesh adaptation does not refine the mesh anymore.
#if TREE
while (adapt_wavelet ({f,u,pfield,c1},
(double[]){0.01,uemax,uemax,uemax,0.001,0.001}, LEVEL, 5).nf);
#else
while (0);
#endif
}
}Outputs
We are interested in the viscous dissipation rate in both water and air.
int dissipation_rate (double* rates)
{
double rateWater = 0.0;
double rateAir = 0.0;
foreach (reduction (+:rateWater) reduction (+:rateAir)) {
double dudx = (u.x[1] - u.x[-1] )/(2.*Delta);
double dudy = (u.x[0,1] - u.x[0,-1] )/(2.*Delta);
double dudz = (u.x[0,0,1] - u.x[0,0,-1])/(2.*Delta);
double dvdx = (u.y[1] - u.y[-1] )/(2.*Delta);
double dvdy = (u.y[0,1] - u.y[0,-1] )/(2.*Delta);
double dvdz = (u.y[0,0,1] - u.y[0,0,-1])/(2.*Delta);
double dwdx = (u.z[1] - u.z[-1] )/(2.*Delta);
double dwdy = (u.z[0,1] - u.z[0,-1] )/(2.*Delta);
double dwdz = (u.z[0,0,1] - u.z[0,0,-1])/(2.*Delta);
double SDeformxx = dudx;
double SDeformxy = 0.5*(dudy + dvdx);
double SDeformxz = 0.5*(dudz + dwdx);
double SDeformyx = SDeformxy;
double SDeformyy = dvdy;
double SDeformyz = 0.5*(dvdz + dwdy);
double SDeformzx = SDeformxz;
double SDeformzy = SDeformyz;
double SDeformzz = dwdz;
double sqterm = 2.*dv()*(sq(SDeformxx) + sq(SDeformxy) + sq(SDeformxz) +
sq(SDeformyx) + sq(SDeformyy) + sq(SDeformyz) +
sq(SDeformzx) + sq(SDeformzy) + sq(SDeformzz)) ;
rateWater += mu1/rho[]*f[]*sqterm; //water
rateAir += mu2/rho[]*(1. - f[])*sqterm; //air
}
rates[0] = rateWater;
rates[1] = rateAir;
return 0;
}We also want to count the drops and bubbles in the flow.
event countDropsBubble(i++)
{
scalar m1[]; //droplets
scalar m2[]; //bubbles
foreach(){
m1[] = f[] > 0.5; //i.e. set m true if f[] is close to unity (droplets)
m2[] = f[] < 0.5; //m true if f[] close to zero (bubbles)
}
int n1 = tag(m1);
int n2 = tag(m2);Having counted the bubbles, now we find their size. This example is similar to the jet atomization problem. We are interested in the volumes and positions of each droplet/bubble.
double v1[n1]; //droplet
coord b1[n1]; //droplet
double v2[n2]; //bubble
coord b2[n2]; //bubbleWe initialize:
for (int j=0; j<n1; j++)
v1[j] = b1[j].x = b1[j].y = b1[j].z = 0.0;
for (int j=0; j<n2; j++)
v2[j] = b2[j].x = b2[j].y = b2[j].z = 0.0;We proceed with calculation.
foreach_leaf() {
// droplets
if (m1[] > 0) {
int j = m1[] - 1;
v1[j] += dv()*f[]; //increment the volume of the droplet
coord p = {x,y,z};
foreach_dimension()
b1[j].x += dv()*f[]*p.x;
}
// bubbles
if (m2[] > 0) {
int j = m2[] - 1;
v2[j] += dv()*(1.0-f[]);
coord p = {x,y,z};
foreach_dimension()
b2[j].x += dv()*(1.0-f[])*p.x;
}
}Reduce for MPI.
#if _MPI
MPI_Allreduce (MPI_IN_PLACE, v1, n1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
MPI_Allreduce (MPI_IN_PLACE, b1, 3*n1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
MPI_Allreduce (MPI_IN_PLACE, v2, n2, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
MPI_Allreduce (MPI_IN_PLACE, b2, 3*n2, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
#endifOutput the volume and position of each droplet to file.
static FILE * fdrop = fopen("droplets.dat","w");
static FILE * fbubb = fopen("bubbles.dat","w");
for (int j=0; j<n1; j++)
fprintf (fdrop, "%d %g %d %g %g %g\n", i, t,
j, v1[j], b1[j].x/v1[j], b1[j].y/v1[j]);
for (int j=0; j<n2; j++)
fprintf (fbubb, "%d %g %d %g %g %g\n", i, t,
j, v2[j], b2[j].x/v2[j], b2[j].y/v2[j]);
}We log the evolution of the kinetic and potential energies and dissipation rate as functions of the non-dimensional time.
event graphs (i++) {
static FILE * fpwater = fopen("budgetWater.dat", "w");
static FILE * fpair = fopen("budgetAir.dat", "w");
double ke = 0., gpe = 0.;
double spe = 0.;
double keAir = 0., gpeAir = 0.;
foreach(reduction(+:ke) reduction(+:gpe) reduction(+:spe)
reduction(+:keAir) reduction(+:gpeAir)) {
double norm2 = 0.;
foreach_dimension()
norm2 += sq(u.x[]);
ke += rho[]*norm2*f[]*dv();
keAir += rho[]*norm2*(1.0-f[])*dv();
gpe += rho1*g_*y*f[]*dv();
gpeAir += rho2*g_*y*(1.0-f[])*dv();
if (interfacial (point, f)) {
coord n = interface_normal(point, f), pp;
double alpha = plane_alpha (f[], n);
double ar = pow(Delta, dimension - 1)*plane_area_center (n, alpha, &pp);
spe += ar*sigmaf[];
}
}
double rates[2];
dissipation_rate(rates);
double dissWater = rates[0];
double dissAir = rates[1];
if (i == 0) {
fprintf (fpwater, "t ke gpe dissipation spe\n");
fprintf (fpair, "t ke gpe dissipation spe\n");
}
fprintf (fpwater, "%g %g %g %g %g\n",
t/(k_/sqrt(g_*k_)), ke/2., gpe + 0.125, dissWater, spe);
fprintf (fpair, "%g %g %g %g\n",
t/(k_/sqrt(g_*k_)), keAir/2., gpeAir + 0.125, dissAir);
fprintf (ferr, "%g %g %g %g %g\n",
t/(k_/sqrt(g_*k_)), ke/2., gpe + 0.125, dissWater, spe);
}Visualisation
event movies (t += 0.01) {
scalar omega[];
vorticity (u, omega);
foreach(){
gamma2[] = c1[]*4.*EPSILON/gamma0;
}
#if dimension == 2
view (width = 800, height = 600, fov = 18.8);
clear();We repeat the drawing periodically in the x-direction.
for (double x = -L0; x <= L0; x += L0)
translate (x) {
draw_vof ("f");
squares ("omega", linear = true, map = cool_warm , min=-10.0, max=10.0);
}
{
static FILE * fp = POPEN ("vor", "a");
save (fp = fp);
fflush (fp);
}#else // dimension == 3
view (width = 1600, height = 1200, theta = pi/4, phi = -pi/6, fov = 20);
clear();
for (double x = -2*L0; x <= L0; x += L0)
translate (x) {
squares ("omega", linear = true, n = {0,0,1}, alpha = -L0/2);
for (double z = -3*L0; z <= L0; z += L0)
translate (z = z)
draw_vof ("f");
}
save ("below.mp4");
view (width = 1600, height = 1200, theta = pi/4, phi = pi/6, fov = 20);
clear();
for (double x = -2*L0; x <= L0; x += L0)
translate (x) {
squares ("omega", linear = true, n = {0,0,1}, alpha = -L0/2);
for (double z = -3*L0; z <= L0; z += L0)
translate (z = z)
draw_vof ("f");
}
#endif // dimension == 3
save ("movie.mp4");
}Dump/restore
To be able to restart, we dump the entire simulation at regular intervals.
scalar stress2[];
scalar stx[];
scalar sty[];
event snapshot (t += 0.5) {
foreach(){
gamma2[] = c1[]*4.*EPSILON;
}
char filename[100];
sprintf(filename, "dat/Ma%g-Bo%g-ak%g-%d-%g",MA,BO,ak,(1 << LEVEL),t);
foreach_dimension () {
iforce.x.nodump = false;
}
dump(filename);
foreach_dimension () {
iforce.x.nodump = true;
}
}End
The wave period is k_/sqrt(g_*k_). We want to run up to
2 (alternatively 4) periods.
Mesh adaptation
On trees, we adapt the mesh according to the error on volume fraction and velocity.
#if TREE
event adapt (i++) {
double femax = 0.001;
double uxemax = 0.005;
double uyemax = 0.005;
double uzemax = 0.005;
double c1emax = 0.001;
double pfemax = 0.001;
adapt_wavelet ({f,u,pfield,c1}, (double[]){femax,uxemax,uyemax,uzemax,pfemax,c1emax}, LEVEL);
}
#endifFunctions to extract surface quantities
static int compare (const void * a, const void * b)
{
const double * A = (const double *) a;
const double * B = (const double *) b;
// sort by first column (x)
if (A[0] < B[0]) return -1;
if (A[0] > B[0]) return 1;
return 0;
}We want to compute some quantities at the interface.
void output_int_qtn (char * fname, int istep,
scalar c, scalar sca,
double stp_eta)
{
// We first loop over all the interfacial points
// and we count them (per processor)
int int_pt = 0;
foreach (serial) {
if (interfacial (point, c)) {
if (point.level == LEVEL) {
coord n = interface_normal (point, c), pp;
double alpha1 = plane_alpha (c[], n);
plane_area_center (n, alpha1, &pp);
// we compute centroid coordinates (used later)
double xc = x + Delta*pp.x;
double yc = y + Delta*pp.y + stp_eta;
(void) xc; (void) yc; // silence warnings in case you later edit outputs
#if dimension > 2
double zc = z + Delta*pp.z;
(void) zc;
#endif
// Stay on the current interfacial cell (no locate/Point reassignment)
int_pt++;
}
}
}
int tot_column = 4;
double t_mat[int_pt][tot_column];
for (int j = 0; j < tot_column; j++)
for (int i = 0; i < int_pt; i++)
t_mat[i][j] = 0.;
fprintf (stderr, "First pass over interfacial points\n");
scalar pos[];
#if dimension > 2
coord G = {0.,1.,0.}, Z = {0.,0.,0.};
#else
coord G = {0.,1.}, Z = {0.,0.};
#endif
position (c, pos, G, Z);
int count = 0;
foreach (serial) {
if (interfacial (point, c)) {
if (point.level == LEVEL) {
coord n = interface_normal (point, c), pp;
double alpha1 = plane_alpha (c[], n);
plane_area_center (n, alpha1, &pp);
double eta = pos[];
double xc = x + Delta*pp.x;
double yc = y + Delta*pp.y + stp_eta;
(void) yc; // yc not otherwise used unless you re-enable interpolation
#if dimension > 2
double zc = z + Delta*pp.z;
#endif
t_mat[count][0] = xc;
#if dimension > 2
t_mat[count][1] = zc;
#else
t_mat[count][1] = 0.;
#endif
t_mat[count][2] = sca[];
t_mat[count][3] = eta; // already defined at the interface
count++;
}
}
}
fprintf (stderr, "Second pass over interfacial points\n");
// We sort locally t_mat by the x coordinate (the first, i.e. 0-th, column)
qsort (t_mat, int_pt, tot_column*sizeof(double), compare);
fprintf (stderr, "First sort\n");
double tot_row;
#if _MPI
// On multiple cores, we gather all the int_pt to the root pid
// and, then, we broadcast this information to all the processes
int nproc;
MPI_Comm_size (MPI_COMM_WORLD, &nproc);
int counts_it[nproc];
if (pid() == 0) {
MPI_Gather (&int_pt, 1, MPI_INT, counts_it, 1, MPI_INT, 0, MPI_COMM_WORLD);
} else {
MPI_Gather (&int_pt, 1, MPI_INT, NULL, 1, MPI_INT, 0, MPI_COMM_WORLD);
}
MPI_Bcast (counts_it, nproc, MPI_INT, 0, MPI_COMM_WORLD);
// Each processor knows the int_pt of the others. So we can compute
// the displacement, the total number of interfacial points and
// the number of elements owned by each processor
int tot_int_pt = 0;
int tot_el_p[nproc], disp_r[nproc], disp[nproc];
for (int i = 0; i < nproc; i++) {
disp_r[i] = tot_int_pt;
disp[i] = disp_r[i]*tot_column;
tot_int_pt += counts_it[i];
tot_el_p[i] = counts_it[i]*tot_column;
}
tot_row = tot_int_pt;
// --> Gather to the root pid
// --> Sort by first column
double t_mat_tot[tot_int_pt][tot_column];
if (pid() == 0) {
int tot_el_p0[nproc], disp0[nproc];
for (int i = 0; i < nproc; i++) {
tot_el_p0[i] = tot_el_p[i];
disp0[i] = disp[i];
}
MPI_Gatherv (&t_mat, int_pt*tot_column, MPI_DOUBLE,
t_mat_tot, tot_el_p0, disp0, MPI_DOUBLE,
0, MPI_COMM_WORLD);
fprintf (stderr, "GatherV 0\n");
qsort (t_mat_tot, tot_int_pt, tot_column*sizeof(double), compare);
fprintf (stderr, "Second sort 0\n");
}
else {
int tot_el_p1[nproc], disp1[nproc];
for (int i = 0; i < nproc; i++) {
tot_el_p1[i] = tot_el_p[i];
disp1[i] = disp[i];
}
MPI_Gatherv (&t_mat, int_pt*tot_column, MPI_DOUBLE,
NULL, tot_el_p1, disp1, MPI_DOUBLE,
0, MPI_COMM_WORLD);
}
#else
tot_row = int_pt;
double t_mat_tot[int_pt][tot_column];
for (int j = 0; j < tot_column; j++)
for (int i = 0; i < int_pt; i++)
t_mat_tot[i][j] = t_mat[i][j];
#endif
if (pid() == 0) {
fflush (stderr);
FILE * eta_loc = fopen (fname, "w");
// Print in ASCII format
for (int i = 0; i < tot_row; i++) {
fprintf (eta_loc, "%8E %8E %8E %8E\n",
t_mat_tot[i][0], t_mat_tot[i][1],
t_mat_tot[i][2], t_mat_tot[i][3]);
}
fclose (eta_loc);
fflush (eta_loc);
}
fprintf (stderr, "Print\n");
}
event eta_loc (t += 0.01)
{
fflush (stderr);
char etaname_in[100];
sprintf (etaname_in, "./eta/eta_loc_t%09d.out", i);
double stp_eta = 0.0*(L0/pow(2.0,LEVEL)); // it corresponds to 0*Delta
boundary ({gamma2});
output_int_qtn (etaname_in, i, f, gamma2, stp_eta);
fflush (stderr);
if (pid() == 0) {
char name_1[80];
sprintf (name_1,"./log_eta.out");
FILE * log_sim = fopen (name_1,"a");
fprintf (log_sim, "%8E %8E\n", t, 1.0*i);
fclose (log_sim);
}
}