sandbox/Antoonvh/mortcscart.c

    Morton versus Cartesian indexing

    On this page we test the socalled “locality” of a morton-style interator versus a regular Cartesian iterator. We test it for a 32^3 grid and assume that our results are somehow scaleable to other grids. We focus the analysis on the distance in iteration-sequence space between cells that are neighbors in the 3D-grid space

    #include "grid/octree.h"
    
    scalar m[],xyz[];
    int main(){
      int maxlevel = 5;
      int cells = pow(2,3*maxlevel); 
      double cartarr[cells];
      double mortarr[cells];
      int i=0;
      while (i<cells){
        cartarr[i]=0.;
        mortarr[i]=0.;
        i++;
      }

    The grid is initialized and we use the foreach() loop for the Morton-style iteration and store the indixes in field s.

      init_grid(1<<maxlevel);
      int a=1;
      foreach()
        m[]=a++;
      a=1;
      int o = 1+BGHOSTS;

    For the Cartesian-style indexing, we define a x-y-z-sequence iterator. The result is stored in the xyz field.

      for (int k= o; k<N+o; k++){
        for (int j= o; j<N+o; j++){
          for (int i= o; i<N+o; i++){
    	Point point;
    	point.i=i; point.j=j; point.k=k; point.level=maxlevel;
    	xyz[]=a++;
          }
        } 
      }
      double distcart=0;
      double distmort=0;

    Below we perform our analysis. Foreach cell we log the distance to three of its face-sharing neighbors. The boundary-ghost-cell values are set using the default scalar-field boundary condtion. This way, the index distance to ghost cells is 0 and does not ‘pollute’ the results. We define a total distance that is the sum of all individual neighbours’ distances.

      boundary(all);
      foreach(){
        double cart=xyz[];
        double mort=m[];
        foreach_dimension(){
          double cd = fabs(cart-xyz[1,0,0]);
          double md = fabs(mort-m[1,0,0]);
          distcart += cd;
          distmort += md;

    Remarkably(?), the total ‘index distance’ to neighbors is exactly equal for both approaches (i.e. N^2(N^2(N-1))+N(N^2(N-1))+(N^2(N-1))\propto N^5) for a N^3 grid). Therefore we check the underlying distribution of the indexing distances.

          cartarr[(int)(cd+0.5)]++;
          mortarr[(int)(md+0.5)]++;
        }
      }
      FILE * fp = fopen("hist","w");
      i=1;
      while (i<cells){
        fprintf(fp,"%d\t%g\t%g\n",i,cartarr[i],mortarr[i]);
        i++;
      }
    Below, the histrogram of the index distances between neighbors is shown:
    set xr [0.5 :100001]
    set yr [0.5 :80000]
    set logscale y
    set logscale x
    set xlabel 'Indexing distance'
    set ylabel 'Number of occurences'
    plot 'hist' u 1:2 w lines lw 3 t 'Cartesian-style' ,\
    'hist' u 1:3 w lines lw 3 t 'Morton-style'
    Notice the logaritmic x and y axes (script)

    Notice the logaritmic x and y axes (script)

    We can see that the Cartesian style indexing has resulted in three-values for its index distances. (1,N and N^2). The Morton-style curve has index distance values for each power of two. Compared to the Cartesian-style index distances; there are more neigbors with an index distance smaller than N, but the Morton-style indexing pays with more cells at an index distance larger than N^2. Remember, the (total) first order moment associated with each histrogram is equal!

    }