text: /******************************************************************************
   * Copyright (c) 1998 Lawrence Livermore National Security, LLC and other
   * HYPRE Project Developers. See the top-level COPYRIGHT file for details.
   *
   * SPDX-License-Identifier: (Apache-2.0 OR MIT)
   ******************************************************************************/
  
  /******************************************************************************
   * OpenMP Problems
   *
   * Not sure about performace yet, so leaving the '#if 1' blocks below.
   *
   ******************************************************************************/
  
  /******************************************************************************
   *  FAC composite level interpolation.
   *  Identity interpolation of values away from underlying refinement patches;
   *  linear inside patch.
   ******************************************************************************/
  
  #include "_hypre_sstruct_ls.h"
  #include "fac.h"
  
  /*--------------------------------------------------------------------------
   * hypre_FacSemiInterpData data structure
   *--------------------------------------------------------------------------*/
  typedef struct
  {
     HYPRE_Int             nvars;
     HYPRE_Int             ndim;
     hypre_Index           stride;
  
     hypre_SStructPVector *recv_cvectors;
     HYPRE_Int           **recv_boxnum_map;   /* mapping between the boxes of the
                                                 recv_grid and the given grid */
     hypre_BoxArrayArray **identity_arrayboxes;
     hypre_BoxArrayArray **ownboxes;
     HYPRE_Int          ***own_cboxnums;
  
     hypre_CommPkg       **interlevel_comm;
     hypre_CommPkg       **gnodes_comm_pkg;
  
     HYPRE_Real          **weights;
  
  } hypre_FacSemiInterpData2;
  
  /*--------------------------------------------------------------------------
   * hypre_FacSemiInterpCreate
   *--------------------------------------------------------------------------*/
  HYPRE_Int
  hypre_FacSemiInterpCreate2( void **fac_interp_vdata_ptr )
  {
     HYPRE_Int                 ierr = 0;
     hypre_FacSemiInterpData2  *fac_interp_data;
  
     fac_interp_data = hypre_CTAlloc(hypre_FacSemiInterpData2,  1, HYPRE_MEMORY_HOST);
     *fac_interp_vdata_ptr = (void *) fac_interp_data;
  
     return ierr;
  }
  
  /*--------------------------------------------------------------------------
   * hypre_FacSemiInterpDestroy
   *--------------------------------------------------------------------------*/
  HYPRE_Int
  hypre_FacSemiInterpDestroy2( void *fac_interp_vdata)
  {
     HYPRE_Int                 ierr = 0;
  
     hypre_FacSemiInterpData2 *fac_interp_data = (hypre_FacSemiInterpData2 *)fac_interp_vdata;
     HYPRE_Int                 i, j, size;
  
     if (fac_interp_data)
     {
        hypre_SStructPVectorDestroy(fac_interp_data-> recv_cvectors);
  
        for (i = 0; i < (fac_interp_data-> nvars); i++)
        {
           hypre_TFree(fac_interp_data -> recv_boxnum_map[i], HYPRE_MEMORY_HOST);
           hypre_BoxArrayArrayDestroy(fac_interp_data -> identity_arrayboxes[i]);
  
           size = hypre_BoxArrayArraySize(fac_interp_data -> ownboxes[i]);
           hypre_BoxArrayArrayDestroy(fac_interp_data -> ownboxes[i]);
           for (j = 0; j < size; j++)
           {
              hypre_TFree(fac_interp_data -> own_cboxnums[i][j], HYPRE_MEMORY_HOST);
           }
           hypre_TFree(fac_interp_data -> own_cboxnums[i], HYPRE_MEMORY_HOST);
  
           hypre_CommPkgDestroy(fac_interp_data -> gnodes_comm_pkg[i]);
           hypre_CommPkgDestroy(fac_interp_data -> interlevel_comm[i]);
  
        }
        hypre_TFree(fac_interp_data -> recv_boxnum_map, HYPRE_MEMORY_HOST);
        hypre_TFree(fac_interp_data -> identity_arrayboxes, HYPRE_MEMORY_HOST);
        hypre_TFree(fac_interp_data -> ownboxes, HYPRE_MEMORY_HOST);
        hypre_TFree(fac_interp_data -> own_cboxnums, HYPRE_MEMORY_HOST);
  
        hypre_TFree(fac_interp_data -> gnodes_comm_pkg, HYPRE_MEMORY_HOST);
        hypre_TFree(fac_interp_data -> interlevel_comm, HYPRE_MEMORY_HOST);
  
        for (i = 0; i < (fac_interp_data -> ndim); i++)
        {
           hypre_TFree(fac_interp_data -> weights[i], HYPRE_MEMORY_HOST);
        }
        hypre_TFree(fac_interp_data -> weights, HYPRE_MEMORY_HOST);
  
        hypre_TFree(fac_interp_data, HYPRE_MEMORY_HOST);
     }
     return ierr;
  }
  
  /*--------------------------------------------------------------------------
   * hypre_FacSemiInterpSetup2:
   * Note that an intermediate coarse SStruct_PVector is used in interpolating
   * the interlevel communicated data (coarse data). The data in these
   * intermediate vectors will be interpolated to the fine grid.
   *--------------------------------------------------------------------------*/
  HYPRE_Int
  hypre_FacSemiInterpSetup2( void                 *fac_interp_vdata,
                             hypre_SStructVector  *e,
                             hypre_SStructPVector *ec,
                             hypre_Index           rfactors)
  {
     HYPRE_Int                 ierr = 0;
  
     hypre_FacSemiInterpData2 *fac_interp_data = (hypre_FacSemiInterpData2 *)fac_interp_vdata;
     HYPRE_Int                 part_fine = 1;
     HYPRE_Int                 part_crse = 0;
  
     hypre_CommPkg           **gnodes_comm_pkg;
     hypre_CommPkg           **interlevel_comm;
     hypre_CommInfo           *comm_info;
  
     hypre_SStructPVector     *recv_cvectors;
     hypre_SStructPGrid       *recv_cgrid;
     HYPRE_Int               **recv_boxnum_map;
     hypre_SStructGrid        *temp_grid;
  
     hypre_SStructPGrid       *pgrid;
  
     hypre_SStructPVector     *ef = hypre_SStructVectorPVector(e, part_fine);
     hypre_StructVector       *e_var, *s_rc, *s_cvector;
  
     hypre_BoxArrayArray     **identity_arrayboxes;
     hypre_BoxArrayArray     **ownboxes;
  
     hypre_BoxArrayArray     **send_boxes, *send_rboxes;
     HYPRE_Int              ***send_processes;
     HYPRE_Int              ***send_remote_boxnums;
  
     hypre_BoxArrayArray     **recv_boxes, *recv_rboxes;
     HYPRE_Int              ***recv_processes;
     HYPRE_Int              ***recv_remote_boxnums;
  
     hypre_BoxArray           *boxarray;
     hypre_BoxArray           *tmp_boxarray, *intersect_boxes;
     hypre_Box                 box, scaled_box;
     HYPRE_Int              ***own_cboxnums;
  
     hypre_BoxManager         *boxman1;
     hypre_BoxManEntry       **boxman_entries;
     HYPRE_Int                 nboxman_entries;
  
     HYPRE_Int                 nvars = hypre_SStructPVectorNVars(ef);
     HYPRE_Int                 vars;
  
     hypre_Index               zero_index, index;
     hypre_Index               ilower, iupper;
     HYPRE_Int                *num_ghost;
  
     HYPRE_Int                 ndim, i, j, k, fi, ci;
     HYPRE_Int                 cnt1, cnt2;
     HYPRE_Int                 proc, myproc, tot_procs;
     HYPRE_Int                 num_values;
  
     HYPRE_Real              **weights;
     HYPRE_Real                refine_factors_2recp[3];
     hypre_Index               refine_factors_half;
  
     hypre_MPI_Comm_rank(hypre_MPI_COMM_WORLD, &myproc);
     hypre_MPI_Comm_size(hypre_MPI_COMM_WORLD, &tot_procs);
  
     ndim = hypre_SStructPGridNDim(hypre_SStructPVectorPGrid(ef));
     hypre_SetIndex3(zero_index, 0, 0, 0);
  
     hypre_BoxInit(&box, ndim);
     hypre_BoxInit(&scaled_box, ndim);
  
     /*------------------------------------------------------------------------
      * Intralevel communication structures-
      * A communication pkg must be created for each StructVector. Stencils
      * are needed in creating the packages- we are assuming that the same
      * stencil pattern for each StructVector, i.e., linear interpolation for
      * each variable.
      *------------------------------------------------------------------------*/
     gnodes_comm_pkg = hypre_CTAlloc(hypre_CommPkg *,  nvars, HYPRE_MEMORY_HOST);
     for (vars = 0; vars < nvars; vars++)
     {
        e_var = hypre_SStructPVectorSVector(ec, vars);
        num_ghost = hypre_StructVectorNumGhost(e_var);
  
        hypre_CreateCommInfoFromNumGhost(hypre_StructVectorGrid(e_var),
                                         num_ghost, &comm_info);
        hypre_CommPkgCreate(comm_info,
                            hypre_StructVectorDataSpace(e_var),
                            hypre_StructVectorDataSpace(e_var),
                            1, NULL, 0, hypre_StructVectorComm(e_var),
                            &gnodes_comm_pkg[vars]);
        hypre_CommInfoDestroy(comm_info);
     }
  
     (fac_interp_data -> ndim)           = ndim;
     (fac_interp_data -> nvars)          = nvars;
     (fac_interp_data -> gnodes_comm_pkg) = gnodes_comm_pkg;
     hypre_CopyIndex(rfactors, (fac_interp_data -> stride));
  
     /*------------------------------------------------------------------------
      * Interlevel communication structures.
      *
      * Algorithm for identity_boxes: For each cbox on this processor, refine
      * it and intersect it with the fmap.
      *    (cbox - all coarsened fmap_intersect boxes)= identity chunks
      * for cbox.
      *
      * Algorithm for own_boxes (fullwgted boxes on this processor): For each
      * fbox, coarsen it and boxmap intersect it with cmap.
      *   (cmap_intersect boxes on myproc)= ownboxes
      * for this fbox.
      *
      * Algorithm for recv_box: For each fbox, coarsen it and boxmap intersect
      * it with cmap.
      *   (cmap_intersect boxes off_proc)= unstretched recv_boxes.
      * These boxes are stretched by one in each direction so that the ghostlayer
      * is also communicated. However, the recv_grid will consists of the
      * unstretched boxes so that overlapping does not occur.
      *--------------------------------------------------------------------------*/
     identity_arrayboxes = hypre_CTAlloc(hypre_BoxArrayArray *,  nvars, HYPRE_MEMORY_HOST);
  
     pgrid = hypre_SStructPVectorPGrid(ec);
     hypre_ClearIndex(index);
     for (i = 0; i < ndim; i++)
     {
        index[i] = rfactors[i] - 1;
     }
  
     tmp_boxarray = hypre_BoxArrayCreate(0, ndim);
     for (vars = 0; vars < nvars; vars++)
     {
        boxman1 = hypre_SStructGridBoxManager(hypre_SStructVectorGrid(e),
                                              part_fine, vars);
        boxarray = hypre_StructGridBoxes(hypre_SStructPGridSGrid(pgrid, vars));
        identity_arrayboxes[vars] = hypre_BoxArrayArrayCreate(hypre_BoxArraySize(boxarray), ndim);
  
        hypre_ForBoxI(ci, boxarray)
        {
           box = *hypre_BoxArrayBox(boxarray, ci);
           hypre_AppendBox(&box,
                           hypre_BoxArrayArrayBoxArray(identity_arrayboxes[vars], ci));
  
           hypre_StructMapCoarseToFine(hypre_BoxIMin(&box), zero_index,
                                       rfactors, hypre_BoxIMin(&scaled_box));
           hypre_StructMapCoarseToFine(hypre_BoxIMax(&box), index,
                                       rfactors, hypre_BoxIMax(&scaled_box));
  
           hypre_BoxManIntersect(boxman1, hypre_BoxIMin(&scaled_box),
                                 hypre_BoxIMax(&scaled_box), &boxman_entries,
                                 &nboxman_entries);
  
           intersect_boxes = hypre_BoxArrayCreate(0, ndim);
           for (i = 0; i < nboxman_entries; i++)
           {
              hypre_BoxManEntryGetExtents(boxman_entries[i], ilower, iupper);
              hypre_BoxSetExtents(&box, ilower, iupper);
              hypre_IntersectBoxes(&box, &scaled_box, &box);
  
              /* contract this refined box so that only the coarse nodes on this
                 processor will be subtracted. */
              for (j = 0; j < ndim; j++)
              {
                 k = hypre_BoxIMin(&box)[j] % rfactors[j];
                 if (k)
                 {
                    hypre_BoxIMin(&box)[j] += rfactors[j] - k;
                 }
              }
  
              hypre_StructMapFineToCoarse(hypre_BoxIMin(&box), zero_index,
                                          rfactors, hypre_BoxIMin(&box));
              hypre_StructMapFineToCoarse(hypre_BoxIMax(&box), zero_index,
                                          rfactors, hypre_BoxIMax(&box));
              hypre_AppendBox(&box, intersect_boxes);
           }
  
           hypre_SubtractBoxArrays(hypre_BoxArrayArrayBoxArray(identity_arrayboxes[vars], ci),
                                   intersect_boxes, tmp_boxarray);
           hypre_MinUnionBoxes(hypre_BoxArrayArrayBoxArray(identity_arrayboxes[vars], ci));
  
           hypre_TFree(boxman_entries, HYPRE_MEMORY_HOST);
           hypre_BoxArrayDestroy(intersect_boxes);
        }
     }
     hypre_BoxArrayDestroy(tmp_boxarray);
     fac_interp_data -> identity_arrayboxes = identity_arrayboxes;
  
     /*--------------------------------------------------------------------------
      * fboxes are coarsened. For each coarsened fbox, we need a boxarray of
      * recvboxes or ownboxes.
      *--------------------------------------------------------------------------*/
     ownboxes = hypre_CTAlloc(hypre_BoxArrayArray *,  nvars, HYPRE_MEMORY_HOST);
     own_cboxnums = hypre_CTAlloc(HYPRE_Int **,  nvars, HYPRE_MEMORY_HOST);
  
     recv_boxes = hypre_CTAlloc(hypre_BoxArrayArray *,  nvars, HYPRE_MEMORY_HOST);
     recv_processes = hypre_CTAlloc(HYPRE_Int **,  nvars, HYPRE_MEMORY_HOST);
  
     /* dummy pointer for CommInfoCreate */
     recv_remote_boxnums = hypre_CTAlloc(HYPRE_Int **,  nvars, HYPRE_MEMORY_HOST);
     hypre_ClearIndex(index);
     for (i = 0; i < ndim; i++)
     {
        index[i] = 1;
     }
  
     for (vars = 0; vars < nvars; vars++)
     {
        boxman1 = hypre_SStructGridBoxManager(hypre_SStructVectorGrid(e),
                                              part_crse, vars);
        pgrid = hypre_SStructPVectorPGrid(ef);
        boxarray = hypre_StructGridBoxes(hypre_SStructPGridSGrid(pgrid, vars));
  
        ownboxes[vars] = hypre_BoxArrayArrayCreate(hypre_BoxArraySize(boxarray), ndim);
        own_cboxnums[vars] = hypre_CTAlloc(HYPRE_Int *,  hypre_BoxArraySize(boxarray), HYPRE_MEMORY_HOST);
        recv_boxes[vars]    = hypre_BoxArrayArrayCreate(hypre_BoxArraySize(boxarray), ndim);
        recv_processes[vars] = hypre_CTAlloc(HYPRE_Int *,  hypre_BoxArraySize(boxarray), HYPRE_MEMORY_HOST);
        recv_remote_boxnums[vars] = hypre_CTAlloc(HYPRE_Int *,  hypre_BoxArraySize(boxarray),
                                                  HYPRE_MEMORY_HOST);
  
        hypre_ForBoxI(fi, boxarray)
        {
           box = *hypre_BoxArrayBox(boxarray, fi);
  
           /*--------------------------------------------------------------------
            * Adjust this box so that only the coarse nodes inside the fine box
            * are extracted.
            *--------------------------------------------------------------------*/
           for (j = 0; j < ndim; j++)
           {
              k = hypre_BoxIMin(&box)[j] % rfactors[j];
              if (k)
              {
                 hypre_BoxIMin(&box)[j] += rfactors[j] - k;
              }
           }
  
           hypre_StructMapFineToCoarse(hypre_BoxIMin(&box), zero_index,
                                       rfactors, hypre_BoxIMin(&scaled_box));
           hypre_StructMapFineToCoarse(hypre_BoxIMax(&box), zero_index,
                                       rfactors, hypre_BoxIMax(&scaled_box));
  
           hypre_BoxManIntersect(boxman1, hypre_BoxIMin(&scaled_box),
                                 hypre_BoxIMax(&scaled_box), &boxman_entries, &nboxman_entries);
  
           cnt1 = 0; cnt2 = 0;
           for (i = 0; i < nboxman_entries; i++)
           {
              hypre_SStructBoxManEntryGetProcess(boxman_entries[i], &proc);
              if (proc == myproc)
              {
                 cnt1++;
              }
              else
              {
                 cnt2++;
              }
           }
  
           own_cboxnums[vars][fi]  = hypre_CTAlloc(HYPRE_Int,  cnt1, HYPRE_MEMORY_HOST);
           recv_processes[vars][fi] = hypre_CTAlloc(HYPRE_Int,  cnt2, HYPRE_MEMORY_HOST);
           recv_remote_boxnums[vars][fi] = hypre_CTAlloc(HYPRE_Int,  cnt2, HYPRE_MEMORY_HOST);
  
           cnt1 = 0; cnt2 = 0;
           for (i = 0; i < nboxman_entries; i++)
           {
              hypre_BoxManEntryGetExtents(boxman_entries[i], ilower, iupper);
              hypre_BoxSetExtents(&box, ilower, iupper);
              hypre_IntersectBoxes(&box, &scaled_box, &box);
  
              hypre_SStructBoxManEntryGetProcess(boxman_entries[i], &proc);
              if (proc == myproc)
              {
                 hypre_AppendBox(&box,
                                 hypre_BoxArrayArrayBoxArray(ownboxes[vars], fi));
                 hypre_SStructBoxManEntryGetBoxnum(boxman_entries[i],
                                                   &own_cboxnums[vars][fi][cnt1]);
                 cnt1++;
              }
              else
              {
                 /* extend the box so all the required data for interpolation is recvd. */
                 hypre_SubtractIndexes(hypre_BoxIMin(&box), index, 3,
                                       hypre_BoxIMin(&box));
                 hypre_AddIndexes(hypre_BoxIMax(&box), index, 3, hypre_BoxIMax(&box));
  
                 hypre_AppendBox(&box,
                                 hypre_BoxArrayArrayBoxArray(recv_boxes[vars], fi));
                 recv_processes[vars][fi][cnt2] = proc;
                 cnt2++;
              }
           }
           hypre_TFree(boxman_entries, HYPRE_MEMORY_HOST);
        }  /* hypre_ForBoxI(fi, boxarray) */
     }     /* for (vars= 0; vars< nvars; vars++) */
  
     (fac_interp_data -> ownboxes) = ownboxes;
     (fac_interp_data -> own_cboxnums) = own_cboxnums;
  
     /*--------------------------------------------------------------------------
      * With the recv'ed boxes form a SStructPGrid and a SStructGrid. The
      * SStructGrid is needed to generate a box_manager (so that a local box ordering
      * for the remote_boxnums are obtained). Record the recv_boxnum/fbox_num
      * mapping. That is, we interpolate a recv_box l to a fine box m, generally
      * l != m since the recv_grid and fgrid do not agree.
      *--------------------------------------------------------------------------*/
     HYPRE_SStructGridCreate(hypre_SStructPVectorComm(ec),
                             ndim, 1, &temp_grid);
     hypre_SStructPGridCreate(hypre_SStructPVectorComm(ec), ndim, &recv_cgrid);
     recv_boxnum_map = hypre_CTAlloc(HYPRE_Int *,  nvars, HYPRE_MEMORY_HOST);
  
     cnt2 = 0;
     hypre_ClearIndex(index);
     for (i = 0; i < ndim; i++)
     {
        index[i] = 1;
     }
     for (vars = 0; vars < nvars; vars++)
     {
        cnt1 = 0;
        hypre_ForBoxArrayI(i, recv_boxes[vars])
        {
           boxarray = hypre_BoxArrayArrayBoxArray(recv_boxes[vars], i);
           cnt1 += hypre_BoxArraySize(boxarray);
        }
        recv_boxnum_map[vars] = hypre_CTAlloc(HYPRE_Int,  cnt1, HYPRE_MEMORY_HOST);
  
        cnt1 = 0;
        hypre_ForBoxArrayI(i, recv_boxes[vars])
        {
           boxarray = hypre_BoxArrayArrayBoxArray(recv_boxes[vars], i);
           hypre_ForBoxI(j, boxarray)
           {
              box = *hypre_BoxArrayBox(boxarray, j);
  
              /* contract the box its actual size. */
              hypre_AddIndexes(hypre_BoxIMin(&box), index, 3, hypre_BoxIMin(&box));
              hypre_SubtractIndexes(hypre_BoxIMax(&box), index, 3,
                                    hypre_BoxIMax(&box));
  
              hypre_SStructPGridSetExtents(recv_cgrid,
                                           hypre_BoxIMin(&box),
                                           hypre_BoxIMax(&box));
  
              HYPRE_SStructGridSetExtents(temp_grid, 0,
                                          hypre_BoxIMin(&box),
                                          hypre_BoxIMax(&box));
  
              recv_boxnum_map[vars][cnt1] = i; /* record the fbox num. i */
              cnt1++;
              cnt2++;
           }
        }
     }
  
     /*------------------------------------------------------------------------
      * When there are no boxes to communicate, set the temp_grid to have a
      * box of size zero. This is needed so that this SStructGrid can be
      * assembled. This is done only when this only one processor.
      *------------------------------------------------------------------------*/
     if (cnt2 == 0)
     {
        /* min_index > max_index so that the box has volume zero. */
        hypre_BoxSetExtents(&box, index, zero_index);
        hypre_SStructPGridSetExtents(recv_cgrid,
                                     hypre_BoxIMin(&box),
                                     hypre_BoxIMax(&box));
  
        HYPRE_SStructGridSetExtents(temp_grid, 0,
                                    hypre_BoxIMin(&box),
                                    hypre_BoxIMax(&box));
     }
  
     HYPRE_SStructGridSetVariables(temp_grid, 0,
                                   hypre_SStructPGridNVars(pgrid),
                                   hypre_SStructPGridVarTypes(pgrid));
     HYPRE_SStructGridAssemble(temp_grid);
     hypre_SStructPGridSetVariables(recv_cgrid, nvars,
                                    hypre_SStructPGridVarTypes(pgrid) );
     hypre_SStructPGridAssemble(recv_cgrid);
  
     hypre_SStructPVectorCreate(hypre_SStructPGridComm(recv_cgrid), recv_cgrid,
                                &recv_cvectors);
     hypre_SStructPVectorInitialize(recv_cvectors);
     hypre_SStructPVectorAssemble(recv_cvectors);
  
     fac_interp_data -> recv_cvectors  = recv_cvectors;
     fac_interp_data -> recv_boxnum_map = recv_boxnum_map;
  
     /* pgrid recv_cgrid no longer needed. */
     hypre_SStructPGridDestroy(recv_cgrid);
  
     /*------------------------------------------------------------------------
      * Send_boxes.
      * Algorithm for send_boxes: For each cbox on this processor, box_map
      * intersect it with temp_grid's map.
      *   (intersection boxes off-proc)= send_boxes for this cbox.
      * Note that the send_boxes will be stretched to include the ghostlayers.
      * This guarantees that all the data required for linear interpolation
      * will be on the processor. Also, note that the remote_boxnums are
      * with respect to the recv_cgrid box numbering.
      *--------------------------------------------------------------------------*/
     send_boxes = hypre_CTAlloc(hypre_BoxArrayArray *,  nvars, HYPRE_MEMORY_HOST);
     send_processes = hypre_CTAlloc(HYPRE_Int **,  nvars, HYPRE_MEMORY_HOST);
     send_remote_boxnums = hypre_CTAlloc(HYPRE_Int **,  nvars, HYPRE_MEMORY_HOST);
  
     hypre_ClearIndex(index);
     for (i = 0; i < ndim; i++)
     {
        index[i] = 1;
     }
     for (vars = 0; vars < nvars; vars++)
     {
        /*-------------------------------------------------------------------
         * send boxes: intersect with temp_grid that has all the recv boxes-
         * These local box_nums may not be the same as the local box_nums of
         * the coarse grid.
         *-------------------------------------------------------------------*/
        boxman1 = hypre_SStructGridBoxManager(temp_grid, 0, vars);
        pgrid = hypre_SStructPVectorPGrid(ec);
        boxarray = hypre_StructGridBoxes(hypre_SStructPGridSGrid(pgrid, vars));
  
        send_boxes[vars] = hypre_BoxArrayArrayCreate(hypre_BoxArraySize(boxarray), ndim);
        send_processes[vars] = hypre_CTAlloc(HYPRE_Int *,  hypre_BoxArraySize(boxarray), HYPRE_MEMORY_HOST);
        send_remote_boxnums[vars] = hypre_CTAlloc(HYPRE_Int *,  hypre_BoxArraySize(boxarray),
                                                  HYPRE_MEMORY_HOST);
  
        hypre_ForBoxI(ci, boxarray)
        {
           box = *hypre_BoxArrayBox(boxarray, ci);
           hypre_BoxSetExtents(&scaled_box, hypre_BoxIMin(&box), hypre_BoxIMax(&box));
  
           hypre_BoxManIntersect(boxman1, hypre_BoxIMin(&scaled_box),
                                 hypre_BoxIMax(&scaled_box), &boxman_entries, &nboxman_entries);
  
           cnt1 = 0;
           for (i = 0; i < nboxman_entries; i++)
           {
              hypre_SStructBoxManEntryGetProcess(boxman_entries[i], &proc);
              if (proc != myproc)
              {
                 cnt1++;
              }
           }
           send_processes[vars][ci]     = hypre_CTAlloc(HYPRE_Int,  cnt1, HYPRE_MEMORY_HOST);
           send_remote_boxnums[vars][ci] = hypre_CTAlloc(HYPRE_Int,  cnt1, HYPRE_MEMORY_HOST);
  
           cnt1 = 0;
           for (i = 0; i < nboxman_entries; i++)
           {
              hypre_BoxManEntryGetExtents(boxman_entries[i], ilower, iupper);
              hypre_BoxSetExtents(&box, ilower, iupper);
              hypre_IntersectBoxes(&box, &scaled_box, &box);
  
              hypre_SStructBoxManEntryGetProcess(boxman_entries[i], &proc);
              if (proc != myproc)
              {
                 /* strech the box */
                 hypre_SubtractIndexes(hypre_BoxIMin(&box), index, 3,
                                       hypre_BoxIMin(&box));
                 hypre_AddIndexes(hypre_BoxIMax(&box), index, 3, hypre_BoxIMax(&box));
  
                 hypre_AppendBox(&box,
                                 hypre_BoxArrayArrayBoxArray(send_boxes[vars], ci));
  
                 send_processes[vars][ci][cnt1] = proc;
                 hypre_SStructBoxManEntryGetBoxnum(
                    boxman_entries[i], &send_remote_boxnums[vars][ci][cnt1]);
                 cnt1++;
              }
           }
  
           hypre_TFree(boxman_entries, HYPRE_MEMORY_HOST);
        }  /* hypre_ForBoxI(ci, boxarray) */
     }    /* for (vars= 0; vars< nvars; vars++) */
  
     /*--------------------------------------------------------------------------
      * Can disgard temp_grid now- only needed it's box_man info,
      *--------------------------------------------------------------------------*/
     HYPRE_SStructGridDestroy(temp_grid);
  
     /*--------------------------------------------------------------------------
      * Can create the interlevel_comm.
      *--------------------------------------------------------------------------*/
     interlevel_comm = hypre_CTAlloc(hypre_CommPkg *,  nvars, HYPRE_MEMORY_HOST);
  
     num_values = 1;
     for (vars = 0; vars < nvars; vars++)
     {
        s_rc = hypre_SStructPVectorSVector(ec, vars);
  
        s_cvector = hypre_SStructPVectorSVector(recv_cvectors, vars);
        send_rboxes = hypre_BoxArrayArrayDuplicate(send_boxes[vars]);
        recv_rboxes = hypre_BoxArrayArrayDuplicate(recv_boxes[vars]);
  
        hypre_CommInfoCreate(send_boxes[vars], recv_boxes[vars],
                             send_processes[vars], recv_processes[vars],
                             send_remote_boxnums[vars], recv_remote_boxnums[vars],
                             send_rboxes, recv_rboxes, 1, &comm_info);
  
        hypre_CommPkgCreate(comm_info,
                            hypre_StructVectorDataSpace(s_rc),
                            hypre_StructVectorDataSpace(s_cvector),
                            num_values, NULL, 0,
                            hypre_StructVectorComm(s_rc),
                            &interlevel_comm[vars]);
        hypre_CommInfoDestroy(comm_info);
     }
     hypre_TFree(send_boxes, HYPRE_MEMORY_HOST);
     hypre_TFree(recv_boxes, HYPRE_MEMORY_HOST);
     hypre_TFree(send_processes, HYPRE_MEMORY_HOST);
     hypre_TFree(recv_processes, HYPRE_MEMORY_HOST);
     hypre_TFree(send_remote_boxnums, HYPRE_MEMORY_HOST);
     hypre_TFree(recv_remote_boxnums, HYPRE_MEMORY_HOST);
  
     (fac_interp_data -> interlevel_comm) = interlevel_comm;
  
     /* interpolation weights */
     weights = hypre_TAlloc(HYPRE_Real *,  ndim, HYPRE_MEMORY_HOST);
     for (i = 0; i < ndim; i++)
     {
        weights[i] = hypre_CTAlloc(HYPRE_Real,  rfactors[i] + 1, HYPRE_MEMORY_HOST);
     }
  
     hypre_ClearIndex(refine_factors_half);
     /*   hypre_ClearIndex(refine_factors_2recp);*/
     for (i = 0; i < ndim; i++)
     {
        refine_factors_half[i] = rfactors[i] / 2;
        refine_factors_2recp[i] = 1.0 / (2.0 * rfactors[i]);
     }
  
     for (i = 0; i < ndim; i++)
     {
        for (j = 0; j <= refine_factors_half[i]; j++)
        {
           weights[i][j] = refine_factors_2recp[i] * (rfactors[i] + 2 * j - 1.0);
        }
  
        for (j = (refine_factors_half[i] + 1); j <= rfactors[i]; j++)
        {
           weights[i][j] = refine_factors_2recp[i] * (2 * j - rfactors[i] - 1.0);
        }
     }
     (fac_interp_data -> weights) = weights;
  
  
     return ierr;
  }
  
  HYPRE_Int
  hypre_FAC_IdentityInterp2(void                 *  fac_interp_vdata,
                            hypre_SStructPVector *  xc,
                            hypre_SStructVector  *  e)
  {
     hypre_FacSemiInterpData2 *interp_data = (hypre_FacSemiInterpData2 *)fac_interp_vdata;
     hypre_BoxArrayArray     **identity_boxes = interp_data-> identity_arrayboxes;
  
     HYPRE_Int               part_crse = 0;
  
     HYPRE_Int               ierr     = 0;
  
     /*-----------------------------------------------------------------------
      * Compute e at coarse points (injection).
      * The pgrid of xc is the same as the part_csre pgrid of e.
      *-----------------------------------------------------------------------*/
     hypre_SStructPartialPCopy(xc,
                               hypre_SStructVectorPVector(e, part_crse),
                               identity_boxes);
  
     return ierr;
  }
  
  /*-------------------------------------------------------------------------
   * Linear interpolation. Interpolate the vector first by interpolating the
   * values in ownboxes and then values in recv_cvectors (the interlevel
   * communicated data).
   *-------------------------------------------------------------------------*/
  HYPRE_Int
  hypre_FAC_WeightedInterp2(void                  *fac_interp_vdata,
                            hypre_SStructPVector  *xc,
                            hypre_SStructVector   *e_parts)
  {
     HYPRE_Int ierr = 0;
  
     hypre_FacSemiInterpData2 *interp_data = (hypre_FacSemiInterpData2 *)fac_interp_vdata;
  
     hypre_CommPkg          **comm_pkg       = interp_data-> gnodes_comm_pkg;
     hypre_CommPkg          **interlevel_comm = interp_data-> interlevel_comm;
     hypre_SStructPVector    *recv_cvectors  = interp_data-> recv_cvectors;
     HYPRE_Int              **recv_boxnum_map = interp_data-> recv_boxnum_map;
     hypre_BoxArrayArray    **ownboxes       = interp_data-> ownboxes;
     HYPRE_Int             ***own_cboxnums   = interp_data-> own_cboxnums;
     HYPRE_Real             **weights        = interp_data-> weights;
     HYPRE_Int                ndim           = interp_data-> ndim;
  
     hypre_CommHandle       *comm_handle;
  
     hypre_IndexRef          stride;  /* refinement factors */
  
     hypre_SStructPVector   *e;
  
     hypre_StructGrid       *fgrid;
     hypre_BoxArray         *fgrid_boxes;
     hypre_Box              *fbox;
     hypre_BoxArrayArray    *own_cboxes;
     hypre_BoxArray         *own_abox;
     hypre_Box              *ownbox;
     HYPRE_Int             **var_boxnums;
     HYPRE_Int              *cboxnums;
  
     hypre_Box              *xc_dbox;
     hypre_Box              *e_dbox;
  
     hypre_Box               refined_box, intersect_box;
  
  
     hypre_StructVector     *xc_var;
     hypre_StructVector     *e_var;
     hypre_StructVector     *recv_var;
  
     HYPRE_Real           ***xcp;
     HYPRE_Real           ***ep;
  
     hypre_Index             loop_size, lindex;
     hypre_Index             start, start_offset;
     hypre_Index             startc;
     hypre_Index             stridec;
     hypre_Index             refine_factors;
     hypre_Index             refine_factors_half;
     hypre_Index             intersect_size;
     hypre_Index             zero_index, temp_index1, temp_index2;
  
     HYPRE_Int               fi, bi;
     HYPRE_Int               nvars, var;
  
     HYPRE_Int               i, j, k, offset_ip1, offset_jp1, offset_kp1;
     HYPRE_Int               ishift, jshift, kshift;
     HYPRE_Int               ptr_ishift, ptr_jshift, ptr_kshift;
     HYPRE_Int               imax, jmax, kmax;
     HYPRE_Int               jsize, ksize;
  
     HYPRE_Int               part_fine = 1;
  
     HYPRE_Real              xweight1, xweight2;
     HYPRE_Real              yweight1, yweight2;
     HYPRE_Real              zweight1, zweight2;
  
     /*-----------------------------------------------------------------------
      * Initialize some things
      *-----------------------------------------------------------------------*/
  
     hypre_BoxInit(&refined_box, ndim);
     hypre_BoxInit(&intersect_box, ndim);
  
     stride        = (interp_data -> stride);
  
     hypre_SetIndex3(zero_index, 0, 0, 0);
     hypre_CopyIndex(stride, refine_factors);
     for (i = ndim; i < 3; i++)
     {
        refine_factors[i] = 1;
     }
     hypre_SetIndex3(stridec, 1, 1, 1);
     for (i = 0; i < ndim; i++)
     {
        refine_factors_half[i] = refine_factors[i] / 2;
     }
  
     /*-----------------------------------------------------------------------
      * Compute e in the refined patch. But first communicate the coarse
      * data. Will need a ghostlayer communication on the given level and an
      * interlevel communication between levels.
      *-----------------------------------------------------------------------*/
     nvars =  hypre_SStructPVectorNVars(xc);
     for (var = 0; var < nvars; var++)
     {
        xc_var = hypre_SStructPVectorSVector(xc, var);
        hypre_InitializeCommunication(comm_pkg[var],
                                      hypre_StructVectorData(xc_var),
                                      hypre_StructVectorData(xc_var), 0, 0,
                                      &comm_handle);
        hypre_FinalizeCommunication(comm_handle);
  
        if (recv_cvectors != NULL)
        {
           recv_var = hypre_SStructPVectorSVector(recv_cvectors, var);
           hypre_InitializeCommunication(interlevel_comm[var],
                                         hypre_StructVectorData(xc_var),
                                         hypre_StructVectorData(recv_var), 0, 0,
                                         &comm_handle);
           hypre_FinalizeCommunication(comm_handle);
        }
     }
  
     e =  hypre_SStructVectorPVector(e_parts, part_fine);
  
     /*-----------------------------------------------------------------------
      * Allocate memory for the data pointers. Assuming linear interpolation.
      * We stride through the refinement patch by the refinement factors, and
      * so we must have pointers to the intermediate fine nodes=> ep will
      * be size refine_factors[2]*refine_factors[1]. This holds for all
      * dimensions since refine_factors[i]= 1 for i>= ndim.
      * Note that we need 3 coarse nodes per coordinate direction for the
      * interpolating. This is dimensional dependent:
      *   ndim= 3     kplane= 0,1,2 & jplane= 0,1,2    **ptr size [3][3]
      *   ndim= 2     kplane= 0     & jplane= 0,1,2    **ptr size [1][3]
      *   ndim= 1     kplane= 0     & jplane= 0        **ptr size [1][1]
      *-----------------------------------------------------------------------*/
     ksize = 3;
     jsize = 3;
     if (ndim < 3)
     {
        ksize = 1;
     }
     if (ndim < 2)
     {
        jsize = 1;
     }
  
     xcp  = hypre_TAlloc(HYPRE_Real **,  ksize, HYPRE_MEMORY_HOST);
     ep   = hypre_TAlloc(HYPRE_Real **,  refine_factors[2], HYPRE_MEMORY_HOST);
  
     for (k = 0; k < refine_factors[2]; k++)
     {
        ep[k] = hypre_TAlloc(HYPRE_Real *,  refine_factors[1], HYPRE_MEMORY_HOST);
     }
  
     for (k = 0; k < ksize; k++)
     {
        xcp[k] = hypre_TAlloc(HYPRE_Real *,  jsize, HYPRE_MEMORY_HOST);
     }
  
     for (var = 0; var < nvars; var++)
     {
        xc_var = hypre_SStructPVectorSVector(xc, var);
        e_var = hypre_SStructPVectorSVector(e, var);
  
        fgrid      = hypre_StructVectorGrid(e_var);
        fgrid_boxes = hypre_StructGridBoxes(fgrid);
  
        own_cboxes = ownboxes[var];
        var_boxnums = own_cboxnums[var];
  
        /*--------------------------------------------------------------------
         * Interpolate the own_box coarse grid values.
         *--------------------------------------------------------------------*/
        hypre_ForBoxI(fi, fgrid_boxes)
        {
           fbox = hypre_BoxArrayBox(fgrid_boxes, fi);
  
           e_dbox = hypre_BoxArrayBox(hypre_StructVectorDataSpace(e_var), fi);
           own_abox = hypre_BoxArrayArrayBoxArray(own_cboxes, fi);
           cboxnums = var_boxnums[fi];
  
           /*--------------------------------------------------------------------
            * Get the ptrs for the fine struct_vectors.
            *--------------------------------------------------------------------*/
           for (k = 0; k < refine_factors[2]; k++)
           {
              for (j = 0; j < refine_factors[1]; j++)
              {
                 hypre_SetIndex3(temp_index1, 0, j, k);
                 ep[k][j] = hypre_StructVectorBoxData(e_var, fi) +
                            hypre_BoxOffsetDistance(e_dbox, temp_index1);
              }
           }
  
           hypre_ForBoxI(bi, own_abox)
           {
              ownbox = hypre_BoxArrayBox(own_abox, bi);
              hypre_StructMapCoarseToFine(hypre_BoxIMin(ownbox), zero_index,
                                          refine_factors, hypre_BoxIMin(&refined_box));
              hypre_ClearIndex(temp_index1);
              for (j = 0; j < ndim; j++)
              {
                 temp_index1[j] = refine_factors[j] - 1;
              }
              hypre_StructMapCoarseToFine(hypre_BoxIMax(ownbox), temp_index1,
                                          refine_factors, hypre_BoxIMax(&refined_box));
              hypre_IntersectBoxes(fbox, &refined_box, &intersect_box);
  
              xc_dbox = hypre_BoxArrayBox(hypre_StructVectorDataSpace(xc_var),
                                          cboxnums[bi]);
  
              /*-----------------------------------------------------------------
               * Get ptrs for the crse struct_vectors. For linear interpolation
               * and arbitrary refinement factors, we need to point to the correct
               * coarse grid nodes. Note that the ownboxes were created so that
               * only the coarse nodes inside a fbox are contained in ownbox.
               * Since we loop over the fine intersect box, we need to refine
               * ownbox.
               *-----------------------------------------------------------------*/
              hypre_CopyIndex(hypre_BoxIMin(&intersect_box), start);
              hypre_CopyIndex(hypre_BoxIMax(&intersect_box), intersect_size);
              for (i = 0; i < 3; i++)
              {
                 intersect_size[i] -= (start[i] - 1);
              }
  
              /*------------------------------------------------------------------
               * The fine intersection box may not be divisible by the refinement
               * factor. This means that the interpolated coarse nodes and their
               * wieghts must be carefully determined. We accomplish this using the
               * offset away from a fine index that is divisible by the factor.
               * Because the ownboxes were created so that only coarse nodes
               * completely in the fbox are included, start is always divisible
               * by refine_factors. We do the calculation anyways for future changes.
               *------------------------------------------------------------------*/
              hypre_ClearIndex(start_offset);
              for (i = 0; i < ndim; i++)
              {
                 start_offset[i] = start[i] % refine_factors[i];
              }
  
              ptr_kshift = 0;
              if ( (start[2] % refine_factors[2] < refine_factors_half[2]) && ndim == 3 )
              {
                 ptr_kshift = -1;
              }
  
              ptr_jshift = 0;
              if ( start[1] % refine_factors[1] < refine_factors_half[1] && ndim >= 2 )
              {
                 ptr_jshift = -1;
              }
  
              ptr_ishift = 0;
              if ( start[0] % refine_factors[0] < refine_factors_half[0] )
              {
                 ptr_ishift = -1;
              }
  
              for (k = 0; k < ksize; k++)
              {
                 for (j = 0; j < jsize; j++)
                 {
                    hypre_SetIndex3(temp_index2, ptr_ishift, j + ptr_jshift, k + ptr_kshift);
                    xcp[k][j] = hypre_StructVectorBoxData(xc_var, cboxnums[bi]) +
                                hypre_BoxOffsetDistance(xc_dbox, temp_index2);
                 }
              }
  
              hypre_CopyIndex(hypre_BoxIMin(ownbox), startc);
              hypre_BoxGetSize(ownbox, loop_size);
  
              hypre_SerialBoxLoop2Begin(ndim, loop_size,
                                        e_dbox,  start,  stride,  ei,
                                        xc_dbox, startc, stridec, xci);
              {
                 /*--------------------------------------------------------
                  * Linear interpolation. Determine the weights and the
                  * correct coarse grid values to be weighted. All fine
                  * values in an agglomerated coarse cell or in the remainder
                  * agglomerated coarse cells are determined. The upper
                  * extents are needed.
                  *--------------------------------------------------------*/
                 zypre_BoxLoopGetIndex(lindex);
                 imax = hypre_min( (intersect_size[0] - lindex[0] * stride[0]),
                                   refine_factors[0] );
                 jmax = hypre_min( (intersect_size[1] - lindex[1] * stride[1]),
                                   refine_factors[1]);
                 kmax = hypre_min( (intersect_size[2] - lindex[2] * stride[2]),
                                   refine_factors[2]);
  
                 for (k = 0; k < kmax; k++)
                 {
                    if (ndim == 3)
                    {
                       offset_kp1 = start_offset[2] + k + 1;
  
                       if (ptr_kshift == -1)
                       {
                          if (offset_kp1 <= refine_factors_half[2])
                          {
                             zweight2 = weights[2][offset_kp1];
                             kshift = 0;
                          }
                          else
                          {
                             kshift = 1;
                             if (offset_kp1 >  refine_factors_half[2] &&
                                 offset_kp1 <= refine_factors[2])
                             {
                                zweight2 = weights[2][offset_kp1];
                             }
                             else
                             {
                                zweight2 = weights[2][offset_kp1 - refine_factors[2]];
                             }
                          }
                          zweight1 = 1.0 - zweight2;
                       }
  
                       else
                       {
                          if (offset_kp1 > refine_factors_half[2] &&
                              offset_kp1 <= refine_factors[2])
                          {
                             zweight2 = weights[2][offset_kp1];
                             kshift = 0;
                          }
                          else
                          {
                             kshift = 0;
                             offset_kp1 -= refine_factors[2];
                             if (offset_kp1 > 0 && offset_kp1 <= refine_factors_half[2])
                             {
                                zweight2 = weights[2][offset_kp1];
                             }
                             else
                             {
                                zweight2 = weights[2][offset_kp1];
                                kshift  = 1;
                             }
                          }
                          zweight1 = 1.0 - zweight2;
                       }
                    }     /* if (ndim == 3) */
  
                    for (j = 0; j < jmax; j++)
                    {
                       if (ndim >= 2)
                       {
                          offset_jp1 = start_offset[1] + j + 1;
  
                          if (ptr_jshift == -1)
                          {
                             if (offset_jp1 <= refine_factors_half[1])
                             {
                                yweight2 = weights[1][offset_jp1];
                                jshift = 0;
                             }
                             else
                             {
                                jshift = 1;
                                if (offset_jp1 >  refine_factors_half[1] &&
                                    offset_jp1 <= refine_factors[1])
                                {
                                   yweight2 = weights[1][offset_jp1];
                                }
                                else
                                {
                                   yweight2 = weights[1][offset_jp1 - refine_factors[1]];
                                }
                             }
                             yweight1 = 1.0 - yweight2;
                          }
  
                          else
                          {
                             if (offset_jp1 > refine_factors_half[1] &&
                                 offset_jp1 <= refine_factors[1])
                             {
                                yweight2 = weights[1][offset_jp1];
                                jshift = 0;
                             }
                             else
                             {
                                jshift = 0;
                                offset_jp1 -= refine_factors[1];
                                if (offset_jp1 > 0 && offset_jp1 <= refine_factors_half[1])
                                {
                                   yweight2 = weights[1][offset_jp1];
                                }
                                else
                                {
                                   yweight2 = weights[1][offset_jp1];
                                   jshift  = 1;
                                }
                             }
                             yweight1 = 1.0 - yweight2;
                          }
                       }     /* if (ndim >= 2) */
  
                       for (i = 0; i < imax; i++)
                       {
                          offset_ip1 = start_offset[0] + i + 1;
  
                          if (ptr_ishift == -1)
                          {
                             if (offset_ip1 <= refine_factors_half[0])
                             {
                                xweight2 = weights[0][offset_ip1];
                                ishift = 0;
                             }
                             else
                             {
                                ishift = 1;
                                if (offset_ip1 >  refine_factors_half[0] &&
                                    offset_ip1 <= refine_factors[0])
                                {
                                   xweight2 = weights[0][offset_ip1];
                                }
                                else
                                {
                                   xweight2 = weights[0][offset_ip1 - refine_factors[0]];
                                }
                             }
                             xweight1 = 1.0 - xweight2;
                          }
  
                          else
                          {
                             if (offset_ip1 > refine_factors_half[0] &&
                                 offset_ip1 <= refine_factors[0])
                             {
                                xweight2 = weights[0][offset_ip1];
                                ishift = 0;
                             }
                             else
                             {
                                ishift = 0;
                                offset_ip1 -= refine_factors[0];
                                if (offset_ip1 > 0 && offset_ip1 <= refine_factors_half[0])
                                {
                                   xweight2 = weights[0][offset_ip1];
                                }
                                else
                                {
                                   xweight2 = weights[0][offset_ip1];
                                   ishift  = 1;
                                }
                             }
                             xweight1 = 1.0 - xweight2;
                          }
  
                          if (ndim == 3)
                          {
                             ep[k][j][ei + i] = zweight1 * (
                                                   yweight1 * (
                                                      xweight1 * xcp[kshift][jshift][ishift + xci] +
                                                      xweight2 * xcp[kshift][jshift][ishift + xci + 1])
                                                   + yweight2 * (
                                                      xweight1 * xcp[kshift][jshift + 1][ishift + xci] +
                                                      xweight2 * xcp[kshift][jshift + 1][ishift + xci + 1]) )
                                                + zweight2 * (
                                                   yweight1 * (
                                                      xweight1 * xcp[kshift + 1][jshift][ishift + xci] +
                                                      xweight2 * xcp[kshift + 1][jshift][ishift + xci + 1])
                                                   + yweight2 * (
                                                      xweight1 * xcp[kshift + 1][jshift + 1][ishift + xci] +
                                                      xweight2 * xcp[kshift + 1][jshift + 1][ishift + xci + 1]) );
                          }
                          else if (ndim == 2)
                          {
                             ep[0][j][ei + i] = yweight1 * (
                                                   xweight1 * xcp[0][jshift][ishift + xci] +
                                                   xweight2 * xcp[0][jshift][ishift + xci + 1]);
                             ep[0][j][ei + i] += yweight2 * (
                                                    xweight1 * xcp[0][jshift + 1][ishift + xci] +
                                                    xweight2 * xcp[0][jshift + 1][ishift + xci + 1]);
                          }
                          else
                          {
                             ep[0][0][ei + i] = xweight1 * xcp[0][0][ishift + xci] +
                                                xweight2 * xcp[0][0][ishift + xci + 1];
                          }
                       }      /* for (i= 0; i< imax; i++) */
                    }         /* for (j= 0; j< jmax; j++) */
                 }            /* for (k= 0; k< kmax; k++) */
              }
              hypre_SerialBoxLoop2End(ei, xci);
  
           }/* hypre_ForBoxI(bi, own_abox) */
        }   /* hypre_ForBoxArray(fi, fgrid_boxes) */
  
        /*--------------------------------------------------------------------
         * Interpolate the off-processor coarse grid values. These are the
         * recv_cvector values. We will use the ownbox ptrs.
         * recv_vector is non-null even when it has a grid with zero-volume
         * boxes.
         *--------------------------------------------------------------------*/
        recv_var = hypre_SStructPVectorSVector(recv_cvectors, var);
        own_abox = hypre_StructGridBoxes(hypre_StructVectorGrid(recv_var));
        cboxnums = recv_boxnum_map[var];
  
        hypre_ForBoxI(bi, own_abox)
        {
           ownbox = hypre_BoxArrayBox(own_abox, bi);
  
           /*check for boxes of volume zero- i.e., recv_cvectors is really null.*/
           if (hypre_BoxVolume(ownbox))
           {
              xc_dbox = hypre_BoxArrayBox(
                           hypre_StructVectorDataSpace(recv_var), bi);
  
              fi = cboxnums[bi];
              fbox  = hypre_BoxArrayBox(fgrid_boxes, fi);
              e_dbox = hypre_BoxArrayBox(hypre_StructVectorDataSpace(e_var), fi);
  
              /*------------------------------------------------------------------
               * Get the ptrs for the fine struct_vectors.
               *------------------------------------------------------------------*/
              for (k = 0; k < refine_factors[2]; k++)
              {
                 for (j = 0; j < refine_factors[1]; j++)
                 {
                    hypre_SetIndex3(temp_index1, 0, j, k);
                    ep[k][j] = hypre_StructVectorBoxData(e_var, fi) +
                               hypre_BoxOffsetDistance(e_dbox, temp_index1);
                 }
              }
  
              hypre_StructMapCoarseToFine(hypre_BoxIMin(ownbox), zero_index,
                                          refine_factors, hypre_BoxIMin(&refined_box));
              hypre_ClearIndex(temp_index1);
              for (j = 0; j < ndim; j++)
              {
                 temp_index1[j] = refine_factors[j] - 1;
              }
              hypre_StructMapCoarseToFine(hypre_BoxIMax(ownbox), temp_index1,
                                          refine_factors, hypre_BoxIMax(&refined_box));
              hypre_IntersectBoxes(fbox, &refined_box, &intersect_box);
  
              /*-----------------------------------------------------------------
               * Get ptrs for the crse struct_vectors. For linear interpolation
               * and arbitrary refinement factors, we need to point to the correct
               * coarse grid nodes. Note that the ownboxes were created so that
               * only the coarse nodes inside a fbox are contained in ownbox.
               * Since we loop over the fine intersect box, we need to refine
               * ownbox.
               *-----------------------------------------------------------------*/
              hypre_CopyIndex(hypre_BoxIMin(&intersect_box), start);
              hypre_CopyIndex(hypre_BoxIMax(&intersect_box), intersect_size);
              for (i = 0; i < 3; i++)
              {
                 intersect_size[i] -= (start[i] - 1);
              }
  
              /*------------------------------------------------------------------
               * The fine intersection box may not be divisible by the refinement
               * factor. This means that the interpolated coarse nodes and their
               * weights must be carefully determined. We accomplish this using the
               * offset away from a fine index that is divisible by the factor.
               * Because the ownboxes were created so that only coarse nodes
               * completely in the fbox are included, start is always divisible
               * by refine_factors. We do the calculation anyways for future changes.
               *------------------------------------------------------------------*/
              hypre_ClearIndex(start_offset);
              for (i = 0; i < ndim; i++)
              {
                 start_offset[i] = start[i] % refine_factors[i];
              }
  
              ptr_kshift = 0;
              if ((start[2] % refine_factors[2] < refine_factors_half[2]) && ndim == 3)
              {
                 ptr_kshift = -1;
              }
  
              ptr_jshift = 0;
              if ((start[1] % refine_factors[1] < refine_factors_half[1]) && ndim >= 2)
              {
                 ptr_jshift = -1;
              }
  
              ptr_ishift = 0;
              if ( start[0] % refine_factors[0] < refine_factors_half[0] )
              {
                 ptr_ishift = -1;
              }
  
              for (k = 0; k < ksize; k++)
              {
                 for (j = 0; j < jsize; j++)
                 {
                    hypre_SetIndex3(temp_index2,
                                    ptr_ishift, j + ptr_jshift, k + ptr_kshift);
                    xcp[k][j] = hypre_StructVectorBoxData(recv_var, bi) +
                                hypre_BoxOffsetDistance(xc_dbox, temp_index2);
                 }
              }
  
              hypre_CopyIndex(hypre_BoxIMin(ownbox), startc);
              hypre_BoxGetSize(ownbox, loop_size);
  
              hypre_SerialBoxLoop2Begin(ndim, loop_size,
                                        e_dbox,  start,  stride,  ei,
                                        xc_dbox, startc, stridec, xci);
              {
                 /*--------------------------------------------------------
                  * Linear interpolation. Determine the weights and the
                  * correct coarse grid values to be weighted. All fine
                  * values in an agglomerated coarse cell or in the remainder
                  * agglomerated coarse cells are determined. The upper
                  * extents are needed.
                  *--------------------------------------------------------*/
                 zypre_BoxLoopGetIndex(lindex);
                 imax = hypre_min( (intersect_size[0] - lindex[0] * stride[0]),
                                   refine_factors[0] );
                 jmax = hypre_min( (intersect_size[1] - lindex[1] * stride[1]),
                                   refine_factors[1]);
                 kmax = hypre_min( (intersect_size[2] - lindex[2] * stride[2]),
                                   refine_factors[2]);
  
                 for (k = 0; k < kmax; k++)
                 {
                    if (ndim == 3)
                    {
                       offset_kp1 = start_offset[2] + k + 1;
  
                       if (ptr_kshift == -1)
                       {
                          if (offset_kp1 <= refine_factors_half[2])
                          {
                             zweight2 = weights[2][offset_kp1];
                             kshift = 0;
                          }
                          else
                          {
                             kshift = 1;
                             if (offset_kp1 >  refine_factors_half[2] &&
                                 offset_kp1 <= refine_factors[2])
                             {
                                zweight2 = weights[2][offset_kp1];
                             }
                             else
                             {
                                zweight2 = weights[2][offset_kp1 - refine_factors[2]];
                             }
                          }
                          zweight1 = 1.0 - zweight2;
                       }
  
                       else
                       {
                          if (offset_kp1 > refine_factors_half[2] &&
                              offset_kp1 <= refine_factors[2])
                          {
                             zweight2 = weights[2][offset_kp1];
                             kshift = 0;
                          }
                          else
                          {
                             kshift = 0;
                             offset_kp1 -= refine_factors[2];
                             if (offset_kp1 > 0 && offset_kp1 <= refine_factors_half[2])
                             {
                                zweight2 = weights[2][offset_kp1];
                             }
                             else
                             {
                                zweight2 = weights[2][offset_kp1];
                                kshift  = 1;
                             }
                          }
                          zweight1 = 1.0 - zweight2;
                       }
                    }     /* if (ndim == 3) */
  
                    for (j = 0; j < jmax; j++)
                    {
                       if (ndim >= 2)
                       {
                          offset_jp1 = start_offset[1] + j + 1;
  
                          if (ptr_jshift == -1)
                          {
                             if (offset_jp1 <= refine_factors_half[1])
                             {
                                yweight2 = weights[1][offset_jp1];
                                jshift = 0;
                             }
                             else
                             {
                                jshift = 1;
                                if (offset_jp1 >  refine_factors_half[1] &&
                                    offset_jp1 <= refine_factors[1])
                                {
                                   yweight2 = weights[1][offset_jp1];
                                }
                                else
                                {
                                   yweight2 = weights[1][offset_jp1 - refine_factors[1]];
                                }
                             }
                             yweight1 = 1.0 - yweight2;
                          }
  
                          else
                          {
                             if (offset_jp1 > refine_factors_half[1] &&
                                 offset_jp1 <= refine_factors[1])
                             {
                                yweight2 = weights[1][offset_jp1];
                                jshift = 0;
                             }
                             else
                             {
                                jshift = 0;
                                offset_jp1 -= refine_factors[1];
                                if (offset_jp1 > 0 && offset_jp1 <= refine_factors_half[1])
                                {
                                   yweight2 = weights[1][offset_jp1];
                                }
                                else
                                {
                                   yweight2 = weights[1][offset_jp1];
                                   jshift  = 1;
                                }
                             }
                             yweight1 = 1.0 - yweight2;
                          }
                       }  /* if (ndim >= 2) */
  
                       for (i = 0; i < imax; i++)
                       {
                          offset_ip1 = start_offset[0] + i + 1;
  
                          if (ptr_ishift == -1)
                          {
                             if (offset_ip1 <= refine_factors_half[0])
                             {
                                xweight2 = weights[0][offset_ip1];
                                ishift = 0;
                             }
                             else
                             {
                                ishift = 1;
                                if (offset_ip1 >  refine_factors_half[0] &&
                                    offset_ip1 <= refine_factors[0])
                                {
                                   xweight2 = weights[0][offset_ip1];
                                }
                                else
                                {
                                   xweight2 = weights[0][offset_ip1 - refine_factors[0]];
                                }
                             }
                             xweight1 = 1.0 - xweight2;
                          }
  
                          else
                          {
                             if (offset_ip1 > refine_factors_half[0] &&
                                 offset_ip1 <= refine_factors[0])
                             {
                                xweight2 = weights[0][offset_ip1];
                                ishift = 0;
                             }
                             else
                             {
                                ishift = 0;
                                offset_ip1 -= refine_factors[0];
                                if (offset_ip1 > 0 && offset_ip1 <= refine_factors_half[0])
                                {
                                   xweight2 = weights[0][offset_ip1];
                                }
                                else
                                {
                                   xweight2 = weights[0][offset_ip1];
                                   ishift  = 1;
                                }
                             }
                             xweight1 = 1.0 - xweight2;
                          }
  
  
                          if (ndim == 3)
                          {
                             ep[k][j][ei + i] = zweight1 * (
                                                   yweight1 * (
                                                      xweight1 * xcp[kshift][jshift][ishift + xci] +
                                                      xweight2 * xcp[kshift][jshift][ishift + xci + 1])
                                                   + yweight2 * (
                                                      xweight1 * xcp[kshift][jshift + 1][ishift + xci] +
                                                      xweight2 * xcp[kshift][jshift + 1][ishift + xci + 1]) )
                                                + zweight2 * (
                                                   yweight1 * (
                                                      xweight1 * xcp[kshift + 1][jshift][ishift + xci] +
                                                      xweight2 * xcp[kshift + 1][jshift][ishift + xci + 1])
                                                   + yweight2 * (
                                                      xweight1 * xcp[kshift + 1][jshift + 1][ishift + xci] +
                                                      xweight2 * xcp[kshift + 1][jshift + 1][ishift + xci + 1]) );
                          }
                          else if (ndim == 2)
                          {
                             ep[0][j][ei + i] = yweight1 * (
                                                   xweight1 * xcp[0][jshift][ishift + xci] +
                                                   xweight2 * xcp[0][jshift][ishift + xci + 1]);
                             ep[0][j][ei + i] += yweight2 * (
                                                    xweight1 * xcp[0][jshift + 1][ishift + xci] +
                                                    xweight2 * xcp[0][jshift + 1][ishift + xci + 1]);
                          }
  
                          else
                          {
                             ep[0][0][ei + i] = xweight1 * xcp[0][0][ishift + xci] +
                                                xweight2 * xcp[0][0][ishift + xci + 1];
                          }
  
                       }      /* for (i= 0; i< imax; i++) */
                    }         /* for (j= 0; j< jmax; j++) */
                 }            /* for (k= 0; k< kmax; k++) */
              }
              hypre_SerialBoxLoop2End(ei, xci);
  
           }  /* if (hypre_BoxVolume(ownbox)) */
        }     /* hypre_ForBoxI(bi, own_abox) */
     }         /* for (var= 0; var< nvars; var++)*/
  
     for (k = 0; k < ksize; k++)
     {
        hypre_TFree(xcp[k], HYPRE_MEMORY_HOST);
     }
     hypre_TFree(xcp, HYPRE_MEMORY_HOST);
  
     for (k = 0; k < refine_factors[2]; k++)
     {
        hypre_TFree(ep[k], HYPRE_MEMORY_HOST);
     }
     hypre_TFree(ep, HYPRE_MEMORY_HOST);
  
     /*-----------------------------------------------------------------------
      * Return
      *-----------------------------------------------------------------------*/
     return ierr;
  }
  