sandbox/vheusinkveld/myfunctions/equidistant/averaging.h

    Short intro

    This page is to explain the equidistant averaging function. Notes on convergence in time and space can be respectively found here and here. Note that the convergence in space is carried out only for a constant high resolution grid, since the errors of the low grid values will dominate the higher resolution ones. Having a combination of resolutions is left as an exercise.

    The functions

    NOTE: Very much in progress.

    These functions are geared towards equidistant diagnostics. The level for which diagnostics are done can be specified. Values will be linearly interpolated if necesarry.

    So far this function works with MPI and only works in 3D.

    Short description of what they do:

    //void equi_diag(scalar s, int lvl, int diagi) { adds values to the equifield array }

    //void equi_output_ascii (scalar s, char * fname, int lvl, int diagi) { outputs equifield array to ascii file fname in the format: place = xnn + y*n + z data is devided by diagi to average }

    //void equi_output_binary(scalar s, char * fname, int lvl, int diagi)i { outputs equifield to file binary fname in the format: place = xnn + y*n + z }

    //void equi_import_binary (scalar s, char * fname, int lvl) { imports data written by the equi_output_binary(…) function data is read into scalar s, no interpolation is used. }

    TODO implement 2D TODO walking average since values in equifield could get big, or divide before summing? TODO multiple fields at once?

    double *equifield = NULL; 	// The diagnostics field
    
    int equi_diag (scalar s, int lvl, int diagi){  
        int len = 1;		
        int n = 1<<lvl;
        if(!equifield) {
            equifield = calloc(len*n*n*n, sizeof(double)); // Init with zeros
        } 	
    
        double dDelta = 0.9999999*L0/n;  
    
        restriction({s}); 		// Make sure that coarse level values exist
        boundary({s}); 		// Update boundaries
        
        // Iterate over diag level of leaf cell
        foreach_level_or_leaf(lvl) {
      	if(level < lvl){
    	    int pn = 1<<(lvl-level);
    	    for(int i = 0; i < pn; i++) {
    		for(int j = 0; j < pn; j++) {
    		    for(int k = 0; k < pn; k++) {
    			
    			double ctrans = dDelta/2. - Delta/2.;	  // Translation to corner of cell
    			double xx = x + ctrans + i*dDelta;   	  // Coordinates in equidistant grid
    			double yy = y + ctrans + j*dDelta;
     			double zz = z + ctrans + k*dDelta;
    
    		        int ii = round((xx - dDelta/2.)/dDelta);  // Iteration in equidistant grid
    	         	int jj = round((yy - dDelta/2.)/dDelta);
                	  	int kk = round((zz - dDelta/2.)/dDelta);
    
    	    		int place = ii*n*n + jj*n + kk*len;  	  // Location in equidistant grid 
    			double temp = interpolate(s, xx, yy, zz); // Linear interpolation 
    
     			equifield[place] += temp;
    		    }
    		}
    	    }
    
            } else {
     
                int ii = round((x - dDelta/2.)/dDelta); // x adaptive is x equidistant 
           	    int jj = round((y - dDelta/2.)/dDelta); // Derive place in equidistant grid
         	    int kk = round((z - dDelta/2.)/dDelta);
    
    	    int place = ii*n*n + jj*n + kk*len;
    	    equifield[place] += s[];
    	}
        }
        return diagi + 1;
    }

    Output equidistant double field to double binary file

    void equi_output_binary (scalar s, char * fname, int lvl, int diagi) {    
        int len = 1;
        int n = 1<<lvl;
    
        if(pid() == 0){
        FILE * fpm = fopen(fname, "w");     
    // Make sure all thread values are summed up using MPI
    @if _MPI
        MPI_Reduce (MPI_IN_PLACE, equifield, len*n*n*n, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
    @endif
        int sizef = sizeof(double);
        int len = 1;
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                for(int k = 0; k < n; k++) {
    		int place = i*n*n + j*n + k*len;
    		double temp = (double)(equifield[place]/((double)diagi)); // Divide by number of additions
    	        fseek(fpm, place*sizef, SEEK_SET);
        		fwrite(&temp, sizef, 1, fpm); ;
    	    }
    	}    
        }
        fclose(fpm);	
        }
    @if _MPI
        else // slave
        MPI_Reduce (equifield, NULL, len*n*n*n, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
    @endif
    }

    Output equidistant double field to ascii file

    void equi_output_ascii (scalar s, char * fname, int lvl, int diagi) {
        int len = 1;
        int n = 1<<lvl;
    
        if(pid() == 0){
        FILE * fpm = fopen(fname, "w"); 
    // Make sure all thread values are summed up using MPI
    @if _MPI
        MPI_Reduce (MPI_IN_PLACE, equifield, len*n*n*n, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
    @endif
        int len = 1;
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                for(int k = 0; k < n; k++) {
    		int place = i*n*n + j*n + k*len;
    		double temp = (equifield[place]/((double)diagi)); // Divide by number of additions
    	        fprintf(fpm, "%g\t", temp);
    	    }
    	}    
        }
        fclose(fpm);	
        }
    @if _MPI
        else // slave
        MPI_Reduce (equifield, NULL, len*n*n*n, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
    @endif
    }

    Importing binary doubles from file written by equi_output_binary(…) It is a bit bodged together but for my application it seems fast enough.

    Array equifield is filled with the imported data after which a scalar field is filled.

    void equi_import_binary (scalar s, char * fname, int lvl){  
        int len = 1;		
        int n = 1<<lvl;
    
        free(equifield);	// Make sure equifield is reset 
        equifield = NULL;	
        
        if(!equifield) {
            equifield = calloc(len*n*n*n, sizeof(double)); // Init with zeros
        } 	
    
        double dDelta = 0.9999999*L0/n;  
    
        if(pid() == 0){
        FILE * fpm = fopen(fname, "r");     
        int sizef = sizeof(double);
        // Fill equifield array
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++) {
                for(int k = 0; k < n; k++) {
    		int place = i*n*n + j*n + k*len;
    		fseek(fpm, place*sizef, SEEK_SET);
        		fread(&equifield[place], sizef, 1, fpm); ;
    	    }
    	}    
        }
        fclose(fpm);	
        }
    
    @if _MPI 
        MPI_Allreduce (MPI_IN_PLACE, equifield, len*n*n*n, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
    @endif
    	
    
        // Filling each cell with respective value
        foreach() {
      	if(level < lvl){
     	    double aveval = 0.;
    	    int pn = 1<<(lvl-level);
    	    for(int i = 0; i < pn; i++) {
    		for(int j = 0; j < pn; j++) {
    		    for(int k = 0; k < pn; k++) {
    			
    			double ctrans = dDelta/2. - Delta/2.;	// Translation to corner of cell
    			double xx = x + ctrans + i*dDelta;   	// Coordinates in equidistant grid
    			double yy = y + ctrans + j*dDelta;
     			double zz = z + ctrans + k*dDelta;
    
    		        int ii = round((xx - dDelta/2.)/dDelta); // Iteration in equidistant grid
    	         	int jj = round((yy - dDelta/2.)/dDelta);
                	  	int kk = round((zz - dDelta/2.)/dDelta);
    
    	    		int place = ii*n*n + jj*n + kk*len;	// Location in equidistant grid 
    
     			aveval += equifield[place];
    		    }
    		}
    	    }
    	    s[] = 1.*aveval/cube(pn);
    
            } else {
     
                int ii = round((x-dDelta/2)/dDelta); 
           	    int jj = round((y-dDelta/2)/dDelta); 
         	    int kk = round((z-dDelta/2)/dDelta);
    
    	    int place = ii*n*n + jj*n + kk*len;
    	    s[] = 1.* equifield[place];
    	}
        }
    }