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