1 2 /* 3 Support for the parallel AIJ matrix vector multiply 4 */ 5 #include <../src/mat/impls/aij/mpi/mpiaij.h> 6 #include <petsc/private/vecimpl.h> 7 #include <petsc/private/isimpl.h> /* needed because accesses data structure of ISLocalToGlobalMapping directly */ 8 9 PetscErrorCode MatSetUpMultiply_MPIAIJ(Mat mat) 10 { 11 Mat_MPIAIJ *aij = (Mat_MPIAIJ *)mat->data; 12 Mat_SeqAIJ *B = (Mat_SeqAIJ *)(aij->B->data); 13 PetscInt i, j, *aj = B->j, *garray; 14 PetscInt ec = 0; /* Number of nonzero external columns */ 15 IS from, to; 16 Vec gvec; 17 #if defined(PETSC_USE_CTABLE) 18 PetscTable gid1_lid1; 19 PetscTablePosition tpos; 20 PetscInt gid, lid; 21 #else 22 PetscInt N = mat->cmap->N, *indices; 23 #endif 24 25 PetscFunctionBegin; 26 if (!aij->garray) { 27 PetscCheck(aij->B, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing B mat"); 28 #if defined(PETSC_USE_CTABLE) 29 /* use a table */ 30 PetscCall(PetscTableCreate(aij->B->rmap->n, mat->cmap->N + 1, &gid1_lid1)); 31 for (i = 0; i < aij->B->rmap->n; i++) { 32 for (j = 0; j < B->ilen[i]; j++) { 33 PetscInt data, gid1 = aj[B->i[i] + j] + 1; 34 PetscCall(PetscTableFind(gid1_lid1, gid1, &data)); 35 if (!data) { 36 /* one based table */ 37 PetscCall(PetscTableAdd(gid1_lid1, gid1, ++ec, INSERT_VALUES)); 38 } 39 } 40 } 41 /* form array of columns we need */ 42 PetscCall(PetscMalloc1(ec, &garray)); 43 PetscCall(PetscTableGetHeadPosition(gid1_lid1, &tpos)); 44 while (tpos) { 45 PetscCall(PetscTableGetNext(gid1_lid1, &tpos, &gid, &lid)); 46 gid--; 47 lid--; 48 garray[lid] = gid; 49 } 50 PetscCall(PetscSortInt(ec, garray)); /* sort, and rebuild */ 51 PetscCall(PetscTableRemoveAll(gid1_lid1)); 52 for (i = 0; i < ec; i++) PetscCall(PetscTableAdd(gid1_lid1, garray[i] + 1, i + 1, INSERT_VALUES)); 53 /* compact out the extra columns in B */ 54 for (i = 0; i < aij->B->rmap->n; i++) { 55 for (j = 0; j < B->ilen[i]; j++) { 56 PetscInt gid1 = aj[B->i[i] + j] + 1; 57 PetscCall(PetscTableFind(gid1_lid1, gid1, &lid)); 58 lid--; 59 aj[B->i[i] + j] = lid; 60 } 61 } 62 PetscCall(PetscLayoutDestroy(&aij->B->cmap)); 63 PetscCall(PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)aij->B), ec, ec, 1, &aij->B->cmap)); 64 PetscCall(PetscTableDestroy(&gid1_lid1)); 65 #else 66 /* Make an array as long as the number of columns */ 67 /* mark those columns that are in aij->B */ 68 PetscCall(PetscCalloc1(N, &indices)); 69 for (i = 0; i < aij->B->rmap->n; i++) { 70 for (j = 0; j < B->ilen[i]; j++) { 71 if (!indices[aj[B->i[i] + j]]) ec++; 72 indices[aj[B->i[i] + j]] = 1; 73 } 74 } 75 76 /* form array of columns we need */ 77 PetscCall(PetscMalloc1(ec, &garray)); 78 ec = 0; 79 for (i = 0; i < N; i++) { 80 if (indices[i]) garray[ec++] = i; 81 } 82 83 /* make indices now point into garray */ 84 for (i = 0; i < ec; i++) indices[garray[i]] = i; 85 86 /* compact out the extra columns in B */ 87 for (i = 0; i < aij->B->rmap->n; i++) { 88 for (j = 0; j < B->ilen[i]; j++) aj[B->i[i] + j] = indices[aj[B->i[i] + j]]; 89 } 90 PetscCall(PetscLayoutDestroy(&aij->B->cmap)); 91 PetscCall(PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)aij->B), ec, ec, 1, &aij->B->cmap)); 92 PetscCall(PetscFree(indices)); 93 #endif 94 } else { 95 garray = aij->garray; 96 } 97 98 if (!aij->lvec) { 99 PetscCheck(aij->B, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing B mat"); 100 PetscCall(MatCreateVecs(aij->B, &aij->lvec, NULL)); 101 } 102 PetscCall(VecGetSize(aij->lvec, &ec)); 103 104 /* create two temporary Index sets for build scatter gather */ 105 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ec, garray, PETSC_COPY_VALUES, &from)); 106 PetscCall(ISCreateStride(PETSC_COMM_SELF, ec, 0, 1, &to)); 107 108 /* create temporary global vector to generate scatter context */ 109 /* This does not allocate the array's memory so is efficient */ 110 PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)mat), 1, mat->cmap->n, mat->cmap->N, NULL, &gvec)); 111 112 /* generate the scatter context */ 113 PetscCall(VecScatterDestroy(&aij->Mvctx)); 114 PetscCall(VecScatterCreate(gvec, from, aij->lvec, to, &aij->Mvctx)); 115 PetscCall(VecScatterViewFromOptions(aij->Mvctx, (PetscObject)mat, "-matmult_vecscatter_view")); 116 aij->garray = garray; 117 118 PetscCall(ISDestroy(&from)); 119 PetscCall(ISDestroy(&to)); 120 PetscCall(VecDestroy(&gvec)); 121 PetscFunctionReturn(0); 122 } 123 124 /* Disassemble the off-diag portion of the MPIAIJXxx matrix. 125 In other words, change the B from reduced format using local col ids 126 to expanded format using global col ids, which will make it easier to 127 insert new nonzeros (with global col ids) into the matrix. 128 The off-diag B determines communication in the matrix vector multiply. 129 */ 130 PetscErrorCode MatDisAssemble_MPIAIJ(Mat A) 131 { 132 Mat_MPIAIJ *aij = (Mat_MPIAIJ *)A->data; 133 Mat B = aij->B, Bnew; 134 Mat_SeqAIJ *Baij = (Mat_SeqAIJ *)B->data; 135 PetscInt i, j, m = B->rmap->n, n = A->cmap->N, col, ct = 0, *garray = aij->garray, *nz; 136 PetscScalar v; 137 const PetscScalar *ba; 138 139 PetscFunctionBegin; 140 /* free stuff related to matrix-vec multiply */ 141 PetscCall(VecDestroy(&aij->lvec)); 142 if (aij->colmap) { 143 #if defined(PETSC_USE_CTABLE) 144 PetscCall(PetscTableDestroy(&aij->colmap)); 145 #else 146 PetscCall(PetscFree(aij->colmap)); 147 #endif 148 } 149 150 /* make sure that B is assembled so we can access its values */ 151 PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY)); 152 PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY)); 153 154 /* invent new B and copy stuff over */ 155 PetscCall(PetscMalloc1(m + 1, &nz)); 156 for (i = 0; i < m; i++) nz[i] = Baij->i[i + 1] - Baij->i[i]; 157 PetscCall(MatCreate(PETSC_COMM_SELF, &Bnew)); 158 PetscCall(MatSetSizes(Bnew, m, n, m, n)); /* Bnew now uses A->cmap->N as its col size */ 159 PetscCall(MatSetBlockSizesFromMats(Bnew, A, A)); 160 PetscCall(MatSetType(Bnew, ((PetscObject)B)->type_name)); 161 PetscCall(MatSeqAIJSetPreallocation(Bnew, 0, nz)); 162 163 if (Baij->nonew >= 0) { /* Inherit insertion error options (if positive). */ 164 ((Mat_SeqAIJ *)Bnew->data)->nonew = Baij->nonew; 165 } 166 167 /* 168 Ensure that B's nonzerostate is monotonically increasing. 169 Or should this follow the MatSetValues() loop to preserve B's nonzerstate across a MatDisAssemble() call? 170 */ 171 Bnew->nonzerostate = B->nonzerostate; 172 173 PetscCall(PetscFree(nz)); 174 PetscCall(MatSeqAIJGetArrayRead(B, &ba)); 175 for (i = 0; i < m; i++) { 176 for (j = Baij->i[i]; j < Baij->i[i + 1]; j++) { 177 col = garray[Baij->j[ct]]; 178 v = ba[ct++]; 179 PetscCall(MatSetValues(Bnew, 1, &i, 1, &col, &v, B->insertmode)); 180 } 181 } 182 PetscCall(MatSeqAIJRestoreArrayRead(B, &ba)); 183 184 PetscCall(PetscFree(aij->garray)); 185 PetscCall(MatDestroy(&B)); 186 187 aij->B = Bnew; 188 A->was_assembled = PETSC_FALSE; 189 PetscFunctionReturn(0); 190 } 191 192 /* ugly stuff added for Glenn someday we should fix this up */ 193 194 static PetscInt *auglyrmapd = NULL, *auglyrmapo = NULL; /* mapping from the local ordering to the "diagonal" and "off-diagonal" parts of the local matrix */ 195 static Vec auglydd = NULL, auglyoo = NULL; /* work vectors used to scale the two parts of the local matrix */ 196 197 PetscErrorCode MatMPIAIJDiagonalScaleLocalSetUp(Mat inA, Vec scale) 198 { 199 Mat_MPIAIJ *ina = (Mat_MPIAIJ *)inA->data; /*access private part of matrix */ 200 PetscInt i, n, nt, cstart, cend, no, *garray = ina->garray, *lindices; 201 PetscInt *r_rmapd, *r_rmapo; 202 203 PetscFunctionBegin; 204 PetscCall(MatGetOwnershipRange(inA, &cstart, &cend)); 205 PetscCall(MatGetSize(ina->A, NULL, &n)); 206 PetscCall(PetscCalloc1(inA->rmap->mapping->n + 1, &r_rmapd)); 207 nt = 0; 208 for (i = 0; i < inA->rmap->mapping->n; i++) { 209 if (inA->rmap->mapping->indices[i] >= cstart && inA->rmap->mapping->indices[i] < cend) { 210 nt++; 211 r_rmapd[i] = inA->rmap->mapping->indices[i] + 1; 212 } 213 } 214 PetscCheck(nt == n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hmm nt %" PetscInt_FMT " n %" PetscInt_FMT, nt, n); 215 PetscCall(PetscMalloc1(n + 1, &auglyrmapd)); 216 for (i = 0; i < inA->rmap->mapping->n; i++) { 217 if (r_rmapd[i]) auglyrmapd[(r_rmapd[i] - 1) - cstart] = i; 218 } 219 PetscCall(PetscFree(r_rmapd)); 220 PetscCall(VecCreateSeq(PETSC_COMM_SELF, n, &auglydd)); 221 222 PetscCall(PetscCalloc1(inA->cmap->N + 1, &lindices)); 223 for (i = 0; i < ina->B->cmap->n; i++) lindices[garray[i]] = i + 1; 224 no = inA->rmap->mapping->n - nt; 225 PetscCall(PetscCalloc1(inA->rmap->mapping->n + 1, &r_rmapo)); 226 nt = 0; 227 for (i = 0; i < inA->rmap->mapping->n; i++) { 228 if (lindices[inA->rmap->mapping->indices[i]]) { 229 nt++; 230 r_rmapo[i] = lindices[inA->rmap->mapping->indices[i]]; 231 } 232 } 233 PetscCheck(nt <= no, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hmm nt %" PetscInt_FMT " no %" PetscInt_FMT, nt, n); 234 PetscCall(PetscFree(lindices)); 235 PetscCall(PetscMalloc1(nt + 1, &auglyrmapo)); 236 for (i = 0; i < inA->rmap->mapping->n; i++) { 237 if (r_rmapo[i]) auglyrmapo[(r_rmapo[i] - 1)] = i; 238 } 239 PetscCall(PetscFree(r_rmapo)); 240 PetscCall(VecCreateSeq(PETSC_COMM_SELF, nt, &auglyoo)); 241 PetscFunctionReturn(0); 242 } 243 244 PetscErrorCode MatMPIAIJDiagonalScaleLocal(Mat A, Vec scale) 245 { 246 /* This routine should really be abandoned as it duplicates MatDiagonalScaleLocal */ 247 248 PetscFunctionBegin; 249 PetscTryMethod(A, "MatDiagonalScaleLocal_C", (Mat, Vec), (A, scale)); 250 PetscFunctionReturn(0); 251 } 252 253 PetscErrorCode MatDiagonalScaleLocal_MPIAIJ(Mat A, Vec scale) 254 { 255 Mat_MPIAIJ *a = (Mat_MPIAIJ *)A->data; /*access private part of matrix */ 256 PetscInt n, i; 257 PetscScalar *d, *o; 258 const PetscScalar *s; 259 260 PetscFunctionBegin; 261 if (!auglyrmapd) PetscCall(MatMPIAIJDiagonalScaleLocalSetUp(A, scale)); 262 263 PetscCall(VecGetArrayRead(scale, &s)); 264 265 PetscCall(VecGetLocalSize(auglydd, &n)); 266 PetscCall(VecGetArray(auglydd, &d)); 267 for (i = 0; i < n; i++) { d[i] = s[auglyrmapd[i]]; /* copy "diagonal" (true local) portion of scale into dd vector */ } 268 PetscCall(VecRestoreArray(auglydd, &d)); 269 /* column scale "diagonal" portion of local matrix */ 270 PetscCall(MatDiagonalScale(a->A, NULL, auglydd)); 271 272 PetscCall(VecGetLocalSize(auglyoo, &n)); 273 PetscCall(VecGetArray(auglyoo, &o)); 274 for (i = 0; i < n; i++) { o[i] = s[auglyrmapo[i]]; /* copy "off-diagonal" portion of scale into oo vector */ } 275 PetscCall(VecRestoreArrayRead(scale, &s)); 276 PetscCall(VecRestoreArray(auglyoo, &o)); 277 /* column scale "off-diagonal" portion of local matrix */ 278 PetscCall(MatDiagonalScale(a->B, NULL, auglyoo)); 279 PetscFunctionReturn(0); 280 } 281