gem5/splash2/codes/apps/raytrace/hutv.C
Sanchayan Maity 2fcc51c2c1 Commit splash2 benchmark
While at it also add the libpthread static library amd m5op_x86
for matrix multiplication test code as well.

Note that the splash2 benchmark code does not comply with gem5
coding guidelines. Academic guys never seem to follow 80 columns
and no whitespace guideline :(.
2017-04-26 20:50:15 +05:30

1005 lines
28 KiB
C

/*************************************************************************/
/* */
/* Copyright (c) 1994 Stanford University */
/* */
/* All rights reserved. */
/* */
/* Permission is given to use, copy, and modify this software for any */
/* non-commercial purpose as long as this copyright notice is not */
/* removed. All other uses, including redistribution in whole or in */
/* part, are forbidden without prior written permission. */
/* */
/* This software is provided with absolutely no warranty and no */
/* support. */
/* */
/*************************************************************************/
/*
* NAME
* hutv.c
*
* DESCRIPTION
*
*/
#include <cmath>
#include <cstdio>
#include "rt.h"
/*
* eps_t is a small increment in t to be added to t_in to insure that the
* point is inside a cell not on the boundary.
*/
REAL eps_t = 1.0E-10;
/*
* NAME
* prn_tv_stats - print out HU traversal statistics -- not implemented in
* this version
*
* SYNOPSIS
* VOID prn_tv_stats()
*
* RETURNS
* Nothing.
*/
VOID prn_tv_stats()
{
}
/*
* NAME
* send_ray(r, v) - send ray to remote cluster
*
* SYNOPSIS
* INT send_ray(r, v)
* RAY *r;
* VOXEL *v;
*
* DESCRIPTION
* Not implemented yet.
*
* RETURNS
* Nothing, yet.
*/
INT send_ray(RAY *r, VOXEL *v)
{
return(0);
}
/*
* NAME
* lookup_hashtable -
*
* SYNOPSIS
* VOXEL *lookup_hashtable(indx, g)
* INT indx;
* GRID *g;
*
* DESCRIPTION
* Hashtable is a table of all non-empty cells in the grid.
* hashtable[num_buckets] is indexed by index1D mod num_buckets,
* num_buckets and n, the # of cells per axis, should be relatively
* prime, grids at different levels may have different num_buckets. This
* routine assumes that there exists a non-empty voxel in the table.
*
* RETURNS
*
*/
VOXEL *lookup_hashtable(INT indx, GRID *g)
{
INT i;
VOXEL *v;
i = indx - ((indx / g->num_buckets) * g->num_buckets);
v = g->hashtable[i];
while (v->id != indx)
{
v = v->next;
if (v == NULL)
{
fprintf(stderr, "hashtable error \n");
exit(-1);
}
}
return (v);
}
/*
* NAME
* lookup_emptycells -
*
* SYNOPSIS
* INT lookup_emptycells(indx, g)
* INT indx;
* GRID *g;
*
* DESCRIPTION
* Emptycells is a packed array of bits, one bit per cell in the grid. A
* 1 indicates that the cell is empty and therefore there is no entry for
* that cell in the hashtable.
*
* RETURNS
*
*/
INT lookup_emptycells(INT indx, GRID *g)
{
INT i, w, r, num_bits;
UINT p, b;
num_bits = sizeof(UINT)*8;
w = indx / num_bits;
r = indx - w * num_bits;
p = g->emptycells[w];
b = p & (MSB >> r);
i = b > 0 ? EMPTY : NONEMPTY;
return (i);
}
/*
* NAME
* pop_up_a_grid -
*
* SYNOPSIS
* VOID pop_up_a_grid(r)
* RAY *r;
*
* DESCRIPTION
* Pop_up_a_grid takes RAYINFO & a grid pointer off the top of the stack
* and discards it which puts the ray in the voxel containing the grid
* being left.
*
* RETURNS
* Nothing.
*/
VOID pop_up_a_grid(RAY *r)
{
RAYINFO *old_ri;
old_ri = r->ri;
r->ri = old_ri->next;
free_rayinfo(r);
}
/*
* NAME
* push_down_grid -
*
* SYNOPSIS
* VOID push_down_grid(r, v)
* RAY *r;
* VOXEL *v; Voxel containing the new grid.
*
* DESCRIPTION
* push_down_grid creates rayinfo for the new grid being entered and puts
* it on top of the stack.
*
* RETURNS
* Nothing.
*/
VOID push_down_grid(RAY *r, VOXEL *v)
{
INT n; /* # cells per axis in new grid. */
INT small;
INT i_in, i_out, i, il, ih;
REAL wc[3]; /* Entry point of grid in world coord.*/
REAL ti;
REAL del1, del2;
REAL t_in, t_out, tl, th;
REAL t[6], min[3];
GRID *new_g;
RAYINFO *new_ri;
RAYINFO *old_ri;
old_ri = r->ri;
new_g = (GRID *)v->cell;
new_ri = ma_rayinfo(r);
r->ri = new_ri;
new_ri->next = old_ri; /* Push new RAYINFO onto the stack. */
new_ri->grid = new_g;
n = new_g->indx_inc[1];
new_ri->delta[0] = old_ri->delta[0]/n;
new_ri->delta[1] = old_ri->delta[1]/n;
new_ri->delta[2] = old_ri->delta[2]/n;
if (old_ri->t_in >= 0.0)
{
/* Ray origin outside the voxel. */
new_ri->entry_plane = old_ri->entry_plane;
new_ri->t_in = old_ri->t_in;
ti = old_ri->t_in + eps_t;
}
else
{
/* Ray origin inside the voxel. */
ti= 0.0;
new_ri->entry_plane = -1; /* no entry plane calculated */
new_ri->t_in = old_ri->t_in;
}
wc[0] = ti*r->D[0] + r->P[0];
wc[1] = ti*r->D[1] + r->P[1];
wc[2] = ti*r->D[2] + r->P[2];
new_ri->index3D[0] = (INT)((wc[0] - new_g->min[0]) / new_g->cellsize[0]);
if (new_ri->index3D[0] < 0)
new_ri->index3D[0] = 0;
if (new_ri->index3D[0] >= n)
new_ri->index3D[0] = n - 1;
new_ri->index3D[1] = (INT)((wc[1] - new_g->min[1]) / new_g->cellsize[1]);
if (new_ri->index3D[1] < 0)
new_ri->index3D[1] = 0;
if (new_ri->index3D[1] >= n)
new_ri->index3D[1] = n - 1;
new_ri->index3D[2] = (INT)((wc[2] - new_g->min[2]) / new_g->cellsize[2]);
if (new_ri->index3D[2] < 0)
new_ri->index3D[2] = 0;
if (new_ri->index3D[2] >= n)
new_ri->index3D[2] = n - 1;
new_ri->index1D = new_ri->index3D[0] + new_ri->index3D[1]*n + new_ri->index3D[2]*new_g->indx_inc[2];
new_ri->indx_inc1D[0] = r->indx_inc3D[0];
new_ri->indx_inc1D[1] = r->indx_inc3D[1]*n;
new_ri->indx_inc1D[2] = r->indx_inc3D[2]*new_g->indx_inc[2];
switch (new_ri->entry_plane)
{
case 3: /* max X */
new_ri->entry_plane = 0;
case 0: /* min X */
new_ri->d[0] = new_ri->t_in + new_ri->delta[0];
del1 = fmod((double)(old_ri->d[1] - new_ri->t_in),
(double)new_ri->delta[1]);
if (del1 <= eps_t)
new_ri->d[1] = new_ri->t_in + new_ri->delta[1];
else
new_ri->d[1] = new_ri->t_in + del1;
del2= fmod((double)(old_ri->d[2] - new_ri->t_in),
(double)new_ri->delta[2]);
if (del2 <= eps_t)
new_ri->d[2] = new_ri->t_in + new_ri->delta[2];
else
new_ri->d[2] = new_ri->t_in + del2;
small = new_ri->d[0] <= new_ri->d[1] ? 0 : 1;
small = new_ri->d[small] <= new_ri->d[2] ? small : 2;
new_ri->t_out = new_ri->d[small];
new_ri->exit_plane = small;
break;
case 4: /* max Y */
new_ri->entry_plane = 1;
case 1: /* min Y */
new_ri->d[1] = new_ri->t_in + new_ri->delta[1];
del1 = fmod((double)(old_ri->d[0] - new_ri->t_in),
(double)new_ri->delta[0]);
if (del1 <= eps_t)
new_ri->d[0] = new_ri->t_in + new_ri->delta[0];
else
new_ri->d[0] = new_ri->t_in + del1;
del2 = fmod((double)(old_ri->d[2] - new_ri->t_in),
(double)new_ri->delta[2]);
if (del2 <= eps_t)
new_ri->d[2] = new_ri->t_in + new_ri->delta[2];
else
new_ri->d[2] = new_ri->t_in + del2;
small = new_ri->d[0] <= new_ri->d[1] ? 0 : 1;
small = new_ri->d[small] <= new_ri->d[2] ? small : 2;
new_ri->t_out = new_ri->d[small];
new_ri->exit_plane = small;
break;
case 5: /* max Z */
new_ri->entry_plane = 2;
case 2: /* min Z */
new_ri->d[2] = new_ri->t_in + new_ri->delta[2];
del1 = fmod((double)(old_ri->d[0] - new_ri->t_in),
(double)new_ri->delta[0]);
if (del1 <= eps_t)
new_ri->d[0] = new_ri->t_in + new_ri->delta[0];
else
new_ri->d[0] = new_ri->t_in + del1;
del2 = fmod((double)(old_ri->d[1] - new_ri->t_in),
(double)new_ri->delta[1]);
if (del2 <= eps_t)
new_ri->d[1] = new_ri->t_in + new_ri->delta[1];
else
new_ri->d[1] = new_ri->t_in + del2;
small = new_ri->d[0] <= new_ri->d[1] ? 0 : 1;
small = new_ri->d[small] <= new_ri->d[2] ? small : 2;
new_ri->t_out = new_ri->d[small];
new_ri->exit_plane = small;
break;
case -1: /* No entry plane calculated, origin inside voxel. */
min[0] = new_g->min[0] + new_ri->index3D[0]*new_g->cellsize[0];
min[1] = new_g->min[1] + new_ri->index3D[1]*new_g->cellsize[1];
min[2] = new_g->min[2] + new_ri->index3D[2]*new_g->cellsize[2];
if (r->D[0] == 0.0)
{
if (r->P[0] >= min[0] && r->P[0] <= min[0] + new_g->cellsize[0])
t[0] = -HUGE_REAL;
else
t[0] = HUGE_REAL;
}
else
t[0] = (min[0] - r->P[0]) / r->D[0];
if (r->D[1] == 0.0)
{
if (r->P[1] >= min[1] && r->P[1] <= min[1] + new_g->cellsize[1])
t[1] = -HUGE_REAL;
else
t[1] = HUGE_REAL;
}
else
t[1] = (min[1] - r->P[1]) / r->D[1];
if (r->D[2] == 0.0)
{
if (r->P[2] >= min[2] && r->P[2] <= min[2] + new_g->cellsize[2])
t[2] = -HUGE_REAL;
else
t[2] = HUGE_REAL;
}
else
t[2] = (min[2] - r->P[2]) / r->D[2];
if (r->D[0] == 0.0)
{
if (r->P[0] >= min[0] && r->P[0] <= min[0] + new_g->cellsize[0])
t[3] = HUGE_REAL;
else
t[3] = HUGE_REAL;
}
else
t[3] = (min[0] + new_g->cellsize[0] - r->P[0]) / r->D[0];
if (r->D[1] == 0.0)
{
if (r->P[1] >= min[1] && r->P[1] <= min[1] + new_g->cellsize[1])
t[4] = HUGE_REAL;
else
t[4] = HUGE_REAL;
}
else
t[4] = (min[1] + new_g->cellsize[1] - r->P[1]) / r->D[1];
if (r->D[2] == 0.0)
{
if (r->P[2] >= min[2] && r->P[2] <= min[2] + new_g->cellsize[2])
t[5] = HUGE_REAL;
else
t[5] = HUGE_REAL;
}
else
t[5] = (min[2] + new_g->cellsize[2] - r->P[2]) / r->D[2];
t_in = -HUGE_REAL;
i_in = -1;
t_out = HUGE_REAL;
i_out = -1;
for (i = 0; i < 3; i++)
{
if (t[i] < t[i + 3])
{
tl = t[i];
il = i;
th = t[i + 3];
ih = i + 3;
}
else
{
tl = t[i + 3];
il = i + 3;
th = t[i];
ih = i;
}
new_ri->d[i] = th;
// if (t_in < tl) /* max min */
if (t_in - tl < 0.0)
{
t_in = tl;
i_in = il;
}
// if (t_out > th) /* min max */
if (t_out - th > 0.0)
{
t_out = th;
i_out = ih;
}
}
// if ((t_in > t_out) || (t_out < 0.0))
if ((t_in - t_out > 0.0) || (t_out < 0.0))
{
fprintf(stderr, "push_down_grid: Ray origin not in voxel \n");
exit(-1);
}
if (i_in > 2)
i_in -= 3;
if (i_out > 2)
i_out -= 3;
new_ri->entry_plane = i_in;
new_ri->t_in = t_in;
new_ri->t_out = t_out;
new_ri->exit_plane = i_out;
break;
}
}
/*
* NAME
* step_grid -
*
* SYNOPSIS
* INT step_grid(r)
* RAY *r;
*
* DESCRIPTION
* Step to next voxel on grid and return index1D, updating RAYINFO in the
* process, return -1 if step carries off the current grid, index1D in
* RAYINFO is not valid if off the grid. Assume that ray & RAYINFO are
* all initialized and that the current point along the ray is in the
* cell indentified by index1D & index3D[3]. The corresponding grid and
* RAYINFO are on the top of their stacks resp.
*
* RETURNS
* Nothing.
*/
INT step_grid(RAY *r)
{
INT n; /* # cells per axis in grid. */
INT small; /* Index of closest cell boundary. */
INT *indx;
RAY *ra;
GRID *gr;
RAYINFO *rinfo;
ra = r;
rinfo = r->ri;
gr = rinfo->grid;
indx = gr->indx_inc;
n = indx[1]; /* n = r->ri->grid->indx_inc[1]; */
rinfo->t_in = rinfo->t_out;
rinfo->index3D[rinfo->exit_plane] += r->indx_inc3D[rinfo->exit_plane];
rinfo->entry_plane = rinfo->exit_plane;
if (rinfo->index3D[rinfo->exit_plane] < 0 || rinfo->index3D[rinfo->exit_plane] >= n)
{
/* Out of range, off the grid. */
return (-1);
}
else
{
/* Within current grid. */
rinfo->d[rinfo->exit_plane] += rinfo->delta[rinfo->exit_plane];
rinfo->index1D += rinfo->indx_inc1D[rinfo->exit_plane];
/* Update exit info. */
small = rinfo->d[0] <= rinfo->d[1] ? 0 : 1;
small = rinfo->d[small] <= rinfo->d[2] ? small : 2;
rinfo->t_out = rinfo->d[small];
rinfo->exit_plane = small;
return (rinfo->index1D);
}
}
/*
* NAME
* next_voxel -
*
* SYNOPSIS
* INT next_voxel(r)
* RAY *r;
*
* DESCRIPTION
* Next_voxel() may move up or down in the heirarchy and make appropriate
* adjustments to the stack. The routine returns the index1D of the next
* voxel. An index == -1 indicates the ray exited the space. Assume
* that ray & RAYINFO are all initialized and that the current point
* along the ray is in the cell indentified by index1D & index3D[3]. The
* corresponding grid and RAYINFO are on the top of their stacks resp.
*
* RETURNS
*
*/
INT next_voxel(RAY *r)
{
INT indx;
GRID *gr;
RAYINFO *rinfo;
while ((indx = step_grid(r)) == -1)
{
/* Step carried off grid. */
rinfo = r->ri;
gr = rinfo->grid;
if (gr->subdiv_level != 0)
{
pop_up_a_grid(r);
indx = r->ri->index1D;
}
else
{
/* Top level & off grid. */
/* Exited world space. */
return (-1);
}
}
return (indx);
}
/*
* NAME
* next_nonempty_voxel -
*
* SYNOPSIS
* VOXEL *next_nonempty_voxel(r)
* RAY *r;
*
* DESCRIPTION
* Next_nonempty_voxel() may move up or down in the heirarchy and make
* appropriate adjustments to the stack. The routine returns a pointer
* to the next nonempty voxel. A zero pointer indicates the ray exited
* the space. Assume that ray & RAYINFO are all initialized and that the
* current point along the ray is in the cell indentified by index1D &
* index3D[3]. The corresponding grid and RAYINFO are on the top of
* their stacks resp.
*
* RETURNS
* A pointer to the next nonempty voxel.
*/
VOXEL *next_nonempty_voxel(RAY *r)
{
INT indx;
VOXEL *v;
GRID *gr;
RAYINFO *rinfo;
indx = next_voxel(r);
if (indx < 0)
return (NULL);
rinfo = r->ri;
gr = rinfo->grid;
while (lookup_emptycells(indx, gr) == EMPTY)
{
indx = next_voxel(r);
if (indx < 0) {
return (NULL);
}
rinfo = r->ri;
gr = rinfo->grid;
}
/* Found a nonempty cell. */
v = lookup_hashtable(indx, gr);
return (v);
}
/*
* NAME
* next_nonempty_leaf -
*
* SYNOPSIS
* VOXEL *next_nonempty_leaf(r , step, status)
* RAY *r;
* INT step;
* INT *status;
*
* Step = 1 implies step & move up/down in the heirarchy to a leaf node.
* Step = 0 implies move through the heirarchy to a nonempty leaf node,
* stepping to the next voxel if necessary.
*
* DESCRIPTION
* Next_nonempty_leaf steps to the next nonempty leaf node moving up or
* down in the heirarchy as required and makes appropriate adjustments to
* the stack. If the routine is called with step = 0, then the ray must
* be in a nonempty voxel to begin with and will move to the first
* nonempty leaf without stepping if possible.
*
* The routine returns a pointer to the next nonempty voxel. A zero
* pointer indicates that a nonempty voxel was not found and the status
* word can be consulted to determine why. If the voxel is in a remote
* cluster, the ray is sent to that cluster and NULL is returned.
*
* Assume that ray & RAYINFO are all initialized and that the current
* point along the ray is in the cell indentified by index1D &
* index3D[3]. The corresponding RAYINFO are on the top of their stacks
* resp.
*
* RETURNS
* Nothing.
*/
VOXEL *next_nonempty_leaf(RAY *r, INT step, INT *status)
{
INT indx;
VOXEL *v;
RAYINFO *rinfo;
if (step == STEP)
v = next_nonempty_voxel(r);
else
{
/* Only used by init_ray when step == 0. */
rinfo = r->ri;
v = lookup_hashtable(rinfo->index1D, rinfo->grid);
}
if (v == NULL)
{
*status = EXITED_WORLD;
return (v);
}
/* Nonempty voxel either a GRID or a nonempty leaf. */
while (v->celltype == REMOTE_GRID || v->celltype == GSM_GRID)
{
if (v->celltype == REMOTE_GRID)
{
send_ray(r, v);
*status = SENT_TO_REMOTE;
return (NULL);
}
push_down_grid(r, v);
rinfo = r->ri;
indx = rinfo->index1D;
if (lookup_emptycells(indx, rinfo->grid) != EMPTY)
{
v = lookup_hashtable(indx, rinfo->grid);
if (v->celltype != REMOTE_GRID && v->celltype != GSM_GRID)
{
/* Nonempty leaf. */
if (v->celltype == REMOTE_VOXEL)
{
send_ray(r, v);
*status = SENT_TO_REMOTE;
return (NULL);
}
return (v);
}
/* Nonempty grid so do another while loop. */
}
else
{
v = next_nonempty_leaf(r, STEP, status);
return (v);
}
}
return (v);
}
/*
* NAME
* init_ray -
*
* SYNOPSIS
* VOXEL *init_ray(r, g)
* RAY *r;
* GRID *g; // World grid.
*
* DESCRIPTION
* Add rayinfo to a ray & intersect with world grid and find the initial
* nonempty leaf voxel.
*
* RETURNS
* If the ray hits a nonempty leaf voxel a pointer to that voxel is
* returned, otherwise NULL is returned.
*/
VOXEL *init_ray(RAY *r, GRID *g)
{
INT status;
INT indx, grid_id;
INT i_in, i_out, i, il, ih;
REAL t_in, t_out, tl, th;
REAL t[6];
VOXEL *v;
GRID *gr;
RAYINFO *ri;
reset_rayinfo(r);
if (r->D[0] == 0.0)
{
if (r->P[0] >= g->min[0] && r->P[0] <= g->min[0] + g->cellsize[0])
t[0] = -HUGE_REAL;
else
t[0] = HUGE_REAL;
}
else
t[0] = (g->min[0] - r->P[0]) / r->D[0];
if (r->D[1] == 0.0)
{
if (r->P[1] >= g->min[1] && r->P[1] <= g->min[1] + g->cellsize[1])
t[1] = -HUGE_REAL;
else
t[1] = HUGE_REAL;
}
else
t[1] = (g->min[1] - r->P[1]) / r->D[1];
if (r->D[2] == 0.0)
{
if (r->P[2] >= g->min[2] && r->P[2] <= g->min[2] + g->cellsize[2])
t[2] = -HUGE_REAL;
else
t[2] = HUGE_REAL;
}
else
t[2] = (g->min[2] - r->P[2]) / r->D[2];
if (r->D[0] == 0.0)
{
if (r->P[0] >= g->min[0] && r->P[0] <= g->min[0] + g->cellsize[0])
t[3] = HUGE_REAL;
else
t[3] = HUGE_REAL;
}
else
t[3] = (g->min[0] + g->cellsize[0] - r->P[0]) / r->D[0];
if (r->D[1] == 0.0)
{
if (r->P[1] >= g->min[1] && r->P[1] <= g->min[1] + g->cellsize[1])
t[4] = HUGE_REAL;
else
t[4] = HUGE_REAL;
}
else
t[4] = (g->min[1] + g->cellsize[1] - r->P[1]) / r->D[1];
if (r->D[2] == 0.0)
{
if (r->P[2] >= g->min[2] && r->P[2] <= g->min[2] + g->cellsize[2])
t[5] = HUGE_REAL;
else
t[5] = HUGE_REAL;
}
else
t[5] = (g->min[2] + g->cellsize[2] - r->P[2]) / r->D[2];
t_in = -HUGE_REAL;
i_in = -1;
t_out = HUGE_REAL;
i_out = -1;
for (i = 0 ; i < 3; i++)
{
if (t[i] < t[i + 3])
{
tl = t[i];
il = i;
th = t[i + 3];
ih = i+3;
}
else
{
tl = t[i + 3];
il = i + 3;
th = t[i];
ih = i;
}
if (t_in < tl) /* max min */
{
t_in = tl;
i_in = il;
}
if (t_out > th) /* min max */
{
t_out = th;
i_out = ih;
}
}
if (t_in >= t_out || t_out < 0.0)
{
return (NULL); /* Ray missed world cube. */
}
ri = ma_rayinfo(r);
r->ri = ri;
ri->grid = g;
/* Store exit t[]s. */
if (t[0] >= t[3])
ri->d[0] = t[0];
else
ri->d[0] = t[3];
if (t[1] >= t[4])
ri->d[1] = t[1];
else
ri->d[1] = t[4];
if (t[2] >= t[5])
ri->d[2] = t[2];
else
ri->d[2] = t[5];
if (i_in > 2)
i_in -= 3;
if (i_out > 2)
i_out -= 3;
ri->entry_plane = i_in;
ri->t_in = t_in;
ri->t_out = t_out;
ri->exit_plane = i_out;
ri->delta[0] = r->D[0] == 0.0 ? HUGE_REAL : g->cellsize[0] / ABS(r->D[0]);
ri->delta[1] = r->D[1] == 0.0 ? HUGE_REAL : g->cellsize[1] / ABS(r->D[1]);
ri->delta[2] = r->D[2] == 0.0 ? HUGE_REAL : g->cellsize[2] / ABS(r->D[2]);
ri->index3D[0] = 0;
ri->index3D[1] = 0;
ri->index3D[2] = 0;
r->indx_inc3D[0] = r->D[0] >= 0.0 ? 1 : -1;
r->indx_inc3D[1] = r->D[1] >= 0.0 ? 1 : -1;
r->indx_inc3D[2] = r->D[2] >= 0.0 ? 1 : -1;
ri->index1D = 0;
ri->indx_inc1D[0] = r->D[0] >= 0.0 ? 1 : -1;
ri->indx_inc1D[1] = r->D[1] >= 0.0 ? 1 : -1;
ri->indx_inc1D[2] = r->D[2] >= 0.0 ? 1 : -1;
ri->next = NULL;
/*
* At this point the ray is in the top grid in the hierarchy it
* must now descend to a leaf cell.
*/
if ((v = next_nonempty_leaf(r, NO_STEP, &status)) != NULL)
{
ri = r->ri;
indx = ri->index1D;
gr = ri->grid;
grid_id = gr->id;
}
else
{
return (NULL);
}
return (v);
}