IFPACK  Development
 All Classes Files Functions Variables Enumerations Friends
Mat_dh.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 #include "Mat_dh.h"
00044 #include "getRow_dh.h"
00045 #include "SubdomainGraph_dh.h"
00046 #include "TimeLog_dh.h"
00047 #include "Mem_dh.h"
00048 #include "Numbering_dh.h"
00049 #include "Parser_dh.h"
00050 #include "mat_dh_private.h"
00051 #include "io_dh.h"
00052 #include "Hash_i_dh.h"
00053 
00054 static void setup_matvec_sends_private (Mat_dh mat, int *inlist);
00055 static void setup_matvec_receives_private (Mat_dh mat, int *beg_rows,
00056                        int *end_rows, int reqlen,
00057                        int *reqind, int *outlist);
00058 
00059 #if 0
00060 
00061 partial (?)
00062      implementation below;
00063      not used anyplace, I think;
00064 for future
00065      expansion ?[mar 21, 2 K + 1]
00066        static void Mat_dhAllocate_getRow_private (Mat_dh A);
00067 #endif
00068 
00069      static bool commsOnly = false; /* experimental, for matvec functions */
00070 
00071 #undef __FUNC__
00072 #define __FUNC__ "Mat_dhCreate"
00073      void Mat_dhCreate (Mat_dh * mat)
00074 {
00075   START_FUNC_DH
00076     struct _mat_dh *tmp =
00077     (struct _mat_dh *) MALLOC_DH (sizeof (struct _mat_dh));
00078   CHECK_V_ERROR;
00079   *mat = tmp;
00080 
00081   commsOnly = Parser_dhHasSwitch (parser_dh, "-commsOnly");
00082   if (myid_dh == 0 && commsOnly == true)
00083     {
00084 /*     printf("\n@@@ commsOnly == true for matvecs! @@@\n"); */
00085       fflush (stdout);
00086     }
00087 
00088   tmp->m = 0;
00089   tmp->n = 0;
00090   tmp->beg_row = 0;
00091   tmp->bs = 1;
00092 
00093   tmp->rp = NULL;
00094   tmp->len = NULL;
00095   tmp->cval = NULL;
00096   tmp->aval = NULL;
00097   tmp->diag = NULL;
00098   tmp->fill = NULL;
00099   tmp->owner = true;
00100 
00101   tmp->len_private = 0;
00102   tmp->rowCheckedOut = -1;
00103   tmp->cval_private = NULL;
00104   tmp->aval_private = NULL;
00105 
00106   tmp->row_perm = NULL;
00107 
00108   tmp->num_recv = 0;
00109   tmp->num_send = 0;
00110   tmp->recv_req = NULL;
00111   tmp->send_req = NULL;
00112   tmp->status = NULL;
00113   tmp->recvbuf = NULL;
00114   tmp->sendbuf = NULL;
00115   tmp->sendind = NULL;
00116   tmp->sendlen = 0;
00117   tmp->recvlen = 0;
00118   tmp->numb = NULL;
00119   tmp->matvecIsSetup = false;
00120 
00121   Mat_dhZeroTiming (tmp);
00122   CHECK_V_ERROR;
00123   tmp->matvec_timing = true;
00124 
00125   tmp->debug = Parser_dhHasSwitch (parser_dh, "-debug_Mat");
00126 END_FUNC_DH}
00127 
00128 #undef __FUNC__
00129 #define __FUNC__ "Mat_dhDestroy"
00130 void
00131 Mat_dhDestroy (Mat_dh mat)
00132 {
00133   START_FUNC_DH int i;
00134 
00135   if (mat->owner)
00136     {
00137       if (mat->rp != NULL)
00138     {
00139       FREE_DH (mat->rp);
00140       CHECK_V_ERROR;
00141     }
00142       if (mat->len != NULL)
00143     {
00144       FREE_DH (mat->len);
00145       CHECK_V_ERROR;
00146     }
00147       if (mat->cval != NULL)
00148     {
00149       FREE_DH (mat->cval);
00150       CHECK_V_ERROR;
00151     }
00152       if (mat->aval != NULL)
00153     {
00154       FREE_DH (mat->aval);
00155       CHECK_V_ERROR;
00156     }
00157       if (mat->diag != NULL)
00158     {
00159       FREE_DH (mat->diag);
00160       CHECK_V_ERROR;
00161     }
00162       if (mat->fill != NULL)
00163     {
00164       FREE_DH (mat->fill);
00165       CHECK_V_ERROR;
00166     }
00167       if (mat->cval_private != NULL)
00168     {
00169       FREE_DH (mat->cval_private);
00170       CHECK_V_ERROR;
00171     }
00172       if (mat->aval_private != NULL)
00173     {
00174       FREE_DH (mat->aval_private);
00175       CHECK_V_ERROR;
00176     }
00177       if (mat->row_perm != NULL)
00178     {
00179       FREE_DH (mat->row_perm);
00180       CHECK_V_ERROR;
00181     }
00182     }
00183 
00184   for (i = 0; i < mat->num_recv; i++)
00185     MPI_Request_free (&mat->recv_req[i]);
00186   for (i = 0; i < mat->num_send; i++)
00187     MPI_Request_free (&mat->send_req[i]);
00188   if (mat->recv_req != NULL)
00189     {
00190       FREE_DH (mat->recv_req);
00191       CHECK_V_ERROR;
00192     }
00193   if (mat->send_req != NULL)
00194     {
00195       FREE_DH (mat->send_req);
00196       CHECK_V_ERROR;
00197     }
00198   if (mat->status != NULL)
00199     {
00200       FREE_DH (mat->status);
00201       CHECK_V_ERROR;
00202     }
00203   if (mat->recvbuf != NULL)
00204     {
00205       FREE_DH (mat->recvbuf);
00206       CHECK_V_ERROR;
00207     }
00208   if (mat->sendbuf != NULL)
00209     {
00210       FREE_DH (mat->sendbuf);
00211       CHECK_V_ERROR;
00212     }
00213   if (mat->sendind != NULL)
00214     {
00215       FREE_DH (mat->sendind);
00216       CHECK_V_ERROR;
00217     }
00218 
00219   if (mat->matvecIsSetup)
00220     {
00221       Mat_dhMatVecSetdown (mat);
00222       CHECK_V_ERROR;
00223     }
00224   if (mat->numb != NULL)
00225     {
00226       Numbering_dhDestroy (mat->numb);
00227       CHECK_V_ERROR;
00228     }
00229   FREE_DH (mat);
00230   CHECK_V_ERROR;
00231 END_FUNC_DH}
00232 
00233 
00234 /* this should put the cval array back the way it was! */
00235 #undef __FUNC__
00236 #define __FUNC__ "Mat_dhMatVecSetDown"
00237 void
00238 Mat_dhMatVecSetdown (Mat_dh mat)
00239 {
00240   START_FUNC_DH if (ignoreMe)
00241     SET_V_ERROR ("not implemented");
00242 END_FUNC_DH}
00243 
00244 
00245 /* adopted from Edmond Chow's ParaSails */
00246 #undef __FUNC__
00247 #define __FUNC__ "Mat_dhMatVecSetup"
00248 void
00249 Mat_dhMatVecSetup (Mat_dh mat)
00250 {
00251   START_FUNC_DH if (np_dh == 1)
00252     {
00253       goto DO_NOTHING;
00254     }
00255 
00256   else
00257     {
00258       int *outlist, *inlist;
00259       int ierr, i, row, *rp = mat->rp, *cval = mat->cval;
00260       Numbering_dh numb;
00261       int m = mat->m;
00262       int firstLocal = mat->beg_row;
00263       int lastLocal = firstLocal + m;
00264       int *beg_rows, *end_rows;
00265 
00266       mat->recv_req =
00267     (MPI_Request *) MALLOC_DH (np_dh * sizeof (MPI_Request));
00268       CHECK_V_ERROR;
00269       mat->send_req =
00270     (MPI_Request *) MALLOC_DH (np_dh * sizeof (MPI_Request));
00271       CHECK_V_ERROR;
00272       mat->status = (MPI_Status *) MALLOC_DH (np_dh * sizeof (MPI_Status));
00273       CHECK_V_ERROR;
00274       beg_rows = (int *) MALLOC_DH (np_dh * sizeof (int));
00275       CHECK_V_ERROR;
00276       end_rows = (int *) MALLOC_DH (np_dh * sizeof (int));
00277       CHECK_V_ERROR;
00278 
00279       if (np_dh == 1)
00280     {           /* this is for debugging purposes in some of the drivers */
00281       beg_rows[0] = 0;
00282       end_rows[0] = m;
00283     }
00284       else
00285     {
00286       ierr =
00287         MPI_Allgather (&firstLocal, 1, MPI_INT, beg_rows, 1, MPI_INT,
00288                comm_dh);
00289 
00290       CHECK_MPI_V_ERROR (ierr);
00291 
00292       ierr =
00293         MPI_Allgather (&lastLocal, 1, MPI_INT, end_rows, 1, MPI_INT,
00294                comm_dh);
00295       CHECK_MPI_V_ERROR (ierr);
00296     }
00297 
00298       outlist = (int *) MALLOC_DH (np_dh * sizeof (int));
00299       CHECK_V_ERROR;
00300       inlist = (int *) MALLOC_DH (np_dh * sizeof (int));
00301       CHECK_V_ERROR;
00302       for (i = 0; i < np_dh; ++i)
00303     {
00304       outlist[i] = 0;
00305       inlist[i] = 0;
00306     }
00307 
00308       /* Create Numbering object */
00309       Numbering_dhCreate (&(mat->numb));
00310       CHECK_V_ERROR;
00311       numb = mat->numb;
00312       Numbering_dhSetup (numb, mat);
00313       CHECK_V_ERROR;
00314 
00315       setup_matvec_receives_private (mat, beg_rows, end_rows, numb->num_ext,
00316                      numb->idx_ext, outlist);
00317       CHECK_V_ERROR;
00318 
00319       if (np_dh == 1)
00320     {           /* this is for debugging purposes in some of the drivers */
00321       inlist[0] = outlist[0];
00322     }
00323       else
00324     {
00325       ierr =
00326         MPI_Alltoall (outlist, 1, MPI_INT, inlist, 1, MPI_INT, comm_dh);
00327       CHECK_MPI_V_ERROR (ierr);
00328     }
00329 
00330       setup_matvec_sends_private (mat, inlist);
00331       CHECK_V_ERROR;
00332 
00333       /* Convert to local indices */
00334       for (row = 0; row < m; row++)
00335     {
00336       int len = rp[row + 1] - rp[row];
00337       int *ind = cval + rp[row];
00338       Numbering_dhGlobalToLocal (numb, len, ind, ind);
00339       CHECK_V_ERROR;
00340     }
00341 
00342       FREE_DH (outlist);
00343       CHECK_V_ERROR;
00344       FREE_DH (inlist);
00345       CHECK_V_ERROR;
00346       FREE_DH (beg_rows);
00347       CHECK_V_ERROR;
00348       FREE_DH (end_rows);
00349       CHECK_V_ERROR;
00350     }
00351 
00352 DO_NOTHING:;
00353 
00354 END_FUNC_DH}
00355 
00356 /* adopted from Edmond Chow's ParaSails */
00357 #undef __FUNC__
00358 #define __FUNC__ "setup_matvec_receives_private"
00359 void
00360 setup_matvec_receives_private (Mat_dh mat, int *beg_rows, int *end_rows,
00361                    int reqlen, int *reqind, int *outlist)
00362 {
00363   START_FUNC_DH int ierr, i, j, this_pe;
00364   MPI_Request request;
00365   int m = mat->m;
00366 
00367   mat->num_recv = 0;
00368 
00369   /* Allocate recvbuf */
00370   /* recvbuf has numlocal entries saved for local part of x, used in matvec */
00371   mat->recvbuf = (double *) MALLOC_DH ((reqlen + m) * sizeof (double));
00372 
00373   for (i = 0; i < reqlen; i = j)
00374     {               /* j is set below */
00375       /* The processor that owns the row with index reqind[i] */
00376       this_pe = mat_find_owner (beg_rows, end_rows, reqind[i]);
00377       CHECK_V_ERROR;
00378 
00379       /* Figure out other rows we need from this_pe */
00380       for (j = i + 1; j < reqlen; j++)
00381     {
00382       /* if row is on different pe */
00383       if (reqind[j] < beg_rows[this_pe] || reqind[j] > end_rows[this_pe])
00384         break;
00385     }
00386 
00387       /* Request rows in reqind[i..j-1] */
00388       ierr =
00389     MPI_Isend (&reqind[i], j - i, MPI_INT, this_pe, 444, comm_dh,
00390            &request);
00391       CHECK_MPI_V_ERROR (ierr);
00392       ierr = MPI_Request_free (&request);
00393       CHECK_MPI_V_ERROR (ierr);
00394 
00395       /* Count of number of number of indices needed from this_pe */
00396       outlist[this_pe] = j - i;
00397 
00398       ierr =
00399     MPI_Recv_init (&mat->recvbuf[i + m], j - i, MPI_DOUBLE, this_pe, 555,
00400                comm_dh, &mat->recv_req[mat->num_recv]);
00401       CHECK_MPI_V_ERROR (ierr);
00402 
00403       mat->num_recv++;
00404       mat->recvlen += j - i;    /* only used for statistical reporting */
00405     }
00406 END_FUNC_DH}
00407 
00408 
00409 /* adopted from Edmond Chow's ParaSails */
00410 #undef __FUNC__
00411 #define __FUNC__ "setup_matvec_sends_private"
00412 void
00413 setup_matvec_sends_private (Mat_dh mat, int *inlist)
00414 {
00415   START_FUNC_DH int ierr, i, j, sendlen, first = mat->beg_row;
00416   MPI_Request *requests;
00417   MPI_Status *statuses;
00418 
00419   requests = (MPI_Request *) MALLOC_DH (np_dh * sizeof (MPI_Request));
00420   CHECK_V_ERROR;
00421   statuses = (MPI_Status *) MALLOC_DH (np_dh * sizeof (MPI_Status));
00422   CHECK_V_ERROR;
00423 
00424   /* Determine size of and allocate sendbuf and sendind */
00425   sendlen = 0;
00426   for (i = 0; i < np_dh; i++)
00427     sendlen += inlist[i];
00428   mat->sendlen = sendlen;
00429   mat->sendbuf = (double *) MALLOC_DH (sendlen * sizeof (double));
00430   CHECK_V_ERROR;
00431   mat->sendind = (int *) MALLOC_DH (sendlen * sizeof (int));
00432   CHECK_V_ERROR;
00433 
00434   j = 0;
00435   mat->num_send = 0;
00436   for (i = 0; i < np_dh; i++)
00437     {
00438       if (inlist[i] != 0)
00439     {
00440       /* Post receive for the actual indices */
00441       ierr =
00442         MPI_Irecv (&mat->sendind[j], inlist[i], MPI_INT, i, 444, comm_dh,
00443                &requests[mat->num_send]);
00444       CHECK_MPI_V_ERROR (ierr);
00445       /* Set up the send */
00446       ierr =
00447         MPI_Send_init (&mat->sendbuf[j], inlist[i], MPI_DOUBLE, i, 555,
00448                comm_dh, &mat->send_req[mat->num_send]);
00449       CHECK_MPI_V_ERROR (ierr);
00450 
00451       mat->num_send++;
00452       j += inlist[i];
00453     }
00454     }
00455 
00456   /* total bytes to be sent during matvec */
00457   mat->time[MATVEC_WORDS] = j;
00458 
00459 
00460   ierr = MPI_Waitall (mat->num_send, requests, statuses);
00461   CHECK_MPI_V_ERROR (ierr);
00462   /* convert global indices to local indices */
00463   /* these are all indices on this processor */
00464   for (i = 0; i < mat->sendlen; i++)
00465     mat->sendind[i] -= first;
00466 
00467   FREE_DH (requests);
00468   FREE_DH (statuses);
00469 END_FUNC_DH}
00470 
00471 
00472 /* unthreaded MPI version */
00473 #undef __FUNC__
00474 #define __FUNC__ "Mat_dhMatVec"
00475 void
00476 Mat_dhMatVec (Mat_dh mat, double *x, double *b)
00477 {
00478   START_FUNC_DH if (np_dh == 1)
00479     {
00480       Mat_dhMatVec_uni (mat, x, b);
00481       CHECK_V_ERROR;
00482     }
00483 
00484   else
00485     {
00486       int ierr, i, row, m = mat->m;
00487       int *rp = mat->rp, *cval = mat->cval;
00488       double *aval = mat->aval;
00489       int *sendind = mat->sendind;
00490       int sendlen = mat->sendlen;
00491       double *sendbuf = mat->sendbuf;
00492       double *recvbuf = mat->recvbuf;
00493       double t1 = 0, t2 = 0, t3 = 0, t4 = 0;
00494       bool timeFlag = mat->matvec_timing;
00495 
00496 
00497       if (timeFlag)
00498     t1 = MPI_Wtime ();
00499 
00500       /* Put components of x into the right outgoing buffers */
00501       if (!commsOnly)
00502     {
00503       for (i = 0; i < sendlen; i++)
00504         sendbuf[i] = x[sendind[i]];
00505     }
00506 
00507       if (timeFlag)
00508     {
00509       t2 = MPI_Wtime ();
00510       mat->time[MATVEC_TIME] += (t2 - t1);
00511 
00512     }
00513 
00514       ierr = MPI_Startall (mat->num_recv, mat->recv_req);
00515       CHECK_MPI_V_ERROR (ierr);
00516       ierr = MPI_Startall (mat->num_send, mat->send_req);
00517       CHECK_MPI_V_ERROR (ierr);
00518       ierr = MPI_Waitall (mat->num_recv, mat->recv_req, mat->status);
00519       CHECK_MPI_V_ERROR (ierr);
00520       ierr = MPI_Waitall (mat->num_send, mat->send_req, mat->status);
00521       CHECK_MPI_V_ERROR (ierr);
00522 
00523 
00524       if (timeFlag)
00525     {
00526       t3 = MPI_Wtime ();
00527       mat->time[MATVEC_MPI_TIME] += (t3 - t2);
00528     }
00529 
00530       /* Copy local part of x into top part of recvbuf */
00531       if (!commsOnly)
00532     {
00533       for (i = 0; i < m; i++)
00534         recvbuf[i] = x[i];
00535 
00536       /* do the multiply */
00537       for (row = 0; row < m; row++)
00538         {
00539           int len = rp[row + 1] - rp[row];
00540           int *ind = cval + rp[row];
00541           double *val = aval + rp[row];
00542           double temp = 0.0;
00543           for (i = 0; i < len; i++)
00544         {
00545           temp += (val[i] * recvbuf[ind[i]]);
00546         }
00547           b[row] = temp;
00548         }
00549     }           /* if (! commsOnly) */
00550 
00551       if (timeFlag)
00552     {
00553       t4 = MPI_Wtime ();
00554       mat->time[MATVEC_TOTAL_TIME] += (t4 - t1);
00555       mat->time[MATVEC_TIME] += (t4 - t3);
00556     }
00557     }
00558 END_FUNC_DH}
00559 
00560 /* OpenMP/MPI version */
00561 #undef __FUNC__
00562 #define __FUNC__ "Mat_dhMatVec_omp"
00563 void
00564 Mat_dhMatVec_omp (Mat_dh mat, double *x, double *b)
00565 {
00566   START_FUNC_DH int ierr, i, row, m = mat->m;
00567   int *rp = mat->rp, *cval = mat->cval;
00568   double *aval = mat->aval;
00569   int *sendind = mat->sendind;
00570   int sendlen = mat->sendlen;
00571   double *sendbuf = mat->sendbuf;
00572   double *recvbuf = mat->recvbuf;
00573   double t1 = 0, t2 = 0, t3 = 0, t4 = 0, tx = 0;
00574   double *val, temp;
00575   int len, *ind;
00576   bool timeFlag = mat->matvec_timing;
00577 
00578   if (timeFlag)
00579     t1 = MPI_Wtime ();
00580 
00581   /* Put components of x into the right outgoing buffers */
00582   for (i = 0; i < sendlen; i++)
00583     sendbuf[i] = x[sendind[i]];
00584 
00585   if (timeFlag)
00586     {
00587       t2 = MPI_Wtime ();
00588       mat->time[MATVEC_TIME] += (t2 - t1);
00589     }
00590 
00591   ierr = MPI_Startall (mat->num_recv, mat->recv_req);
00592   CHECK_MPI_V_ERROR (ierr);
00593   ierr = MPI_Startall (mat->num_send, mat->send_req);
00594   CHECK_MPI_V_ERROR (ierr);
00595   ierr = MPI_Waitall (mat->num_recv, mat->recv_req, mat->status);
00596   CHECK_MPI_V_ERROR (ierr);
00597   ierr = MPI_Waitall (mat->num_send, mat->send_req, mat->status);
00598   CHECK_MPI_V_ERROR (ierr);
00599 
00600   if (timeFlag)
00601     {
00602       t3 = MPI_Wtime ();
00603       mat->time[MATVEC_MPI_TIME] += (t3 - t2);
00604     }
00605 
00606   /* Copy local part of x into top part of recvbuf */
00607   for (i = 0; i < m; i++)
00608     recvbuf[i] = x[i];
00609 
00610   if (timeFlag)
00611     {
00612       tx = MPI_Wtime ();
00613       mat->time[MATVEC_MPI_TIME2] += (tx - t1);
00614     }
00615 
00616 
00617   /* do the multiply */
00618   for (row = 0; row < m; row++)
00619     {
00620       len = rp[row + 1] - rp[row];
00621       ind = cval + rp[row];
00622       val = aval + rp[row];
00623       temp = 0.0;
00624       for (i = 0; i < len; i++)
00625     {
00626       temp += (val[i] * recvbuf[ind[i]]);
00627     }
00628       b[row] = temp;
00629     }
00630 
00631   if (timeFlag)
00632     {
00633       t4 = MPI_Wtime ();
00634       mat->time[MATVEC_TOTAL_TIME] += (t4 - t1);
00635       mat->time[MATVEC_TIME] += (t4 - t3);
00636     }
00637 
00638 END_FUNC_DH}
00639 
00640 
00641 /* OpenMP/single primary task version */
00642 #undef __FUNC__
00643 #define __FUNC__ "Mat_dhMatVec_uni_omp"
00644 void
00645 Mat_dhMatVec_uni_omp (Mat_dh mat, double *x, double *b)
00646 {
00647   START_FUNC_DH int i, row, m = mat->m;
00648   int *rp = mat->rp, *cval = mat->cval;
00649   double *aval = mat->aval;
00650   double t1 = 0, t2 = 0;
00651   bool timeFlag = mat->matvec_timing;
00652 
00653   if (timeFlag)
00654     {
00655       t1 = MPI_Wtime ();
00656     }
00657 
00658   /* do the multiply */
00659   for (row = 0; row < m; row++)
00660     {
00661       int len = rp[row + 1] - rp[row];
00662       int *ind = cval + rp[row];
00663       double *val = aval + rp[row];
00664       double temp = 0.0;
00665       for (i = 0; i < len; i++)
00666     {
00667       temp += (val[i] * x[ind[i]]);
00668     }
00669       b[row] = temp;
00670     }
00671 
00672   if (timeFlag)
00673     {
00674       t2 = MPI_Wtime ();
00675       mat->time[MATVEC_TIME] += (t2 - t1);
00676       mat->time[MATVEC_TOTAL_TIME] += (t2 - t1);
00677     }
00678 
00679 END_FUNC_DH}
00680 
00681 
00682 /* unthreaded, single-task version */
00683 #undef __FUNC__
00684 #define __FUNC__ "Mat_dhMatVec_uni"
00685 void
00686 Mat_dhMatVec_uni (Mat_dh mat, double *x, double *b)
00687 {
00688   START_FUNC_DH int i, row, m = mat->m;
00689   int *rp = mat->rp, *cval = mat->cval;
00690   double *aval = mat->aval;
00691   double t1 = 0, t2 = 0;
00692   bool timeFlag = mat->matvec_timing;
00693 
00694   if (timeFlag)
00695     t1 = MPI_Wtime ();
00696 
00697   for (row = 0; row < m; row++)
00698     {
00699       int len = rp[row + 1] - rp[row];
00700       int *ind = cval + rp[row];
00701       double *val = aval + rp[row];
00702       double temp = 0.0;
00703       for (i = 0; i < len; i++)
00704     {
00705       temp += (val[i] * x[ind[i]]);
00706     }
00707       b[row] = temp;
00708     }
00709 
00710   if (timeFlag)
00711     {
00712       t2 = MPI_Wtime ();
00713       mat->time[MATVEC_TIME] += (t2 - t1);
00714       mat->time[MATVEC_TOTAL_TIME] += (t2 - t1);
00715     }
00716 
00717 END_FUNC_DH}
00718 
00719 
00720 #undef __FUNC__
00721 #define __FUNC__ "Mat_dhReadNz"
00722 int
00723 Mat_dhReadNz (Mat_dh mat)
00724 {
00725   START_FUNC_DH int ierr, retval = mat->rp[mat->m];
00726   int nz = retval;
00727   ierr = MPI_Allreduce (&nz, &retval, 1, MPI_INT, MPI_SUM, comm_dh);
00728   CHECK_MPI_ERROR (ierr);
00729 END_FUNC_VAL (retval)}
00730 
00731 
00732 
00733 #if 0
00734 
00735 #undef __FUNC__
00736 #define __FUNC__ "Mat_dhAllocate_getRow_private"
00737 void
00738 Mat_dhAllocate_getRow_private (Mat_dh A)
00739 {
00740   START_FUNC_DH int i, *rp = A->rp, len = 0;
00741   int m = A->m;
00742 
00743   /* find longest row in matrix */
00744   for (i = 0; i < m; ++i)
00745     len = MAX (len, rp[i + 1] - rp[i]);
00746   len *= A->bs;
00747 
00748   /* free any previously allocated private storage */
00749   if (len > A->len_private)
00750     {
00751       if (A->cval_private != NULL)
00752     {
00753       FREE_DH (A->cval_private);
00754       CHECK_V_ERROR;
00755     }
00756       if (A->aval_private != NULL)
00757     {
00758       FREE_DH (A->aval_private);
00759       CHECK_V_ERROR;
00760     }
00761     }
00762 
00763   /* allocate private storage */
00764   A->cval_private = (int *) MALLOC_DH (len * sizeof (int));
00765   CHECK_V_ERROR;
00766   A->aval_private = (double *) MALLOC_DH (len * sizeof (double));
00767   CHECK_V_ERROR;
00768   A->len_private = len;
00769 END_FUNC_DH}
00770 
00771 #endif
00772 
00773 #undef __FUNC__
00774 #define __FUNC__ "Mat_dhZeroTiming"
00775 void
00776 Mat_dhZeroTiming (Mat_dh mat)
00777 {
00778   START_FUNC_DH int i;
00779 
00780   for (i = 0; i < MAT_DH_BINS; ++i)
00781     {
00782       mat->time[i] = 0;
00783       mat->time_max[i] = 0;
00784       mat->time_min[i] = 0;
00785     }
00786 END_FUNC_DH}
00787 
00788 #undef __FUNC__
00789 #define __FUNC__ "Mat_dhReduceTiming"
00790 void
00791 Mat_dhReduceTiming (Mat_dh mat)
00792 {
00793   START_FUNC_DH if (mat->time[MATVEC_MPI_TIME])
00794     {
00795       mat->time[MATVEC_RATIO] =
00796     mat->time[MATVEC_TIME] / mat->time[MATVEC_MPI_TIME];
00797     }
00798   MPI_Allreduce (mat->time, mat->time_min, MAT_DH_BINS, MPI_DOUBLE, MPI_MIN,
00799          comm_dh);
00800   MPI_Allreduce (mat->time, mat->time_max, MAT_DH_BINS, MPI_DOUBLE, MPI_MAX,
00801          comm_dh);
00802 END_FUNC_DH}
00803 
00804 #undef __FUNC__
00805 #define __FUNC__ "Mat_dhPermute"
00806 void
00807 Mat_dhPermute (Mat_dh A, int *n2o, Mat_dh * Bout)
00808 {
00809   START_FUNC_DH Mat_dh B;
00810   int i, j, *RP = A->rp, *CVAL = A->cval;
00811   int *o2n, *rp, *cval, m = A->m, nz = RP[m];
00812   double *aval, *AVAL = A->aval;
00813 
00814   Mat_dhCreate (&B);
00815   CHECK_V_ERROR;
00816   B->m = B->n = m;
00817   *Bout = B;
00818 
00819   /* form inverse permutation */
00820   o2n = (int *) MALLOC_DH (m * sizeof (int));
00821   CHECK_V_ERROR;
00822   for (i = 0; i < m; ++i)
00823     o2n[n2o[i]] = i;
00824 
00825   /* allocate storage for permuted matrix */
00826   rp = B->rp = (int *) MALLOC_DH ((m + 1) * sizeof (int));
00827   CHECK_V_ERROR;
00828   cval = B->cval = (int *) MALLOC_DH (nz * sizeof (int));
00829   CHECK_V_ERROR;
00830   aval = B->aval = (double *) MALLOC_DH (nz * sizeof (double));
00831   CHECK_V_ERROR;
00832 
00833   /* form new rp array */
00834   rp[0] = 0;
00835   for (i = 0; i < m; ++i)
00836     {
00837       int oldRow = n2o[i];
00838       rp[i + 1] = RP[oldRow + 1] - RP[oldRow];
00839     }
00840   for (i = 1; i <= m; ++i)
00841     rp[i] = rp[i] + rp[i - 1];
00842 
00843   for (i = 0; i < m; ++i)
00844     {
00845       int oldRow = n2o[i];
00846       int idx = rp[i];
00847       for (j = RP[oldRow]; j < RP[oldRow + 1]; ++j)
00848     {
00849       cval[idx] = o2n[CVAL[j]];
00850       aval[idx] = AVAL[j];
00851       ++idx;
00852     }
00853     }
00854 
00855   FREE_DH (o2n);
00856   CHECK_V_ERROR;
00857 END_FUNC_DH}
00858 
00859 
00860 /*----------------------------------------------------------------------
00861  * Print methods
00862  *----------------------------------------------------------------------*/
00863 
00864 /* seq or mpi */
00865 #undef __FUNC__
00866 #define __FUNC__ "Mat_dhPrintGraph"
00867 void
00868 Mat_dhPrintGraph (Mat_dh A, SubdomainGraph_dh sg, FILE * fp)
00869 {
00870   START_FUNC_DH int pe, id = myid_dh;
00871   int ierr;
00872 
00873   if (sg != NULL)
00874     {
00875       id = sg->o2n_sub[id];
00876     }
00877 
00878   for (pe = 0; pe < np_dh; ++pe)
00879     {
00880       ierr = MPI_Barrier (comm_dh);
00881       CHECK_MPI_V_ERROR (ierr);
00882       if (id == pe)
00883     {
00884       if (sg == NULL)
00885         {
00886           mat_dh_print_graph_private (A->m, A->beg_row, A->rp, A->cval,
00887                       A->aval, NULL, NULL, NULL, fp);
00888           CHECK_V_ERROR;
00889         }
00890       else
00891         {
00892           int beg_row = sg->beg_rowP[myid_dh];
00893           mat_dh_print_graph_private (A->m, beg_row, A->rp, A->cval,
00894                       A->aval, sg->n2o_row, sg->o2n_col,
00895                       sg->o2n_ext, fp);
00896           CHECK_V_ERROR;
00897         }
00898     }
00899     }
00900 END_FUNC_DH}
00901 
00902 
00903 #undef __FUNC__
00904 #define __FUNC__ "Mat_dhPrintRows"
00905 void
00906 Mat_dhPrintRows (Mat_dh A, SubdomainGraph_dh sg, FILE * fp)
00907 {
00908   START_FUNC_DH bool noValues;
00909   int m = A->m, *rp = A->rp, *cval = A->cval;
00910   double *aval = A->aval;
00911 
00912   noValues = (Parser_dhHasSwitch (parser_dh, "-noValues"));
00913   if (noValues)
00914     aval = NULL;
00915 
00916   /*---------------------------------------------------------------- 
00917    * case 1: print local portion of unpermuted matrix
00918    *----------------------------------------------------------------*/
00919   if (sg == NULL)
00920     {
00921       int i, j;
00922       int beg_row = A->beg_row;
00923 
00924       fprintf (fp,
00925            "\n----- A, unpermuted ------------------------------------\n");
00926       for (i = 0; i < m; ++i)
00927     {
00928       fprintf (fp, "%i :: ", 1 + i + beg_row);
00929       for (j = rp[i]; j < rp[i + 1]; ++j)
00930         {
00931           if (noValues)
00932         {
00933           fprintf (fp, "%i ", 1 + cval[j]);
00934         }
00935           else
00936         {
00937           fprintf (fp, "%i,%g ; ", 1 + cval[j], aval[j]);
00938         }
00939         }
00940       fprintf (fp, "\n");
00941     }
00942     }
00943 
00944   /*---------------------------------------------------------------- 
00945    * case 2: single mpi task, with multiple subdomains
00946    *----------------------------------------------------------------*/
00947   else if (np_dh == 1)
00948     {
00949       int i, k, idx = 1;
00950       int oldRow;
00951 
00952       for (i = 0; i < sg->blocks; ++i)
00953     {
00954       int oldBlock = sg->n2o_sub[i];
00955 
00956       /* here, 'beg_row' and 'end_row' refer to rows in the
00957          original ordering of A.
00958        */
00959       int beg_row = sg->beg_row[oldBlock];
00960       int end_row = beg_row + sg->row_count[oldBlock];
00961 
00962       fprintf (fp, "\n");
00963       fprintf (fp,
00964            "\n----- A, permuted, single mpi task  ------------------\n");
00965       fprintf (fp, "---- new subdomain: %i;  old subdomain: %i\n", i,
00966            oldBlock);
00967       fprintf (fp, "     old beg_row:   %i;  new beg_row:   %i\n",
00968            sg->beg_row[oldBlock], sg->beg_rowP[oldBlock]);
00969       fprintf (fp, "     local rows in this block: %i\n",
00970            sg->row_count[oldBlock]);
00971       fprintf (fp, "     bdry rows in this block:  %i\n",
00972            sg->bdry_count[oldBlock]);
00973       fprintf (fp, "     1st bdry row= %i \n",
00974            1 + end_row - sg->bdry_count[oldBlock]);
00975 
00976       for (oldRow = beg_row; oldRow < end_row; ++oldRow)
00977         {
00978           int len = 0, *cval;
00979           double *aval;
00980 
00981           fprintf (fp, "%3i (old= %3i) :: ", idx, 1 + oldRow);
00982           ++idx;
00983           Mat_dhGetRow (A, oldRow, &len, &cval, &aval);
00984           CHECK_V_ERROR;
00985 
00986           for (k = 0; k < len; ++k)
00987         {
00988           if (noValues)
00989             {
00990               fprintf (fp, "%i ", 1 + sg->o2n_col[cval[k]]);
00991             }
00992           else
00993             {
00994               fprintf (fp, "%i,%g ; ", 1 + sg->o2n_col[cval[k]],
00995                    aval[k]);
00996             }
00997         }
00998 
00999           fprintf (fp, "\n");
01000           Mat_dhRestoreRow (A, oldRow, &len, &cval, &aval);
01001           CHECK_V_ERROR;
01002         }
01003     }
01004     }
01005 
01006   /*---------------------------------------------------------------- 
01007    * case 3: multiple mpi tasks, one subdomain per task
01008    *----------------------------------------------------------------*/
01009   else
01010     {
01011       Hash_i_dh hash = sg->o2n_ext;
01012       int *o2n_col = sg->o2n_col, *n2o_row = sg->n2o_row;
01013       int beg_row = sg->beg_row[myid_dh];
01014       int beg_rowP = sg->beg_rowP[myid_dh];
01015       int i, j;
01016 
01017       for (i = 0; i < m; ++i)
01018     {
01019       int row = n2o_row[i];
01020       fprintf (fp, "%3i (old= %3i) :: ", 1 + i + beg_rowP,
01021            1 + row + beg_row);
01022       for (j = rp[row]; j < rp[row + 1]; ++j)
01023         {
01024           int col = cval[j];
01025 
01026           /* find permuted (old-to-new) value for the column */
01027           /* case i: column is locally owned */
01028           if (col >= beg_row && col < beg_row + m)
01029         {
01030           col = o2n_col[col - beg_row] + beg_rowP;
01031         }
01032 
01033           /* case ii: column is external */
01034           else
01035         {
01036           int tmp = col;
01037           tmp = Hash_i_dhLookup (hash, col);
01038           CHECK_V_ERROR;
01039           if (tmp == -1)
01040             {
01041               sprintf (msgBuf_dh,
01042                    "nonlocal column= %i not in hash table",
01043                    1 + col);
01044               SET_V_ERROR (msgBuf_dh);
01045             }
01046           else
01047             {
01048               col = tmp;
01049             }
01050         }
01051 
01052           if (noValues)
01053         {
01054           fprintf (fp, "%i ", 1 + col);
01055         }
01056           else
01057         {
01058           fprintf (fp, "%i,%g ; ", 1 + col, aval[j]);
01059         }
01060         }
01061       fprintf (fp, "\n");
01062     }
01063     }
01064 END_FUNC_DH}
01065 
01066 
01067 
01068 #undef __FUNC__
01069 #define __FUNC__ "Mat_dhPrintTriples"
01070 void
01071 Mat_dhPrintTriples (Mat_dh A, SubdomainGraph_dh sg, char *filename)
01072 {
01073   START_FUNC_DH int m = A->m, *rp = A->rp, *cval = A->cval;
01074   double *aval = A->aval;
01075   bool noValues;
01076   bool matlab;
01077   FILE *fp;
01078 
01079   noValues = (Parser_dhHasSwitch (parser_dh, "-noValues"));
01080   if (noValues)
01081     aval = NULL;
01082   matlab = (Parser_dhHasSwitch (parser_dh, "-matlab"));
01083 
01084   /*---------------------------------------------------------------- 
01085    * case 1: unpermuted matrix, single or multiple mpi tasks
01086    *----------------------------------------------------------------*/
01087   if (sg == NULL)
01088     {
01089       int i, j, pe;
01090       int beg_row = A->beg_row;
01091       double val;
01092 
01093       for (pe = 0; pe < np_dh; ++pe)
01094     {
01095       MPI_Barrier (comm_dh);
01096       if (pe == myid_dh)
01097         {
01098           if (pe == 0)
01099         {
01100           fp = openFile_dh (filename, "w");
01101           CHECK_V_ERROR;
01102         }
01103           else
01104         {
01105           fp = openFile_dh (filename, "a");
01106           CHECK_V_ERROR;
01107         }
01108 
01109           for (i = 0; i < m; ++i)
01110         {
01111           for (j = rp[i]; j < rp[i + 1]; ++j)
01112             {
01113               if (noValues)
01114             {
01115               fprintf (fp, "%i %i\n", 1 + i + beg_row,
01116                    1 + cval[j]);
01117             }
01118               else
01119             {
01120               val = aval[j];
01121               if (val == 0.0 && matlab)
01122                 val = _MATLAB_ZERO_;
01123               fprintf (fp, TRIPLES_FORMAT, 1 + i + beg_row,
01124                    1 + cval[j], val);
01125             }
01126             }
01127         }
01128           closeFile_dh (fp);
01129           CHECK_V_ERROR;
01130         }
01131     }
01132     }
01133 
01134   /*---------------------------------------------------------------- 
01135    * case 2: single mpi task, with multiple subdomains
01136    *----------------------------------------------------------------*/
01137   else if (np_dh == 1)
01138     {
01139       int i, j, k, idx = 1;
01140 
01141       fp = openFile_dh (filename, "w");
01142       CHECK_V_ERROR;
01143 
01144       for (i = 0; i < sg->blocks; ++i)
01145     {
01146       int oldBlock = sg->n2o_sub[i];
01147       int beg_row = sg->beg_rowP[oldBlock];
01148       int end_row = beg_row + sg->row_count[oldBlock];
01149 
01150       for (j = beg_row; j < end_row; ++j)
01151         {
01152           int len = 0, *cval;
01153           double *aval;
01154           int oldRow = sg->n2o_row[j];
01155 
01156           Mat_dhGetRow (A, oldRow, &len, &cval, &aval);
01157           CHECK_V_ERROR;
01158 
01159           if (noValues)
01160         {
01161           for (k = 0; k < len; ++k)
01162             {
01163               fprintf (fp, "%i %i\n", idx, 1 + sg->o2n_col[cval[k]]);
01164             }
01165           ++idx;
01166         }
01167 
01168           else
01169         {
01170           for (k = 0; k < len; ++k)
01171             {
01172               double val = aval[k];
01173               if (val == 0.0 && matlab)
01174             val = _MATLAB_ZERO_;
01175               fprintf (fp, TRIPLES_FORMAT, idx,
01176                    1 + sg->o2n_col[cval[k]], val);
01177             }
01178           ++idx;
01179         }
01180           Mat_dhRestoreRow (A, oldRow, &len, &cval, &aval);
01181           CHECK_V_ERROR;
01182         }
01183     }
01184     }
01185 
01186   /*---------------------------------------------------------------- 
01187    * case 3: multiple mpi tasks, one subdomain per task
01188    *----------------------------------------------------------------*/
01189   else
01190     {
01191       Hash_i_dh hash = sg->o2n_ext;
01192       int *o2n_col = sg->o2n_col, *n2o_row = sg->n2o_row;
01193       int beg_row = sg->beg_row[myid_dh];
01194       int beg_rowP = sg->beg_rowP[myid_dh];
01195       int i, j, pe;
01196       int id = sg->o2n_sub[myid_dh];
01197 
01198       for (pe = 0; pe < np_dh; ++pe)
01199     {
01200       MPI_Barrier (comm_dh);
01201       if (id == pe)
01202         {
01203           if (pe == 0)
01204         {
01205           fp = openFile_dh (filename, "w");
01206           CHECK_V_ERROR;
01207         }
01208           else
01209         {
01210           fp = openFile_dh (filename, "a");
01211           CHECK_V_ERROR;
01212         }
01213 
01214           for (i = 0; i < m; ++i)
01215         {
01216           int row = n2o_row[i];
01217           for (j = rp[row]; j < rp[row + 1]; ++j)
01218             {
01219               int col = cval[j];
01220               double val = 0.0;
01221 
01222               if (aval != NULL)
01223             val = aval[j];
01224               if (val == 0.0 && matlab)
01225             val = _MATLAB_ZERO_;
01226 
01227               /* find permuted (old-to-new) value for the column */
01228               /* case i: column is locally owned */
01229               if (col >= beg_row && col < beg_row + m)
01230             {
01231               col = o2n_col[col - beg_row] + beg_rowP;
01232             }
01233 
01234               /* case ii: column is external */
01235               else
01236             {
01237               int tmp = col;
01238               tmp = Hash_i_dhLookup (hash, col);
01239               CHECK_V_ERROR;
01240               if (tmp == -1)
01241                 {
01242                   sprintf (msgBuf_dh,
01243                        "nonlocal column= %i not in hash table",
01244                        1 + col);
01245                   SET_V_ERROR (msgBuf_dh);
01246                 }
01247               else
01248                 {
01249                   col = tmp;
01250                 }
01251             }
01252 
01253               if (noValues)
01254             {
01255               fprintf (fp, "%i %i\n", 1 + i + beg_rowP, 1 + col);
01256             }
01257               else
01258             {
01259               fprintf (fp, TRIPLES_FORMAT, 1 + i + beg_rowP,
01260                    1 + col, val);
01261             }
01262             }
01263         }
01264           closeFile_dh (fp);
01265           CHECK_V_ERROR;
01266         }
01267     }
01268     }
01269 END_FUNC_DH}
01270 
01271 
01272 /* seq only */
01273 #undef __FUNC__
01274 #define __FUNC__ "Mat_dhPrintCSR"
01275 void
01276 Mat_dhPrintCSR (Mat_dh A, SubdomainGraph_dh sg, char *filename)
01277 {
01278   START_FUNC_DH FILE * fp;
01279 
01280   if (np_dh > 1)
01281     {
01282       SET_V_ERROR ("only implemented for a single mpi task");
01283     }
01284   if (sg != NULL)
01285     {
01286       SET_V_ERROR
01287     ("not implemented for reordered matrix (SubdomainGraph_dh should be NULL)");
01288     }
01289 
01290   fp = openFile_dh (filename, "w");
01291   CHECK_V_ERROR;
01292 
01293   if (sg == NULL)
01294     {
01295       mat_dh_print_csr_private (A->m, A->rp, A->cval, A->aval, fp);
01296       CHECK_V_ERROR;
01297     }
01298   else
01299     {
01300       mat_dh_print_csr_private (A->m, A->rp, A->cval, A->aval, fp);
01301       CHECK_V_ERROR;
01302     }
01303   closeFile_dh (fp);
01304   CHECK_V_ERROR;
01305 END_FUNC_DH}
01306 
01307 /* seq */
01308 /* no reordering */
01309 #undef __FUNC__
01310 #define __FUNC__ "Mat_dhPrintBIN"
01311 void
01312 Mat_dhPrintBIN (Mat_dh A, SubdomainGraph_dh sg, char *filename)
01313 {
01314   START_FUNC_DH if (np_dh > 1)
01315     {
01316       SET_V_ERROR ("only implemented for a single MPI task");
01317     }
01318 /*  if (n2o != NULL || o2n != NULL || hash != NULL) {
01319 */
01320   if (sg != NULL)
01321     {
01322       SET_V_ERROR ("not implemented for reordering; ensure sg=NULL");
01323     }
01324 
01325   io_dh_print_ebin_mat_private (A->m, A->beg_row, A->rp, A->cval, A->aval,
01326                 NULL, NULL, NULL, filename);
01327   CHECK_V_ERROR;
01328 END_FUNC_DH}
01329 
01330 
01331 /*----------------------------------------------------------------------
01332  * Read methods
01333  *----------------------------------------------------------------------*/
01334 /* seq only */
01335 #undef __FUNC__
01336 #define __FUNC__ "Mat_dhReadCSR"
01337 void
01338 Mat_dhReadCSR (Mat_dh * mat, char *filename)
01339 {
01340   START_FUNC_DH Mat_dh A;
01341   FILE *fp;
01342 
01343   if (np_dh > 1)
01344     {
01345       SET_V_ERROR ("only implemented for a single MPI task");
01346     }
01347 
01348   fp = openFile_dh (filename, "r");
01349   CHECK_V_ERROR;
01350 
01351   Mat_dhCreate (&A);
01352   CHECK_V_ERROR;
01353   mat_dh_read_csr_private (&A->m, &A->rp, &A->cval, &A->aval, fp);
01354   CHECK_V_ERROR;
01355   A->n = A->m;
01356   *mat = A;
01357 
01358   closeFile_dh (fp);
01359   CHECK_V_ERROR;
01360 END_FUNC_DH}
01361 
01362 /* seq only */
01363 #undef __FUNC__
01364 #define __FUNC__ "Mat_dhReadTriples"
01365 void
01366 Mat_dhReadTriples (Mat_dh * mat, int ignore, char *filename)
01367 {
01368   START_FUNC_DH FILE * fp = NULL;
01369   Mat_dh A = NULL;
01370 
01371   if (np_dh > 1)
01372     {
01373       SET_V_ERROR ("only implemented for a single MPI task");
01374     }
01375 
01376   fp = openFile_dh (filename, "r");
01377   CHECK_V_ERROR;
01378 
01379   Mat_dhCreate (&A);
01380   CHECK_V_ERROR;
01381   mat_dh_read_triples_private (ignore, &A->m, &A->rp, &A->cval, &A->aval, fp);
01382   CHECK_V_ERROR;
01383   A->n = A->m;
01384   *mat = A;
01385 
01386   closeFile_dh (fp);
01387   CHECK_V_ERROR;
01388 END_FUNC_DH}
01389 
01390 /* here we pass the private function a filename, instead of an open file,
01391    the reason being that Euclid's binary format is more complicated,
01392    i.e, the other "Read" methods are only for a single mpi task.
01393 */
01394 #undef __FUNC__
01395 #define __FUNC__ "Mat_dhReadBIN"
01396 void
01397 Mat_dhReadBIN (Mat_dh * mat, char *filename)
01398 {
01399   START_FUNC_DH Mat_dh A;
01400 
01401   if (np_dh > 1)
01402     {
01403       SET_V_ERROR ("only implemented for a single MPI task");
01404     }
01405 
01406   Mat_dhCreate (&A);
01407   CHECK_V_ERROR;
01408   io_dh_read_ebin_mat_private (&A->m, &A->rp, &A->cval, &A->aval, filename);
01409   CHECK_V_ERROR;
01410   A->n = A->m;
01411   *mat = A;
01412 END_FUNC_DH}
01413 
01414 #undef __FUNC__
01415 #define __FUNC__ "Mat_dhTranspose"
01416 void
01417 Mat_dhTranspose (Mat_dh A, Mat_dh * Bout)
01418 {
01419   START_FUNC_DH Mat_dh B;
01420 
01421   if (np_dh > 1)
01422     {
01423       SET_V_ERROR ("only for sequential");
01424     }
01425 
01426   Mat_dhCreate (&B);
01427   CHECK_V_ERROR;
01428   *Bout = B;
01429   B->m = B->n = A->m;
01430   mat_dh_transpose_private (A->m, A->rp, &B->rp, A->cval, &B->cval,
01431                 A->aval, &B->aval);
01432   CHECK_V_ERROR;
01433 END_FUNC_DH}
01434 
01435 #undef __FUNC__
01436 #define __FUNC__ "Mat_dhMakeStructurallySymmetric"
01437 void
01438 Mat_dhMakeStructurallySymmetric (Mat_dh A)
01439 {
01440   START_FUNC_DH if (np_dh > 1)
01441     {
01442       SET_V_ERROR ("only for sequential");
01443     }
01444   make_symmetric_private (A->m, &A->rp, &A->cval, &A->aval);
01445   CHECK_V_ERROR;
01446 END_FUNC_DH}
01447 
01448 void insert_diags_private (Mat_dh A, int ct);
01449 
01450 /* inserts diagonal if not explicitly present;
01451    sets diagonal value in row i to sum of absolute
01452    values of all elts in row i.
01453 */
01454 #undef __FUNC__
01455 #define __FUNC__ "Mat_dhFixDiags"
01456 void
01457 Mat_dhFixDiags (Mat_dh A)
01458 {
01459   START_FUNC_DH int i, j;
01460   int *rp = A->rp, *cval = A->cval, m = A->m;
01461   bool ct = 0;          /* number of missing diagonals */
01462   double *aval = A->aval;
01463 
01464   /* determine if any diagonals are missing */
01465   for (i = 0; i < m; ++i)
01466     {
01467       bool flag = true;
01468       for (j = rp[i]; j < rp[i + 1]; ++j)
01469     {
01470       int col = cval[j];
01471       if (col == i)
01472         {
01473           flag = false;
01474           break;
01475         }
01476     }
01477       if (flag)
01478     ++ct;
01479     }
01480 
01481   /* insert any missing diagonal elements */
01482   if (ct)
01483     {
01484       printf
01485     ("\nMat_dhFixDiags:: %i diags not explicitly present; inserting!\n",
01486      ct);
01487       insert_diags_private (A, ct);
01488       CHECK_V_ERROR;
01489       rp = A->rp;
01490       cval = A->cval;
01491       aval = A->aval;
01492     }
01493 
01494   /* set the value of all diagonal elements */
01495   for (i = 0; i < m; ++i)
01496     {
01497       double sum = 0.0;
01498       for (j = rp[i]; j < rp[i + 1]; ++j)
01499     {
01500       sum += fabs (aval[j]);
01501     }
01502       for (j = rp[i]; j < rp[i + 1]; ++j)
01503     {
01504       if (cval[j] == i)
01505         {
01506           aval[j] = sum;
01507         }
01508     }
01509     }
01510 END_FUNC_DH}
01511 
01512 
01513 #undef __FUNC__
01514 #define __FUNC__ "insert_diags_private"
01515 void
01516 insert_diags_private (Mat_dh A, int ct)
01517 {
01518   START_FUNC_DH int *RP = A->rp, *CVAL = A->cval;
01519   int *rp, *cval, m = A->m;
01520   double *aval, *AVAL = A->aval;
01521   int nz = RP[m] + ct;
01522   int i, j, idx = 0;
01523 
01524   rp = A->rp = (int *) MALLOC_DH ((m + 1) * sizeof (int));
01525   CHECK_V_ERROR;
01526   cval = A->cval = (int *) MALLOC_DH (nz * sizeof (int));
01527   CHECK_V_ERROR;
01528   aval = A->aval = (double *) MALLOC_DH (nz * sizeof (double));
01529   CHECK_V_ERROR;
01530   rp[0] = 0;
01531 
01532   for (i = 0; i < m; ++i)
01533     {
01534       bool flag = true;
01535       for (j = RP[i]; j < RP[i + 1]; ++j)
01536     {
01537       cval[idx] = CVAL[j];
01538       aval[idx] = AVAL[j];
01539       ++idx;
01540       if (CVAL[j] == i)
01541         flag = false;
01542     }
01543 
01544       if (flag)
01545     {
01546       cval[idx] = i;
01547       aval[idx] = 0.0;
01548       ++idx;
01549     }
01550       rp[i + 1] = idx;
01551     }
01552 
01553   FREE_DH (RP);
01554   CHECK_V_ERROR;
01555   FREE_DH (CVAL);
01556   CHECK_V_ERROR;
01557   FREE_DH (AVAL);
01558   CHECK_V_ERROR;
01559 
01560 END_FUNC_DH}
01561 
01562 #undef __FUNC__
01563 #define __FUNC__ "Mat_dhPrintDiags"
01564 void
01565 Mat_dhPrintDiags (Mat_dh A, FILE * fp)
01566 {
01567   START_FUNC_DH int i, j, m = A->m;
01568   int *rp = A->rp, *cval = A->cval;
01569   double *aval = A->aval;
01570 
01571   fprintf (fp,
01572        "=================== diagonal elements ====================\n");
01573   for (i = 0; i < m; ++i)
01574     {
01575       bool flag = true;
01576       for (j = rp[i]; j < rp[i + 1]; ++j)
01577     {
01578       if (cval[j] == i)
01579         {
01580           fprintf (fp, "%i  %g\n", i + 1, aval[j]);
01581           flag = false;
01582           break;
01583         }
01584     }
01585       if (flag)
01586     {
01587       fprintf (fp, "%i  ---------- missing\n", i + 1);
01588     }
01589     }
01590 END_FUNC_DH}
01591 
01592 
01593 #undef __FUNC__
01594 #define __FUNC__ "Mat_dhGetRow"
01595 void
01596 Mat_dhGetRow (Mat_dh B, int globalRow, int *len, int **ind, double **val)
01597 {
01598   START_FUNC_DH int row = globalRow - B->beg_row;
01599   if (row > B->m)
01600     {
01601       sprintf (msgBuf_dh,
01602            "requested globalRow= %i, which is local row= %i, but only have %i rows!",
01603            globalRow, row, B->m);
01604       SET_V_ERROR (msgBuf_dh);
01605     }
01606   *len = B->rp[row + 1] - B->rp[row];
01607   if (ind != NULL)
01608     *ind = B->cval + B->rp[row];
01609   if (val != NULL)
01610     *val = B->aval + B->rp[row];
01611 END_FUNC_DH}
01612 
01613 #undef __FUNC__
01614 #define __FUNC__ "Mat_dhRestoreRow"
01615 void
01616 Mat_dhRestoreRow (Mat_dh B, int row, int *len, int **ind, double **val)
01617 {
01618 START_FUNC_DH END_FUNC_DH}
01619 
01620 #undef __FUNC__
01621 #define __FUNC__ "Mat_dhRowPermute"
01622 void
01623 Mat_dhRowPermute (Mat_dh mat)
01624 {
01625   START_FUNC_DH if (ignoreMe)
01626     SET_V_ERROR ("turned off; compilation problem on blue");
01627 
01628 #if 0
01629   int i, j, m = mat->m, nz = mat->rp[m];
01630   int *o2n, *cval;
01631   int algo = 1;
01632   double *r1, *c1;
01633   bool debug = mat->debug;
01634   bool isNatural;
01635   Mat_dh B;
01636 
01637 #if 0
01638 * = 1:Compute a row permutation of the matrix so that the
01639     * permuted matrix has as many entries on its diagonal as
01640     * possible.The values on the diagonal are of arbitrary size.
01641     * HSL subroutine MC21A / AD is used for this
01642   . * = 2: Compute a row permutation of the matrix so that the smallest * value on the diagonal of the permuted matrix is maximized. * = 3:Compute a row permutation of the matrix so that the smallest
01643       * value on the diagonal of the permuted matrix is maximized.
01644       * The algorithm differs from the one used for JOB
01645     = 2 and may * have quite a different performance. * = 4: Compute a row permutation of the matrix so that the sum * of the diagonal entries of the permuted matrix is maximized. * = 5:Compute a row permutation of the matrix so that the product
01646     * of the diagonal entries of the permuted matrix is maximized
01647     * and vectors to scale the matrix so that the nonzero diagonal
01648     * entries of the permuted matrix are one in absolute value and
01649     * all the off - diagonal entries are less than or equal to one in
01650     * absolute value.
01651 #endif
01652     Parser_dhReadInt (parser_dh, "-rowPermute", &algo);
01653   CHECK_V_ERROR;
01654   if (algo < 1)
01655     algo = 1;
01656   if (algo > 5)
01657     algo = 1;
01658   sprintf (msgBuf_dh, "calling row permutation with algo= %i", algo);
01659   SET_INFO (msgBuf_dh);
01660 
01661   r1 = (double *) MALLOC_DH (m * sizeof (double));
01662   CHECK_V_ERROR;
01663   c1 = (double *) MALLOC_DH (m * sizeof (double));
01664   CHECK_V_ERROR;
01665   if (mat->row_perm == NULL)
01666     {
01667       mat->row_perm = o2n = (int *) MALLOC_DH (m * sizeof (int));
01668       CHECK_V_ERROR;
01669     }
01670   else
01671     {
01672       o2n = mat->row_perm;
01673     }
01674 
01675   Mat_dhTranspose (mat, &B);
01676   CHECK_V_ERROR;
01677 
01678   /* get row permutation and scaling vectors */
01679   dldperm (algo, m, nz, B->rp, B->cval, B->aval, o2n, r1, c1);
01680 
01681   /* permute column indices, then turn the matrix rightside up */
01682   cval = B->cval;
01683   for (i = 0; i < nz; ++i)
01684     cval[i] = o2n[cval[i]];
01685 
01686   /* debug block */
01687   if (debug && logFile != NULL)
01688     {
01689       fprintf (logFile, "\n-------- row permutation vector --------\n");
01690       for (i = 0; i < m; ++i)
01691     fprintf (logFile, "%i ", 1 + o2n[i]);
01692       fprintf (logFile, "\n");
01693 
01694       if (myid_dh == 0)
01695     {
01696       printf ("\n-------- row permutation vector --------\n");
01697       for (i = 0; i < m; ++i)
01698         printf ("%i ", 1 + o2n[i]);
01699       printf ("\n");
01700     }
01701     }
01702 
01703   /* check to see if permutation is non-natural */
01704   isNatural = true;
01705   for (i = 0; i < m; ++i)
01706     {
01707       if (o2n[i] != i)
01708     {
01709       isNatural = false;
01710       break;
01711     }
01712     }
01713 
01714   if (isNatural)
01715     {
01716       printf ("@@@ [%i] Mat_dhRowPermute :: got natural ordering!\n",
01717           myid_dh);
01718     }
01719   else
01720     {
01721       int *rp = B->rp, *cval = B->cval;
01722       double *aval = B->aval;
01723 
01724       if (algo == 5)
01725     {
01726       printf
01727         ("@@@ [%i] Mat_dhRowPermute :: scaling matrix rows and columns!\n",
01728          myid_dh);
01729 
01730       /* scale matrix */
01731       for (i = 0; i < m; i++)
01732         {
01733           r1[i] = exp (r1[i]);
01734           c1[i] = exp (c1[i]);
01735         }
01736       for (i = 0; i < m; i++)
01737         for (j = rp[i]; j < rp[i + 1]; j++)
01738           aval[j] *= r1[cval[j]] * c1[i];
01739     }
01740 
01741       mat_dh_transpose_reuse_private (B->m, B->rp, B->cval, B->aval,
01742                       mat->rp, mat->cval, mat->aval);
01743       CHECK_V_ERROR;
01744     }
01745 
01746 
01747   Mat_dhDestroy (B);
01748   CHECK_V_ERROR;
01749   FREE_DH (r1);
01750   CHECK_V_ERROR;
01751   FREE_DH (c1);
01752   CHECK_V_ERROR;
01753 
01754 #endif
01755 END_FUNC_DH}
01756 
01757 
01758 /*==============================================================================*/
01759 #undef __FUNC__
01760 #define __FUNC__ "Mat_dhPartition"
01761 void
01762 build_adj_lists_private (Mat_dh mat, int **rpOUT, int **cvalOUT)
01763 {
01764   START_FUNC_DH int m = mat->m;
01765   int *RP = mat->rp, *CVAL = mat->cval;
01766   int nz = RP[m];
01767   int i, j, *rp, *cval, idx = 0;
01768 
01769   rp = *rpOUT = (int *) MALLOC_DH ((m + 1) * sizeof (int));
01770   CHECK_V_ERROR;
01771   cval = *cvalOUT = (int *) MALLOC_DH (nz * sizeof (int));
01772   CHECK_V_ERROR;
01773   rp[0] = 0;
01774 
01775   /* assume symmetry for now! */
01776   for (i = 0; i < m; ++i)
01777     {
01778       for (j = RP[i]; j < RP[i + 1]; ++j)
01779     {
01780       int col = CVAL[j];
01781       if (col != i)
01782         {
01783           cval[idx++] = col;
01784         }
01785     }
01786       rp[i + 1] = idx;
01787     }
01788 END_FUNC_DH}
01789 
01790 
01791 #undef __FUNC__
01792 #define __FUNC__ "Mat_dhPartition"
01793 void
01794 Mat_dhPartition (Mat_dh mat, int blocks,
01795          int **beg_rowOUT, int **row_countOUT, int **n2oOUT,
01796          int **o2nOUT)
01797 {
01798   START_FUNC_DH
01799 #ifndef HAVE_METIS_DH
01800     if (ignoreMe)
01801     SET_V_ERROR ("not compiled for metis!");
01802 
01803 #else
01804   int *beg_row, *row_count, *n2o, *o2n, bk, new, *part;
01805   int m = mat->m;
01806   int i, cutEdgeCount;
01807   double zero = 0.0;
01808   int metisOpts[5] = { 0, 0, 0, 0, 0 };
01809   int *rp, *cval;
01810 
01811   /* allocate storage for returned arrays */
01812   beg_row = *beg_rowOUT = (int *) MALLOC_DH (blocks * sizeof (int));
01813   CHECK_V_ERROR;
01814   row_count = *row_countOUT = (int *) MALLOC_DH (blocks * sizeof (int));
01815   CHECK_V_ERROR;
01816   *n2oOUT = n2o = (int *) MALLOC_DH (m * sizeof (int));
01817   CHECK_V_ERROR;
01818   *o2nOUT = o2n = (int *) MALLOC_DH (m * sizeof (int));
01819   CHECK_V_ERROR;
01820 
01821 #if 0
01822 == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == = Metis arguments:
01823 
01824   n - number of nodes rp[], cval[]NULL, NULL, 0 /*no edge or vertex weights */
01825     0               /*use zero-based numbering */
01826     blocksIN, options[5] = 0::0 / 1 use defauls;
01827   use uptions 1. .4
01828     1::
01829     edgecutOUT,
01830     part[]
01831     == == == == == == == == == == == == == == == == == == == == == == == == ==
01832     == == == == == =
01833 #endif
01834     /* form the graph representation that metis wants */
01835     build_adj_lists_private (mat, &rp, &cval);
01836   CHECK_V_ERROR;
01837   part = (int *) MALLOC_DH (m * sizeof (int));
01838   CHECK_V_ERROR;
01839 
01840   /* get parition vector from metis */
01841   METIS_PartGraphKway (&m, rp, cval, NULL, NULL,
01842                &zero, &zero, &blocks, metisOpts, &cutEdgeCount, part);
01843 
01844   FREE_DH (rp);
01845   CHECK_V_ERROR;
01846   FREE_DH (cval);
01847   CHECK_V_ERROR;
01848 
01849   if (mat->debug)
01850     {
01851       printf_dh ("\nmetis partitioning vector; blocks= %i\n", blocks);
01852       for (i = 0; i < m; ++i)
01853     printf_dh ("  %i %i\n", i + 1, part[i]);
01854     }
01855 
01856   /* compute beg_row, row_count arrays from partition vector */
01857   for (i = 0; i < blocks; ++i)
01858     row_count[i] = 0;
01859   for (i = 0; i < m; ++i)
01860     {
01861       bk = part[i];     /* block to which row i belongs */
01862       row_count[bk] += 1;
01863     }
01864   beg_row[0] = 0;
01865   for (i = 1; i < blocks; ++i)
01866     beg_row[i] = beg_row[i - 1] + row_count[i - 1];
01867 
01868   if (mat->debug)
01869     {
01870       printf_dh ("\nrow_counts: ");
01871       for (i = 0; i < blocks; ++i)
01872     printf_dh (" %i", row_count[i]);
01873       printf_dh ("\nbeg_row: ");
01874       for (i = 0; i < blocks; ++i)
01875     printf_dh (" %i", beg_row[i] + 1);
01876       printf_dh ("\n");
01877     }
01878 
01879   /* compute permutation vector */
01880   {
01881     int *tmp = (int *) MALLOC_DH (blocks * sizeof (int));
01882     CHECK_V_ERROR;
01883     memcpy (tmp, beg_row, blocks * sizeof (int));
01884     for (i = 0; i < m; ++i)
01885       {
01886     bk = part[i];       /* block to which row i belongs */
01887     new = tmp[bk];
01888     tmp[bk] += 1;
01889     o2n[i] = new;
01890     n2o[new] = i;
01891       }
01892     FREE_DH (tmp);
01893   }
01894 
01895   FREE_DH (part);
01896   CHECK_V_ERROR;
01897 
01898 #endif
01899 
01900 END_FUNC_DH}
 All Classes Files Functions Variables Enumerations Friends