IFPACK  Development
 All Classes Files Functions Variables Enumerations Friends
ilu_mpi_bj.c
00001 /*@HEADER
00002 // ***********************************************************************
00003 //
00004 //       Ifpack: Object-Oriented Algebraic Preconditioner Package
00005 //                 Copyright (2002) Sandia Corporation
00006 //
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00038 //
00039 // ***********************************************************************
00040 //@HEADER
00041 */
00042 
00043 /* to do: re-integrate fix-smalll-pivots */
00044 
00045 #include "ilu_dh.h"
00046 #include "Mem_dh.h"
00047 #include "Parser_dh.h"
00048 #include "Euclid_dh.h"
00049 #include "getRow_dh.h"
00050 #include "Factor_dh.h"
00051 #include "SubdomainGraph_dh.h"
00052 
00053 
00054 int symbolic_row_private (int localRow, int beg_row, int end_row,
00055               int *list, int *marker, int *tmpFill,
00056               int len, int *CVAL, double *AVAL,
00057               int *o2n_col, Euclid_dh ctx);
00058 
00059 static int numeric_row_private (int localRow, int beg_row, int end_row,
00060                 int len, int *CVAL, double *AVAL,
00061                 REAL_DH * work, int *o2n_col, Euclid_dh ctx);
00062 
00063 
00064 /* all non-local column indices are discarded in symbolic_row_private() */
00065 #undef __FUNC__
00066 #define __FUNC__ "iluk_mpi_bj"
00067 void
00068 iluk_mpi_bj (Euclid_dh ctx)
00069 {
00070   START_FUNC_DH int *rp, *cval, *diag;
00071   int *CVAL;
00072   int i, j, len, count, col, idx = 0;
00073   int *list, *marker, *fill, *tmpFill;
00074   int temp, m, from = ctx->from, to = ctx->to;
00075   int *n2o_row, *o2n_col;
00076   int first_row, last_row;
00077   double *AVAL;
00078   REAL_DH *work, *aval;
00079   Factor_dh F = ctx->F;
00080   SubdomainGraph_dh sg = ctx->sg;
00081 
00082   if (ctx->F == NULL)
00083     {
00084       SET_V_ERROR ("ctx->F is NULL");
00085     }
00086   if (ctx->F->rp == NULL)
00087     {
00088       SET_V_ERROR ("ctx->F->rp is NULL");
00089     }
00090 
00091 /*  printf_dh("====================== starting iluk_mpi_bj; level= %i\n\n", ctx->level);
00092 */
00093 
00094   m = F->m;
00095   rp = F->rp;
00096   cval = F->cval;
00097   fill = F->fill;
00098   diag = F->diag;
00099   aval = F->aval;
00100   work = ctx->work;
00101 
00102   n2o_row = sg->n2o_row;
00103   o2n_col = sg->o2n_col;
00104 
00105   /* allocate and initialize working space */
00106   list = (int *) MALLOC_DH ((m + 1) * sizeof (int));
00107   CHECK_V_ERROR;
00108   marker = (int *) MALLOC_DH (m * sizeof (int));
00109   CHECK_V_ERROR;
00110   tmpFill = (int *) MALLOC_DH (m * sizeof (int));
00111   CHECK_V_ERROR;
00112   for (i = 0; i < m; ++i)
00113     {
00114       marker[i] = -1;
00115       work[i] = 0.0;
00116     }
00117 
00118   /*---------- main loop ----------*/
00119 
00120   /* global numbers of first and last locally owned rows,
00121      with respect to A 
00122    */
00123   first_row = sg->beg_row[myid_dh];
00124   last_row = first_row + sg->row_count[myid_dh];
00125   for (i = from; i < to; ++i)
00126     {
00127 
00128       int row = n2o_row[i]; /* local row number */
00129       int globalRow = row + first_row;  /* global row number */
00130 
00131       EuclidGetRow (ctx->A, globalRow, &len, &CVAL, &AVAL);
00132       CHECK_V_ERROR;
00133 
00134       /* compute scaling value for row(i) */
00135       if (ctx->isScaled)
00136     {
00137       compute_scaling_private (i, len, AVAL, ctx);
00138       CHECK_V_ERROR;
00139     }
00140 
00141       /* Compute symbolic factor for row(i);
00142          this also performs sparsification
00143        */
00144       count = symbolic_row_private (i, first_row, last_row,
00145                     list, marker, tmpFill,
00146                     len, CVAL, AVAL, o2n_col, ctx);
00147       CHECK_V_ERROR;
00148 
00149       /* Ensure adequate storage; reallocate, if necessary. */
00150       if (idx + count > F->alloc)
00151     {
00152       Factor_dhReallocate (F, idx, count);
00153       CHECK_V_ERROR;
00154       SET_INFO ("REALLOCATED from lu_mpi_bj");
00155       cval = F->cval;
00156       fill = F->fill;
00157       aval = F->aval;
00158     }
00159 
00160       /* Copy factored symbolic row to permanent storage */
00161       col = list[m];
00162       while (count--)
00163     {
00164       cval[idx] = col;
00165       fill[idx] = tmpFill[col];
00166       ++idx;
00167       col = list[col];
00168     }
00169 
00170       /* add row-pointer to start of next row. */
00171       rp[i + 1] = idx;
00172 
00173       /* Insert pointer to diagonal */
00174       temp = rp[i];
00175       while (cval[temp] != i)
00176     ++temp;
00177       diag[i] = temp;
00178 
00179       /* compute numeric factor for current row */
00180       numeric_row_private (i, first_row, last_row,
00181                len, CVAL, AVAL, work, o2n_col, ctx);
00182       CHECK_V_ERROR EuclidRestoreRow (ctx->A, globalRow, &len, &CVAL, &AVAL);
00183       CHECK_V_ERROR;
00184 
00185       /* Copy factored numeric row to permanent storage,
00186          and re-zero work vector
00187        */
00188       for (j = rp[i]; j < rp[i + 1]; ++j)
00189     {
00190       col = cval[j];
00191       aval[j] = work[col];
00192       work[col] = 0.0;
00193     }
00194 
00195       /* check for zero diagonal */
00196       if (!aval[diag[i]])
00197     {
00198       sprintf (msgBuf_dh, "zero diagonal in local row %i", i + 1);
00199       SET_V_ERROR (msgBuf_dh);
00200     }
00201     }
00202 
00203   FREE_DH (list);
00204   CHECK_V_ERROR;
00205   FREE_DH (tmpFill);
00206   CHECK_V_ERROR;
00207   FREE_DH (marker);
00208   CHECK_V_ERROR;
00209 
00210 END_FUNC_DH}
00211 
00212 
00213 
00214 /* Computes ILU(K) factor of a single row; returns fill 
00215    count for the row.  Explicitly inserts diag if not already 
00216    present.  On return, all column indices are local 
00217    (i.e, referenced to 0).
00218 */
00219 #undef __FUNC__
00220 #define __FUNC__ "symbolic_row_private"
00221 int
00222 symbolic_row_private (int localRow, int beg_row, int end_row,
00223               int *list, int *marker, int *tmpFill,
00224               int len, int *CVAL, double *AVAL,
00225               int *o2n_col, Euclid_dh ctx)
00226 {
00227   START_FUNC_DH int level = ctx->level, m = ctx->F->m;
00228   int *cval = ctx->F->cval, *diag = ctx->F->diag, *rp = ctx->F->rp;
00229   int *fill = ctx->F->fill;
00230   int count = 0;
00231   int j, node, tmp, col, head;
00232   int fill1, fill2;
00233   float val;
00234   double thresh = ctx->sparseTolA;
00235   REAL_DH scale;
00236 
00237   scale = ctx->scale[localRow];
00238   ctx->stats[NZA_STATS] += (double) len;
00239 
00240   /* Insert col indices in linked list, and values in work vector.
00241    * List[m] points to the first (smallest) col in the linked list.
00242    * Column values are adjusted from global to local numbering.
00243    */
00244   list[m] = m;
00245   for (j = 0; j < len; ++j)
00246     {
00247       tmp = m;
00248       col = *CVAL++;
00249       val = *AVAL++;
00250 
00251       /* throw out nonlocal columns */
00252       if (col >= beg_row && col < end_row)
00253     {
00254       col -= beg_row;   /* adjust column to local zero-based */
00255       col = o2n_col[col];   /* permute column */
00256       if (fabs (scale * val) > thresh || col == localRow)
00257         {           /* sparsification */
00258           ++count;
00259           while (col > list[tmp])
00260         tmp = list[tmp];
00261           list[col] = list[tmp];
00262           list[tmp] = col;
00263           tmpFill[col] = 0;
00264           marker[col] = localRow;
00265         }
00266     }
00267     }
00268 
00269   /* insert diag if not already present */
00270   if (marker[localRow] != localRow)
00271     {
00272 /*     ctx->symbolicZeroDiags += 1; */
00273       tmp = m;
00274       while (localRow > list[tmp])
00275     tmp = list[tmp];
00276       list[localRow] = list[tmp];
00277       list[tmp] = localRow;
00278       tmpFill[localRow] = 0;
00279       marker[localRow] = localRow;
00280       ++count;
00281     }
00282   ctx->stats[NZA_USED_STATS] += (double) count;
00283 
00284   /* update row from previously factored rows */
00285   head = m;
00286   if (level > 0)
00287     {
00288       while (list[head] < localRow)
00289     {
00290       node = list[head];
00291       fill1 = tmpFill[node];
00292 
00293       if (fill1 < level)
00294         {
00295           for (j = diag[node] + 1; j < rp[node + 1]; ++j)
00296         {
00297           col = cval[j];
00298           fill2 = fill1 + fill[j] + 1;
00299 
00300           if (fill2 <= level)
00301             {
00302               /* if newly discovered fill entry, mark it as discovered;
00303                * if entry has level <= K, add it to the linked-list.
00304                */
00305               if (marker[col] < localRow)
00306             {
00307               tmp = head;
00308               marker[col] = localRow;
00309               tmpFill[col] = fill2;
00310               while (col > list[tmp])
00311                 tmp = list[tmp];
00312               list[col] = list[tmp];
00313               list[tmp] = col;
00314               ++count;  /* increment fill count */
00315             }
00316 
00317               /* if previously-discovered fill, update the entry's level. */
00318               else
00319             {
00320               tmpFill[col] =
00321                 (fill2 < tmpFill[col]) ? fill2 : tmpFill[col];
00322             }
00323             }
00324         }
00325         }
00326       head = list[head];    /* advance to next item in linked list */
00327     }
00328     }
00329 END_FUNC_VAL (count)}
00330 
00331 
00332 #undef __FUNC__
00333 #define __FUNC__ "numeric_row_private"
00334 int
00335 numeric_row_private (int localRow, int beg_row, int end_row,
00336              int len, int *CVAL, double *AVAL,
00337              REAL_DH * work, int *o2n_col, Euclid_dh ctx)
00338 {
00339   START_FUNC_DH double pc, pv, multiplier;
00340   int j, k, col, row;
00341   int *rp = ctx->F->rp, *cval = ctx->F->cval;
00342   int *diag = ctx->F->diag;
00343   double val;
00344   REAL_DH *aval = ctx->F->aval, scale;
00345 
00346   scale = ctx->scale[localRow];
00347 
00348   /* zero work vector */
00349   /* note: indices in col[] are already permuted, and are 
00350      local (zero-based)
00351    */
00352   for (j = rp[localRow]; j < rp[localRow + 1]; ++j)
00353     {
00354       col = cval[j];
00355       work[col] = 0.0;
00356     }
00357 
00358   /* init work vector with values from A */
00359   /* (note: some values may be na due to sparsification; this is O.K.) */
00360   for (j = 0; j < len; ++j)
00361     {
00362       col = *CVAL++;
00363       val = *AVAL++;
00364 
00365       if (col >= beg_row && col < end_row)
00366     {
00367       col -= beg_row;   /* adjust column to local zero-based */
00368       col = o2n_col[col];   /* we permute the indices from A */
00369       work[col] = val * scale;
00370     }
00371     }
00372 
00373   for (j = rp[localRow]; j < diag[localRow]; ++j)
00374     {
00375       row = cval[j];
00376       pc = work[row];
00377 
00378       if (pc != 0.0)
00379     {
00380       pv = aval[diag[row]];
00381       multiplier = pc / pv;
00382       work[row] = multiplier;
00383 
00384       for (k = diag[row] + 1; k < rp[row + 1]; ++k)
00385         {
00386           col = cval[k];
00387           work[col] -= (multiplier * aval[k]);
00388         }
00389     }
00390     }
00391 
00392   /* check for zero or too small of a pivot */
00393 #if 0
00394   if (fabs (work[i]) <= pivotTol)
00395     {
00396       /* yuck! assume row scaling, and just stick in a value */
00397       aval[diag[i]] = pivotFix;
00398     }
00399 #endif
00400 
00401 END_FUNC_VAL (0)}
 All Classes Files Functions Variables Enumerations Friends