[petsc-users] About MatGetOwnershipRange()

Joon Hee Choi choi240 at purdue.edu
Thu Sep 12 18:03:53 CDT 2013


Hi Jed,

Thank you for your reply. I tried to follow your method, but I think my code still has something wrong because "localsize" is the same as global row size("I"). Could you let me know what I am missing? My new code is as follows:

PetscErrorCode SetUpMatrix(Mat *X, vector< std::tr1::tuple< PetscInt, PetscInt, PetscInt > >, PetscInt I, PetscInt J)
{
   PetscInt i, j;
   PetscScalar val;

   MatCreate(PETSC_COMM_WORLD, X);
   MatSetType(*X, MATMPIAIJ);
   MatSetSizes(*X, PETSC_DECIDE, PETSC_DECIDE, I, J);

   PetscInt begin, end, localsize=PETSC_DECIDE;
   PetscSplitOwnership(PETSC_COMM_WORLD, &localsize, &I);
   MPI_Scan(&localsize, &end, 1, MPI_INT, MPI_SUM, PETSC_COMM_WORLD);
   begin = end - localsize;
   PetscPrintf(PETSC_COMM_WORLD, "Local Size: %d, begin: %d, end: %d \n", localsize, begin, end);

   ...
}

Also, tuples are the total pairs of (row dimension, column dimension, element), values of sparse matrix, which are read from a file. The tuples are sorted and distributed. Thus, I tried to set up d_nnz and o_nnz. I implemented d_nnz[i-begin]++ only if begin<="i"&&"j"<end, otherwise o_nnz[i-begin]++ because "i" means the row number and "j" means the column number. Please let me know if there is something wrong in the following code:

   ...
   for (int x=0; x<tups.size(); x++) {
      i = std::tr1::get<0>(tups[x]);
      if (i>=end) break;
      if (i>=begin) {
         j = std::tr1::get<1>(tups[x]);
         if (j>=begin && j<end)  d_nnz[i-begin]++;
         else                    o_nnz[i-begin]++;
      }
   }
   MatMPIAIJSetPreallocation(*X, 0, d_nnz, 0, o_nnz);
   for (int x=0; x<tups.size(); x++) {
      i = std::tr1::get<0>(tups[x]);
      if (i>=end) break;
      if (i>=begin) {
         j = std::tr1::get<1>(tups[x]);
         val = std::tr1::get<2>(tups[x]);
         MatSetValues(*X, 1, &i, 1, &j, &val, INSERT_VALUES);
      }
   }
   MatAssemblyBegin(*X, MAT_FINAL_ASSEMBLY);
   MatAssemblyEnd(*X, MAT_FINAL_ASSEMBLY);
}


----- Original Message -----
From: "Jed Brown" <jedbrown at mcs.anl.gov>
To: "Joon Hee Choi" <choi240 at purdue.edu>, petsc-users at mcs.anl.gov
Sent: Thursday, September 12, 2013 4:04:17 AM
Subject: Re: [petsc-users] About MatGetOwnershipRange()

Joon Hee Choi <choi240 at purdue.edu> writes:

>> Hello,
>>
>> I am trying to set up a large MATMPIAIJ matrix from tuples. The tuples
>> is pairs of (row, column, value). I will use 12~20 machines for this
>> implementation. However, I think I need to know rows on each process
>> before preallocation, because for large matrices the exact
>> preallocation is important for good performance. Thus, I tried to use
>> MatGetOwnershipRange(), but I found out that I cannot use it before
>> preallocation. Could you let me know how to change my code? I am
>> attaching the code.
>>
>> Thank you,
>> Joon
>>
>>
>> PetscErrorCode SetUpMatrix(Mat *X, vector< std::tr1::tuple< PetscInt, PetscInt, PetscInt > >, PetscInt I, PetscInt J)
>> {
>>    PetscInt i, j;
>>    PetscScalar val;
>>
>>    MatCreate(PETSC_COMM_WORLD, X);
>>    MatSetType(*X, MATMPIAIJ);
>>    MatSetSizes(*X, PETSC_DECIDE, PETSC_DECIDE, I, J);
>>
>>    PetscInt begin, end;
>>    MatGetOwnershipRange(*X, &begin, &end);

>Use PetscSplitOwnership to determine sizes rows/columns, then MPI_Scan
>(or MPI_Exscan) to find your starting offset.  Alternatively, use the
>following sequence (from PetscLayoutCreate).
>
>    Notes: Typical calling sequence
>       PetscLayoutCreate(MPI_Comm,PetscLayout *);
>       PetscLayoutSetBlockSize(PetscLayout,1);
>       PetscLayoutSetSize(PetscLayout,n) or PetscLayoutSetLocalSize(PetscLayout,N);
>       PetscLayoutSetUp(PetscLayout);
>       Optionally use any of the following:
>          PetscLayoutGetSize(PetscLayout,PetscInt *); or PetscLayoutGetLocalSize(PetscLayout,PetscInt *;)
>          PetscLayoutGetRange(PetscLayout,PetscInt *rstart,PetscInt *rend); or PetscLayoutGetRanges(PetscLayout,const PetscInt *range[])
>       PetscLayoutDestroy(PetscLayout*);

>>    PetscInt localsize = end - begin;
>>
>>    PetscInt d_nnz[localsize];
>>    PetscInt o_nnz[localsize];

>This allocation will overflow your stack.  You probably want to put it
>on the heap.

>>    for (int x=0; x<tups.size(); x++) {
>>       i = std::tr1::get<0>(tups[x]);
>>       if (i>=end) break;

>Are your tuples sorted to begin with?  Are they specified redundantly or
>distributed?  Are any of the tuples nonlocal?  If it is distributed
>without matching the row distribution, then you need to communicate
>d_nnz and o_nnz.

>>       if (i>=begin) {
>>          j = std::tr1::get<1>(tups[x]);
>>          if (j>=begin && j<end)  d_nnz[i-begin]++;
>>          else                    o_nnz[i-begin]++;
>>       }
>>    }
>>    MatMPIAIJSetPreallocation(*X, 0, d_nnz, 0, o_nnz);
>>
>>    for (int x=0; x<tups.size(); x++) {
>>       i = std::tr1::get<0>(tups[x]);
>>       if (i>=end) break;
>>       if (i>=begin) {
>>          j = std::tr1::get<1>(tups[x]);
>>          val = std::tr1::get<2>(tups[x]);
>>          MatSetValues(*X, 1, &i, 1, &j, &val, INSERT_VALUES);
>>       }
>>    }
>>    MatAssemblyBegin(*X, MAT_FINAL_ASSEMBLY);
>>    MatAssemblyEnd(*X, MAT_FINAL_ASSEMBLY);
>> }


More information about the petsc-users mailing list