sandbox/acastillo/output_fields/profiles_foreach_region.h
Profile functions
average_foreach_region(): Averages over a specified region.
This function calculates the average of a list of scalar fields
within a specified region using foreach_region(). Fields
are weighted by the field w. The function uses parallel
reduction to accumulate values and weights, then normalizes the
accumulated values.
\tilde{Q} \approx \begin{cases} \dfrac{\iint w(x,y,t) Q(x,y,t)~dx}{\iint w(x,y,t) ~dx } & \text{ if 2D} \\ \\ \dfrac{\iint w(x,y,t) Q(x,y,t)~dx~dy}{\iint w(x,y,t) ~dx~dy } & \text{ if 3D} \end{cases}
The arguments and their default values are:
- list
 - Pointer to the list of scalar fields.
 - w
 - Scalar field containing the weights.
 - v
 - Array to store the calculated averages
 - hprof
 - Coordinate of the plane (default: 0.)
 - n
 - number of points along each dimension. Default is N.
 - linear
 - use first-order (default) or bilinear interpolation.
 - box
 - the lower-left and upper-right coordinates of the domain to consider. Default is the entire domain.
 
double average_foreach_region(scalar *list, scalar w, double *v, double hprof = 0., coord box[2] = {{X0, hprof}, {X0 + L0, hprof}}, coord n = {N, 1})
{
  int len = list_len(list); // Get length of the scalar list
  int m = 0;                // Counter for points within the y-range
  double a = 0 ;            // Accumulator for weights
  
  coord p;
  NOT_UNUSED(len);
  // Main loop: Iterate over the specified region
  foreach_region(p, box, n, reduction(+ : a) reduction(+ : m) reduction(+ : v[:len])){
    m++;
    // Calculate weight factor (cell volume)
    double b = 1. / Delta ;
    foreach_dimension(){
      b *= Delta;
    }
    
    if (w.i == unity.i){ // If no weights are provided    
      a += b;
    }
    else { // If weights are provided  
      a += interpolate_linear(point, w, p.x, p.y, p.z) * b;
    }
    
    // Accumulate weighted values for each scalar field      
    int k = 0;
    if (w.i == unity.i){ // If no weights are provided    
      for (scalar s in list){
        v[k++] += interpolate_linear(point, s, p.x, p.y, p.z) * b;
      }
    }
    else {// If weights are provided  
      for (scalar s in list){
        v[k++] += interpolate_linear(point, s, p.x, p.y, p.z) * interpolate_linear(point, w, p.x, p.y, p.z) * b;
      }
    }
  }
  // Normalize accumulated values
  for (int g = 0; g < len; g++){
    v[g] /= a;
  }
  // Return average cell size or its square root, depending on dimension
#if (dimension == 2)
  return a / (double)m;
#else
  return sqrt(a / (double)m);
#endif
}profile_foreach_region(): Generates profiles for a list of scalar fields and writes them to a file.
This profiling function employs the same profiling strategy as the
void profile() function presented here.
However, this function utilizes foreach_region() and
optional arguments.
A profile with n points between hmin and
hmax is generated by averaging every field in
list over m (or m*m if in 3D)
equally spaced points. The resulting profile is then stored in a file
named filename.
The arguments and their default values are:
- list
 - 
List of scalar fields (default: 
all) - w
 - 
Weights field (default: 
unity) - filename
 - 
Output file name (default: 
profiles.asc) - hmin
 - 
Lower y (or z if 3D) coordinate (default: 
Y0 + _mindelta) - hmax
 - 
Upper y (or z if 3D) coordinate (default:
Y0 + L0 - _mindelta) - rf
 - 
Reduction factor of query heights (default: 
1) - n
 - 
number of points along the profile. Default is 
N. - m
 - 
number of points along each direction of sampled region. Default is
N. 
Usage
  scalar * list = {Y,u};
  profile_foreach_region(list, filename="profiles.asc");which should write a file
#y@0	Y	u.x	u.y	
-0.499023438	1	0.203056828	-0.00047600522
-0.497070313	1	0.203056828	-0.00047600522
-0.495117188	1	0.203056828	-0.00047600522
-0.493164063	1	0.203056828	-0.00047600522
...
see, also example 1.
#define _mindelta (L0 / (double)(1 << (grid->maxdepth + 1)))
void profile_foreach_region(scalar *list = all,                                  
                            scalar w = unity,
                            char *filename = "profiles.asc",                                  
                            double hmin = Z0 + _mindelta,
                            double hmax = Z0 + L0 - _mindelta,
                            double xmin = X0,
                            double xmax = X0 + L0,
                            double ymin = Y0,
                            double ymax = Y0 + L0,
                            double rf = 1,
                            int n = N,
                            int m1 = N,
                            int m2 = N,
                            const char *mode = "a") {
  double deltahn = (hmax - hmin) / ((double)n - 0.99999999);
  FILE *fp = NULL;
  int len = list_len(list);
  
  // The primary worker (pid 0) handles file writing
  if (pid() == 0) {
    fp = fopen(filename, mode);
    if (fp == NULL) {
      perror(filename);
      exit(1);
    }
    // Write header
    fprintf(fp, "#y@%g\t", t);
    for (scalar s in list)
      fprintf(fp, "%s\t", s.name);
    fprintf(fp, "\n");
  }
  double hprof = hmin;
  
  // Iterate over different y-coordinates (in 2D) or z-coordinates (in 3D)
  while (hprof <= hmax) {
    // Define the region of interest
    #if dimension == 2
      coord box[2] = {{xmin, hprof}, {xmax, hprof}};
      coord nsamples = {m1, 1};
    #else
      coord box[2] = {{xmin, ymin, hprof}, {xmax, ymax, hprof}};
      coord nsamples = {m1, m2, 1};
    #endif
    // Calculate averages for the current region
    double aver[len];
    memset(&aver, 0, sizeof(aver));
    double deltah = average_foreach_region(list, w, aver, hprof, box, nsamples);
    // Write results to file (primary worker only)
    if (pid() == 0) {
      for (int k = 0; k < len; k++) {
        if (k == 0) {
          fprintf(fp, "%.9g\t%.9g", hprof, aver[k]);
        }
        else {
          fprintf(fp, "\t%.9g", aver[k]);
        }
      }
      fprintf(fp, "\n");
    }
    // Calculate next y- (or z-) coordinate
    deltah = deltahn / rf;
    hprof += rf * deltah;
  }
  // Close file (primary worker only)
  if (pid() == 0) {
    fprintf(fp, "\n");
    fflush(fp);
    if (fp != stdout)
      fclose(fp);
  }
}
#undef _mindelta