IFPACK  Development
 All Classes Files Functions Variables Enumerations Friends
ilu_seq.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 static bool check_constraint_private (Euclid_dh ctx, int b, int j);
00054 
00055 static int symbolic_row_private (int localRow,
00056                  int *list, int *marker, int *tmpFill,
00057                  int len, int *CVAL, double *AVAL,
00058                  int *o2n_col, Euclid_dh ctx, bool debug);
00059 
00060 static int numeric_row_private (int localRow,
00061                 int len, int *CVAL, double *AVAL,
00062                 REAL_DH * work, int *o2n_col, Euclid_dh ctx,
00063                 bool debug);
00064 
00065 
00066 #undef __FUNC__
00067 #define __FUNC__ "compute_scaling_private"
00068 void
00069 compute_scaling_private (int row, int len, double *AVAL, Euclid_dh ctx)
00070 {
00071   START_FUNC_DH double tmp = 0.0;
00072   int j;
00073 
00074   for (j = 0; j < len; ++j)
00075     tmp = MAX (tmp, fabs (AVAL[j]));
00076   if (tmp)
00077     {
00078       ctx->scale[row] = 1.0 / tmp;
00079     }
00080 END_FUNC_DH}
00081 
00082 #if 0
00083 
00084 /* not used ? */
00085 #undef __FUNC__
00086 #define __FUNC__ "fixPivot_private"
00087 double
00088 fixPivot_private (int row, int len, float *vals)
00089 {
00090   START_FUNC_DH int i;
00091   float max = 0.0;
00092   bool debug = false;
00093 
00094   for (i = 0; i < len; ++i)
00095     {
00096       float tmp = fabs (vals[i]);
00097       max = MAX (max, tmp);
00098     }
00099 END_FUNC_VAL (max * ctxPrivate->pivotFix)}
00100 
00101 #endif
00102 
00103 
00104 
00105 
00106 #undef __FUNC__
00107 #define __FUNC__ "iluk_seq"
00108 void
00109 iluk_seq (Euclid_dh ctx)
00110 {
00111   START_FUNC_DH int *rp, *cval, *diag;
00112   int *CVAL;
00113   int i, j, len, count, col, idx = 0;
00114   int *list, *marker, *fill, *tmpFill;
00115   int temp, m, from = ctx->from, to = ctx->to;
00116   int *n2o_row, *o2n_col, beg_row, beg_rowP;
00117   double *AVAL;
00118   REAL_DH *work, *aval;
00119   Factor_dh F = ctx->F;
00120   SubdomainGraph_dh sg = ctx->sg;
00121   bool debug = false;
00122 
00123   if (logFile != NULL && Parser_dhHasSwitch (parser_dh, "-debug_ilu"))
00124     debug = true;
00125 
00126   m = F->m;
00127   rp = F->rp;
00128   cval = F->cval;
00129   fill = F->fill;
00130   diag = F->diag;
00131   aval = F->aval;
00132   work = ctx->work;
00133   count = rp[from];
00134 
00135   if (sg == NULL)
00136     {
00137       SET_V_ERROR ("subdomain graph is NULL");
00138     }
00139 
00140   n2o_row = ctx->sg->n2o_row;
00141   o2n_col = ctx->sg->o2n_col;
00142   beg_row = ctx->sg->beg_row[myid_dh];
00143   beg_rowP = ctx->sg->beg_rowP[myid_dh];
00144 
00145   /* allocate and initialize working space */
00146   list = (int *) MALLOC_DH ((m + 1) * sizeof (int));
00147   CHECK_V_ERROR;
00148   marker = (int *) MALLOC_DH (m * sizeof (int));
00149   CHECK_V_ERROR;
00150   tmpFill = (int *) MALLOC_DH (m * sizeof (int));
00151   CHECK_V_ERROR;
00152   for (i = 0; i < m; ++i)
00153     marker[i] = -1;
00154 
00155   /* working space for values */
00156   for (i = 0; i < m; ++i)
00157     work[i] = 0.0;
00158 
00159 /*    printf_dh("====================== starting iluk_seq; level= %i\n\n", ctx->level); 
00160 */
00161 
00162 
00163   /*---------- main loop ----------*/
00164 
00165   for (i = from; i < to; ++i)
00166     {
00167       int row = n2o_row[i]; /* local row number */
00168       int globalRow = row + beg_row;    /* global row number */
00169 
00170 /*fprintf(logFile, "--------------------------------- localRow= %i\n", 1+i);
00171 */
00172 
00173       if (debug)
00174     {
00175       fprintf (logFile,
00176            "ILU_seq ================================= starting local row: %i, (global= %i) level= %i\n",
00177            i + 1, i + 1 + sg->beg_rowP[myid_dh], ctx->level);
00178     }
00179 
00180       EuclidGetRow (ctx->A, globalRow, &len, &CVAL, &AVAL);
00181       CHECK_V_ERROR;
00182 
00183       /* compute scaling value for row(i) */
00184       if (ctx->isScaled)
00185     {
00186       compute_scaling_private (i, len, AVAL, ctx);
00187       CHECK_V_ERROR;
00188     }
00189 
00190       /* Compute symbolic factor for row(i);
00191          this also performs sparsification
00192        */
00193       count = symbolic_row_private (i, list, marker, tmpFill,
00194                     len, CVAL, AVAL, o2n_col, ctx, debug);
00195       CHECK_V_ERROR;
00196 
00197       /* Ensure adequate storage; reallocate, if necessary. */
00198       if (idx + count > F->alloc)
00199     {
00200       Factor_dhReallocate (F, idx, count);
00201       CHECK_V_ERROR;
00202       SET_INFO ("REALLOCATED from ilu_seq");
00203       cval = F->cval;
00204       fill = F->fill;
00205       aval = F->aval;
00206     }
00207 
00208       /* Copy factored symbolic row to permanent storage */
00209       col = list[m];
00210       while (count--)
00211     {
00212       cval[idx] = col;
00213       fill[idx] = tmpFill[col];
00214       ++idx;
00215 /*fprintf(logFile, "  col= %i\n", 1+col);
00216 */
00217       col = list[col];
00218     }
00219 
00220       /* add row-pointer to start of next row. */
00221       rp[i + 1] = idx;
00222 
00223       /* Insert pointer to diagonal */
00224       temp = rp[i];
00225       while (cval[temp] != i)
00226     ++temp;
00227       diag[i] = temp;
00228 
00229 /*fprintf(logFile, "  diag[i]= %i\n", diag);
00230 */
00231 
00232       /* compute numeric factor for current row */
00233       numeric_row_private (i, len, CVAL, AVAL, work, o2n_col, ctx, debug);
00234       CHECK_V_ERROR EuclidRestoreRow (ctx->A, globalRow, &len, &CVAL, &AVAL);
00235       CHECK_V_ERROR;
00236 
00237       /* Copy factored numeric row to permanent storage,
00238          and re-zero work vector
00239        */
00240       if (debug)
00241     {
00242       fprintf (logFile, "ILU_seq:  ");
00243       for (j = rp[i]; j < rp[i + 1]; ++j)
00244         {
00245           col = cval[j];
00246           aval[j] = work[col];
00247           work[col] = 0.0;
00248           fprintf (logFile, "%i,%i,%g ; ", 1 + cval[j], fill[j], aval[j]);
00249           fflush (logFile);
00250         }
00251       fprintf (logFile, "\n");
00252     }
00253       else
00254     {
00255       for (j = rp[i]; j < rp[i + 1]; ++j)
00256         {
00257           col = cval[j];
00258           aval[j] = work[col];
00259           work[col] = 0.0;
00260         }
00261     }
00262 
00263       /* check for zero diagonal */
00264       if (!aval[diag[i]])
00265     {
00266       sprintf (msgBuf_dh, "zero diagonal in local row %i", i + 1);
00267       SET_V_ERROR (msgBuf_dh);
00268     }
00269     }
00270 
00271   FREE_DH (list);
00272   CHECK_V_ERROR;
00273   FREE_DH (tmpFill);
00274   CHECK_V_ERROR;
00275   FREE_DH (marker);
00276   CHECK_V_ERROR;
00277 
00278   /* adjust column indices back to global */
00279   if (beg_rowP)
00280     {
00281       int start = rp[from];
00282       int stop = rp[to];
00283       for (i = start; i < stop; ++i)
00284     cval[i] += beg_rowP;
00285     }
00286 
00287   /* for debugging: this is so the Print methods will work, even if
00288      F hasn't been fully factored
00289    */
00290   for (i = to + 1; i < m; ++i)
00291     rp[i] = 0;
00292 
00293 END_FUNC_DH}
00294 
00295 
00296 #undef __FUNC__
00297 #define __FUNC__ "iluk_seq_block"
00298 void
00299 iluk_seq_block (Euclid_dh ctx)
00300 {
00301   START_FUNC_DH int *rp, *cval, *diag;
00302   int *CVAL;
00303   int h, i, j, len, count, col, idx = 0;
00304   int *list, *marker, *fill, *tmpFill;
00305   int temp, m;
00306   int *n2o_row, *o2n_col, *beg_rowP, *n2o_sub, blocks;
00307   int *row_count, *dummy = NULL, dummy2[1];
00308   double *AVAL;
00309   REAL_DH *work, *aval;
00310   Factor_dh F = ctx->F;
00311   SubdomainGraph_dh sg = ctx->sg;
00312   bool bj = false, constrained = false;
00313   int discard = 0;
00314   int gr = -1;          /* globalRow */
00315   bool debug = false;
00316 
00317   if (logFile != NULL && Parser_dhHasSwitch (parser_dh, "-debug_ilu"))
00318     debug = true;
00319 
00320 /*fprintf(stderr, "====================== starting iluk_seq_block; level= %i\n\n", ctx->level); 
00321 */
00322 
00323   if (!strcmp (ctx->algo_par, "bj"))
00324     bj = true;
00325   constrained = !Parser_dhHasSwitch (parser_dh, "-unconstrained");
00326 
00327   m = F->m;
00328   rp = F->rp;
00329   cval = F->cval;
00330   fill = F->fill;
00331   diag = F->diag;
00332   aval = F->aval;
00333   work = ctx->work;
00334 
00335   if (sg != NULL)
00336     {
00337       n2o_row = sg->n2o_row;
00338       o2n_col = sg->o2n_col;
00339       row_count = sg->row_count;
00340       /* beg_row   = sg->beg_row ; */
00341       beg_rowP = sg->beg_rowP;
00342       n2o_sub = sg->n2o_sub;
00343       blocks = sg->blocks;
00344     }
00345 
00346   else
00347     {
00348       dummy = (int *) MALLOC_DH (m * sizeof (int));
00349       CHECK_V_ERROR;
00350       for (i = 0; i < m; ++i)
00351     dummy[i] = i;
00352       n2o_row = dummy;
00353       o2n_col = dummy;
00354       dummy2[0] = m;
00355       row_count = dummy2;
00356       /* beg_row   = 0; */
00357       beg_rowP = dummy;
00358       n2o_sub = dummy;
00359       blocks = 1;
00360     }
00361 
00362   /* allocate and initialize working space */
00363   list = (int *) MALLOC_DH ((m + 1) * sizeof (int));
00364   CHECK_V_ERROR;
00365   marker = (int *) MALLOC_DH (m * sizeof (int));
00366   CHECK_V_ERROR;
00367   tmpFill = (int *) MALLOC_DH (m * sizeof (int));
00368   CHECK_V_ERROR;
00369   for (i = 0; i < m; ++i)
00370     marker[i] = -1;
00371 
00372   /* working space for values */
00373   for (i = 0; i < m; ++i)
00374     work[i] = 0.0;
00375 
00376   /*---------- main loop ----------*/
00377 
00378   for (h = 0; h < blocks; ++h)
00379     {
00380       /* 1st and last row in current block, with respect to A */
00381       int curBlock = n2o_sub[h];
00382       int first_row = beg_rowP[curBlock];
00383       int end_row = first_row + row_count[curBlock];
00384 
00385       if (debug)
00386     {
00387       fprintf (logFile, "\n\nILU_seq BLOCK: %i @@@@@@@@@@@@@@@ \n",
00388            curBlock);
00389     }
00390 
00391       for (i = first_row; i < end_row; ++i)
00392     {
00393       int row = n2o_row[i];
00394       ++gr;
00395 
00396       if (debug)
00397         {
00398           fprintf (logFile,
00399                "ILU_seq  global: %i  local: %i =================================\n",
00400                1 + gr, 1 + i - first_row);
00401         }
00402 
00403 /*prinft("first_row= %i  end_row= %i\n", first_row, end_row);
00404 */
00405 
00406       EuclidGetRow (ctx->A, row, &len, &CVAL, &AVAL);
00407       CHECK_V_ERROR;
00408 
00409       /* compute scaling value for row(i) */
00410       if (ctx->isScaled)
00411         {
00412           compute_scaling_private (i, len, AVAL, ctx);
00413           CHECK_V_ERROR;
00414         }
00415 
00416       /* Compute symbolic factor for row(i);
00417          this also performs sparsification
00418        */
00419       count = symbolic_row_private (i, list, marker, tmpFill,
00420                     len, CVAL, AVAL, o2n_col, ctx, debug);
00421       CHECK_V_ERROR;
00422 
00423       /* Ensure adequate storage; reallocate, if necessary. */
00424       if (idx + count > F->alloc)
00425         {
00426           Factor_dhReallocate (F, idx, count);
00427           CHECK_V_ERROR;
00428           SET_INFO ("REALLOCATED from ilu_seq");
00429           cval = F->cval;
00430           fill = F->fill;
00431           aval = F->aval;
00432         }
00433 
00434       /* Copy factored symbolic row to permanent storage */
00435       col = list[m];
00436       while (count--)
00437         {
00438 
00439           /* constrained pilu */
00440           if (constrained && !bj)
00441         {
00442           if (col >= first_row && col < end_row)
00443             {
00444               cval[idx] = col;
00445               fill[idx] = tmpFill[col];
00446               ++idx;
00447             }
00448           else
00449             {
00450               if (check_constraint_private (ctx, curBlock, col))
00451             {
00452               cval[idx] = col;
00453               fill[idx] = tmpFill[col];
00454               ++idx;
00455             }
00456               else
00457             {
00458               ++discard;
00459             }
00460             }
00461           col = list[col];
00462         }
00463 
00464           /* block jacobi case */
00465           else if (bj)
00466         {
00467           if (col >= first_row && col < end_row)
00468             {
00469               cval[idx] = col;
00470               fill[idx] = tmpFill[col];
00471               ++idx;
00472             }
00473           else
00474             {
00475               ++discard;
00476             }
00477           col = list[col];
00478         }
00479 
00480           /* general case */
00481           else
00482         {
00483           cval[idx] = col;
00484           fill[idx] = tmpFill[col];
00485           ++idx;
00486           col = list[col];
00487         }
00488         }
00489 
00490       /* add row-pointer to start of next row. */
00491       rp[i + 1] = idx;
00492 
00493       /* Insert pointer to diagonal */
00494       temp = rp[i];
00495       while (cval[temp] != i)
00496         ++temp;
00497       diag[i] = temp;
00498 
00499       /* compute numeric factor for current row */
00500       numeric_row_private (i, len, CVAL, AVAL, work, o2n_col, ctx, debug);
00501       CHECK_V_ERROR EuclidRestoreRow (ctx->A, row, &len, &CVAL, &AVAL);
00502       CHECK_V_ERROR;
00503 
00504       /* Copy factored numeric row to permanent storage,
00505          and re-zero work vector
00506        */
00507       if (debug)
00508         {
00509           fprintf (logFile, "ILU_seq: ");
00510           for (j = rp[i]; j < rp[i + 1]; ++j)
00511         {
00512           col = cval[j];
00513           aval[j] = work[col];
00514           work[col] = 0.0;
00515           fprintf (logFile, "%i,%i,%g ; ", 1 + cval[j], fill[j],
00516                aval[j]);
00517         }
00518           fprintf (logFile, "\n");
00519         }
00520 
00521       /* normal operation */
00522       else
00523         {
00524           for (j = rp[i]; j < rp[i + 1]; ++j)
00525         {
00526           col = cval[j];
00527           aval[j] = work[col];
00528           work[col] = 0.0;
00529         }
00530         }
00531 
00532       /* check for zero diagonal */
00533       if (!aval[diag[i]])
00534         {
00535           sprintf (msgBuf_dh, "zero diagonal in local row %i", i + 1);
00536           SET_V_ERROR (msgBuf_dh);
00537         }
00538     }
00539     }
00540 
00541 /*  printf("bj= %i  constrained= %i  discarded= %i\n", bj, constrained, discard); */
00542 
00543   if (dummy != NULL)
00544     {
00545       FREE_DH (dummy);
00546       CHECK_V_ERROR;
00547     }
00548   FREE_DH (list);
00549   CHECK_V_ERROR;
00550   FREE_DH (tmpFill);
00551   CHECK_V_ERROR;
00552   FREE_DH (marker);
00553   CHECK_V_ERROR;
00554 
00555 END_FUNC_DH}
00556 
00557 
00558 
00559 /* Computes ILU(K) factor of a single row; returns fill 
00560    count for the row.  Explicitly inserts diag if not already 
00561    present.  On return, all column indices are local 
00562    (i.e, referenced to 0).
00563 */
00564 #undef __FUNC__
00565 #define __FUNC__ "symbolic_row_private"
00566 int
00567 symbolic_row_private (int localRow,
00568               int *list, int *marker, int *tmpFill,
00569               int len, int *CVAL, double *AVAL,
00570               int *o2n_col, Euclid_dh ctx, bool debug)
00571 {
00572   START_FUNC_DH int level = ctx->level, m = ctx->F->m;
00573   int *cval = ctx->F->cval, *diag = ctx->F->diag, *rp = ctx->F->rp;
00574   int *fill = ctx->F->fill;
00575   int count = 0;
00576   int j, node, tmp, col, head;
00577   int fill1, fill2, beg_row;
00578   double val;
00579   double thresh = ctx->sparseTolA;
00580   REAL_DH scale;
00581 
00582   scale = ctx->scale[localRow];
00583   ctx->stats[NZA_STATS] += (double) len;
00584   beg_row = ctx->sg->beg_row[myid_dh];
00585 
00586   /* Insert col indices in linked list, and values in work vector.
00587    * List[m] points to the first (smallest) col in the linked list.
00588    * Column values are adjusted from global to local numbering.
00589    */
00590   list[m] = m;
00591   for (j = 0; j < len; ++j)
00592     {
00593       tmp = m;
00594       col = *CVAL++;
00595       col -= beg_row;       /* adjust to zero based */
00596       col = o2n_col[col];   /* permute the column */
00597       val = *AVAL++;
00598       val *= scale;     /* scale the value */
00599 
00600       if (fabs (val) > thresh || col == localRow)
00601     {           /* sparsification */
00602       ++count;
00603       while (col > list[tmp])
00604         tmp = list[tmp];
00605       list[col] = list[tmp];
00606       list[tmp] = col;
00607       tmpFill[col] = 0;
00608       marker[col] = localRow;
00609     }
00610     }
00611 
00612   /* insert diag if not already present */
00613   if (marker[localRow] != localRow)
00614     {
00615       tmp = m;
00616       while (localRow > list[tmp])
00617     tmp = list[tmp];
00618       list[localRow] = list[tmp];
00619       list[tmp] = localRow;
00620       tmpFill[localRow] = 0;
00621       marker[localRow] = localRow;
00622       ++count;
00623     }
00624   ctx->stats[NZA_USED_STATS] += (double) count;
00625 
00626   /* update row from previously factored rows */
00627   head = m;
00628   if (level > 0)
00629     {
00630       while (list[head] < localRow)
00631     {
00632       node = list[head];
00633       fill1 = tmpFill[node];
00634 
00635       if (debug)
00636         {
00637           fprintf (logFile, "ILU_seq   sf updating from row: %i\n",
00638                1 + node);
00639         }
00640 
00641       if (fill1 < level)
00642         {
00643           for (j = diag[node] + 1; j < rp[node + 1]; ++j)
00644         {
00645           col = cval[j];
00646           fill2 = fill1 + fill[j] + 1;
00647 
00648           if (fill2 <= level)
00649             {
00650               /* if newly discovered fill entry, mark it as discovered;
00651                * if entry has level <= K, add it to the linked-list.
00652                */
00653               if (marker[col] < localRow)
00654             {
00655               tmp = head;
00656               marker[col] = localRow;
00657               tmpFill[col] = fill2;
00658               while (col > list[tmp])
00659                 tmp = list[tmp];
00660               list[col] = list[tmp];
00661               list[tmp] = col;
00662               ++count;  /* increment fill count */
00663             }
00664 
00665               /* if previously-discovered fill, update the entry's level. */
00666               else
00667             {
00668               tmpFill[col] =
00669                 (fill2 < tmpFill[col]) ? fill2 : tmpFill[col];
00670             }
00671             }
00672         }
00673         }           /* fill1 < level  */
00674       head = list[head];    /* advance to next item in linked list */
00675     }
00676     }
00677 END_FUNC_VAL (count)}
00678 
00679 
00680 #undef __FUNC__
00681 #define __FUNC__ "numeric_row_private"
00682 int
00683 numeric_row_private (int localRow,
00684              int len, int *CVAL, double *AVAL,
00685              REAL_DH * work, int *o2n_col, Euclid_dh ctx, bool debug)
00686 {
00687   START_FUNC_DH double pc, pv, multiplier;
00688   int j, k, col, row;
00689   int *rp = ctx->F->rp, *cval = ctx->F->cval;
00690   int *diag = ctx->F->diag;
00691   int beg_row;
00692   double val;
00693   REAL_DH *aval = ctx->F->aval, scale;
00694 
00695   scale = ctx->scale[localRow];
00696   beg_row = ctx->sg->beg_row[myid_dh];
00697 
00698   /* zero work vector */
00699   /* note: indices in col[] are already permuted. */
00700   for (j = rp[localRow]; j < rp[localRow + 1]; ++j)
00701     {
00702       col = cval[j];
00703       work[col] = 0.0;
00704     }
00705 
00706   /* init work vector with values from A */
00707   /* (note: some values may be na due to sparsification; this is O.K.) */
00708   for (j = 0; j < len; ++j)
00709     {
00710       col = *CVAL++;
00711       col -= beg_row;
00712       val = *AVAL++;
00713       col = o2n_col[col];   /* note: we permute the indices from A */
00714       work[col] = val * scale;
00715     }
00716 
00717 
00718 
00719 /*fprintf(stderr, "local row= %i\n", 1+localRow);
00720 */
00721 
00722 
00723   for (j = rp[localRow]; j < diag[localRow]; ++j)
00724     {
00725       row = cval[j];        /* previously factored row */
00726       pc = work[row];
00727 
00728 
00729       pv = aval[diag[row]]; /* diagonal of previously factored row */
00730 
00731 /*
00732 if (pc == 0.0 || pv == 0.0) {
00733 fprintf(stderr, "pv= %g; pc= %g\n", pv, pc);
00734 }
00735 */
00736 
00737       if (pc != 0.0 && pv != 0.0)
00738     {
00739       multiplier = pc / pv;
00740       work[row] = multiplier;
00741 
00742       if (debug)
00743         {
00744           fprintf (logFile,
00745                "ILU_seq   nf updating from row: %i; multiplier= %g\n",
00746                1 + row, multiplier);
00747         }
00748 
00749       for (k = diag[row] + 1; k < rp[row + 1]; ++k)
00750         {
00751           col = cval[k];
00752           work[col] -= (multiplier * aval[k]);
00753         }
00754     }
00755       else
00756     {
00757       if (debug)
00758         {
00759           fprintf (logFile,
00760                "ILU_seq   nf NO UPDATE from row %i; pc = %g; pv = %g\n",
00761                1 + row, pc, pv);
00762         }
00763     }
00764     }
00765 
00766   /* check for zero or too small of a pivot */
00767 #if 0
00768   if (fabs (work[i]) <= pivotTol)
00769     {
00770       /* yuck! assume row scaling, and just stick in a value */
00771       aval[diag[i]] = pivotFix;
00772     }
00773 #endif
00774 
00775 END_FUNC_VAL (0)}
00776 
00777 
00778 /*-----------------------------------------------------------------------*
00779  * ILUT starts here
00780  *-----------------------------------------------------------------------*/
00781 int ilut_row_private (int localRow, int *list, int *o2n_col, int *marker,
00782               int len, int *CVAL, double *AVAL,
00783               REAL_DH * work, Euclid_dh ctx, bool debug);
00784 
00785 #undef __FUNC__
00786 #define __FUNC__ "ilut_seq"
00787 void
00788 ilut_seq (Euclid_dh ctx)
00789 {
00790   START_FUNC_DH int *rp, *cval, *diag, *CVAL;
00791   int i, len, count, col, idx = 0;
00792   int *list, *marker;
00793   int temp, m, from, to;
00794   int *n2o_row, *o2n_col, beg_row, beg_rowP;
00795   double *AVAL, droptol;
00796   REAL_DH *work, *aval, val;
00797   Factor_dh F = ctx->F;
00798   SubdomainGraph_dh sg = ctx->sg;
00799   bool debug = false;
00800 
00801   if (logFile != NULL && Parser_dhHasSwitch (parser_dh, "-debug_ilu"))
00802     debug = true;
00803 
00804   m = F->m;
00805   rp = F->rp;
00806   cval = F->cval;
00807   diag = F->diag;
00808   aval = F->aval;
00809   work = ctx->work;
00810   from = ctx->from;
00811   to = ctx->to;
00812   count = rp[from];
00813   droptol = ctx->droptol;
00814 
00815   if (sg == NULL)
00816     {
00817       SET_V_ERROR ("subdomain graph is NULL");
00818     }
00819 
00820   n2o_row = ctx->sg->n2o_row;
00821   o2n_col = ctx->sg->o2n_col;
00822   beg_row = ctx->sg->beg_row[myid_dh];
00823   beg_rowP = ctx->sg->beg_rowP[myid_dh];
00824 
00825 
00826   /* allocate and initialize working space */
00827   list = (int *) MALLOC_DH ((m + 1) * sizeof (int));
00828   CHECK_V_ERROR;
00829   marker = (int *) MALLOC_DH (m * sizeof (int));
00830   CHECK_V_ERROR;
00831   for (i = 0; i < m; ++i)
00832     marker[i] = -1;
00833   rp[0] = 0;
00834 
00835   /* working space for values */
00836   for (i = 0; i < m; ++i)
00837     work[i] = 0.0;
00838 
00839   /* ----- main loop start ----- */
00840   for (i = from; i < to; ++i)
00841     {
00842       int row = n2o_row[i]; /* local row number */
00843       int globalRow = row + beg_row;    /* global row number */
00844       EuclidGetRow (ctx->A, globalRow, &len, &CVAL, &AVAL);
00845       CHECK_V_ERROR;
00846 
00847       /* compute scaling value for row(i) */
00848       compute_scaling_private (i, len, AVAL, ctx);
00849       CHECK_V_ERROR;
00850 
00851       /* compute factor for row i */
00852       count = ilut_row_private (i, list, o2n_col, marker,
00853                 len, CVAL, AVAL, work, ctx, debug);
00854       CHECK_V_ERROR;
00855 
00856       EuclidRestoreRow (ctx->A, globalRow, &len, &CVAL, &AVAL);
00857       CHECK_V_ERROR;
00858 
00859       /* Ensure adequate storage; reallocate, if necessary. */
00860       if (idx + count > F->alloc)
00861     {
00862       Factor_dhReallocate (F, idx, count);
00863       CHECK_V_ERROR;
00864       SET_INFO ("REALLOCATED from ilu_seq");
00865       cval = F->cval;
00866       aval = F->aval;
00867     }
00868 
00869       /* Copy factored row to permanent storage,
00870          apply 2nd drop test,
00871          and re-zero work vector
00872        */
00873       col = list[m];
00874       while (count--)
00875     {
00876       val = work[col];
00877       if (col == i || fabs (val) > droptol)
00878         {
00879           cval[idx] = col;
00880           aval[idx++] = val;
00881           work[col] = 0.0;
00882         }
00883       col = list[col];
00884     }
00885 
00886       /* add row-pointer to start of next row. */
00887       rp[i + 1] = idx;
00888 
00889       /* Insert pointer to diagonal */
00890       temp = rp[i];
00891       while (cval[temp] != i)
00892     ++temp;
00893       diag[i] = temp;
00894 
00895       /* check for zero diagonal */
00896       if (!aval[diag[i]])
00897     {
00898       sprintf (msgBuf_dh, "zero diagonal in local row %i", i + 1);
00899       SET_V_ERROR (msgBuf_dh);
00900     }
00901     }               /* --------- main loop end --------- */
00902 
00903   /* adjust column indices back to global */
00904   if (beg_rowP)
00905     {
00906       int start = rp[from];
00907       int stop = rp[to];
00908       for (i = start; i < stop; ++i)
00909     cval[i] += beg_rowP;
00910     }
00911 
00912   FREE_DH (list);
00913   FREE_DH (marker);
00914 END_FUNC_DH}
00915 
00916 
00917 #undef __FUNC__
00918 #define __FUNC__ "ilut_row_private"
00919 int
00920 ilut_row_private (int localRow, int *list, int *o2n_col, int *marker,
00921           int len, int *CVAL, double *AVAL,
00922           REAL_DH * work, Euclid_dh ctx, bool debug)
00923 {
00924   START_FUNC_DH Factor_dh F = ctx->F;
00925   int j, col, m = ctx->m, *rp = F->rp, *cval = F->cval;
00926   int tmp, *diag = F->diag;
00927   int head;
00928   int count = 0, beg_row;
00929   double val;
00930   double mult, *aval = F->aval;
00931   double scale, pv, pc;
00932   double droptol = ctx->droptol;
00933   double thresh = ctx->sparseTolA;
00934 
00935   scale = ctx->scale[localRow];
00936   ctx->stats[NZA_STATS] += (double) len;
00937   beg_row = ctx->sg->beg_row[myid_dh];
00938 
00939 
00940   /* Insert col indices in linked list, and values in work vector.
00941    * List[m] points to the first (smallest) col in the linked list.
00942    * Column values are adjusted from global to local numbering.
00943    */
00944   list[m] = m;
00945   for (j = 0; j < len; ++j)
00946     {
00947       tmp = m;
00948       col = *CVAL++;
00949       col -= beg_row;       /* adjust to zero based */
00950       col = o2n_col[col];   /* permute the column */
00951       val = *AVAL++;
00952       val *= scale;     /* scale the value */
00953 
00954       if (fabs (val) > thresh || col == localRow)
00955     {           /* sparsification */
00956       ++count;
00957       while (col > list[tmp])
00958         tmp = list[tmp];
00959       list[col] = list[tmp];
00960       list[tmp] = col;
00961       work[col] = val;
00962       marker[col] = localRow;
00963     }
00964     }
00965 
00966   /* insert diag if not already present */
00967   if (marker[localRow] != localRow)
00968     {
00969       tmp = m;
00970       while (localRow > list[tmp])
00971     tmp = list[tmp];
00972       list[localRow] = list[tmp];
00973       list[tmp] = localRow;
00974       marker[localRow] = localRow;
00975       ++count;
00976     }
00977 
00978   /* update current row from previously factored rows */
00979   head = m;
00980   while (list[head] < localRow)
00981     {
00982       int row = list[head];
00983 
00984       /* get the multiplier, and apply 1st drop tolerance test */
00985       pc = work[row];
00986       if (pc != 0.0)
00987     {
00988       pv = aval[diag[row]]; /* diagonal (pivot) of previously factored row */
00989       mult = pc / pv;
00990 
00991       /* update localRow from previously factored "row" */
00992       if (fabs (mult) > droptol)
00993         {
00994           work[row] = mult;
00995 
00996           for (j = diag[row] + 1; j < rp[row + 1]; ++j)
00997         {
00998           col = cval[j];
00999           work[col] -= (mult * aval[j]);
01000 
01001           /* if col isn't already present in the linked-list, insert it.  */
01002           if (marker[col] < localRow)
01003             {
01004               marker[col] = localRow;   /* mark the column as known fill */
01005               tmp = head;   /* insert in list [this and next 3 lines] */
01006               while (col > list[tmp])
01007             tmp = list[tmp];
01008               list[col] = list[tmp];
01009               list[tmp] = col;
01010               ++count;  /* increment fill count */
01011             }
01012         }
01013         }
01014     }
01015       head = list[head];    /* advance to next item in linked list */
01016     }
01017 
01018 END_FUNC_VAL (count)}
01019 
01020 
01021 #undef __FUNC__
01022 #define __FUNC__ "check_constraint_private"
01023 bool
01024 check_constraint_private (Euclid_dh ctx, int p1, int j)
01025 {
01026   START_FUNC_DH bool retval = false;
01027   int i, p2;
01028   int *nabors, count;
01029   SubdomainGraph_dh sg = ctx->sg;
01030 
01031   if (sg == NULL)
01032     {
01033       SET_ERROR (-1, "ctx->sg == NULL");
01034     }
01035 
01036   p2 = SubdomainGraph_dhFindOwner (ctx->sg, j, true);
01037 
01038 
01039   nabors = sg->adj + sg->ptrs[p1];
01040   count = sg->ptrs[p1 + 1] - sg->ptrs[p1];
01041 
01042 /*
01043 printf("p1= %i, p2= %i;  p1's nabors: ", p1, p2);
01044 for (i=0; i<count; ++i) printf("%i ", nabors[i]);
01045 printf("\n");
01046 */
01047 
01048   for (i = 0; i < count; ++i)
01049     {
01050 /* printf("  @@@ next nabor= %i\n", nabors[i]);
01051 */
01052       if (nabors[i] == p2)
01053     {
01054       retval = true;
01055       break;
01056     }
01057     }
01058 
01059 END_FUNC_VAL (retval)}
 All Classes Files Functions Variables Enumerations Friends