1d4002b98SHong Zhang /* 2d4002b98SHong Zhang Support for the parallel SELL matrix vector multiply 3d4002b98SHong Zhang */ 4d4002b98SHong Zhang #include <../src/mat/impls/sell/mpi/mpisell.h> 5d4002b98SHong Zhang #include <petsc/private/isimpl.h> /* needed because accesses data structure of ISLocalToGlobalMapping directly */ 6d4002b98SHong Zhang 7d4002b98SHong Zhang /* 8d4002b98SHong Zhang Takes the local part of an already assembled MPISELL matrix 9d4002b98SHong Zhang and disassembles it. This is to allow new nonzeros into the matrix 10d4002b98SHong Zhang that require more communication in the matrix vector multiply. 11d4002b98SHong Zhang Thus certain data-structures must be rebuilt. 12d4002b98SHong Zhang 13d4002b98SHong Zhang Kind of slow! But that's what application programmers get when 14d4002b98SHong Zhang they are sloppy. 15d4002b98SHong Zhang */ 16d4002b98SHong Zhang PetscErrorCode MatDisAssemble_MPISELL(Mat A) 17d4002b98SHong Zhang { 18d4002b98SHong Zhang Mat_MPISELL *sell=(Mat_MPISELL*)A->data; 19d4002b98SHong Zhang Mat B=sell->B,Bnew; 20d4002b98SHong Zhang Mat_SeqSELL *Bsell=(Mat_SeqSELL*)B->data; 21d4002b98SHong Zhang PetscInt i,j,totalslices,N=A->cmap->N,ec,row; 22d4002b98SHong Zhang PetscBool isnonzero; 23d4002b98SHong Zhang PetscErrorCode ierr; 24d4002b98SHong Zhang 25d4002b98SHong Zhang PetscFunctionBegin; 26d4002b98SHong Zhang /* free stuff related to matrix-vec multiply */ 27d4002b98SHong Zhang ierr = VecGetSize(sell->lvec,&ec);CHKERRQ(ierr); /* needed for PetscLogObjectMemory below */ 28d4002b98SHong Zhang ierr = VecDestroy(&sell->lvec);CHKERRQ(ierr); 29d4002b98SHong Zhang ierr = VecScatterDestroy(&sell->Mvctx);CHKERRQ(ierr); 30d4002b98SHong Zhang if (sell->colmap) { 31d4002b98SHong Zhang #if defined(PETSC_USE_CTABLE) 32d4002b98SHong Zhang ierr = PetscTableDestroy(&sell->colmap);CHKERRQ(ierr); 33d4002b98SHong Zhang #else 34d4002b98SHong Zhang ierr = PetscFree(sell->colmap);CHKERRQ(ierr); 35d4002b98SHong Zhang ierr = PetscLogObjectMemory((PetscObject)A,-sell->B->cmap->n*sizeof(PetscInt));CHKERRQ(ierr); 36d4002b98SHong Zhang #endif 37d4002b98SHong Zhang } 38d4002b98SHong Zhang 39d4002b98SHong Zhang /* make sure that B is assembled so we can access its values */ 40d4002b98SHong Zhang ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 41d4002b98SHong Zhang ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 42d4002b98SHong Zhang 43d4002b98SHong Zhang /* invent new B and copy stuff over */ 44d4002b98SHong Zhang ierr = MatCreate(PETSC_COMM_SELF,&Bnew);CHKERRQ(ierr); 45d4002b98SHong Zhang ierr = MatSetSizes(Bnew,B->rmap->n,N,B->rmap->n,N);CHKERRQ(ierr); 46d4002b98SHong Zhang ierr = MatSetBlockSizesFromMats(Bnew,A,A);CHKERRQ(ierr); 47d4002b98SHong Zhang ierr = MatSetType(Bnew,((PetscObject)B)->type_name);CHKERRQ(ierr); 48d4002b98SHong Zhang ierr = MatSeqSELLSetPreallocation(Bnew,0,Bsell->rlen);CHKERRQ(ierr); 49b38c15b3SStefano Zampini if (Bsell->nonew >= 0) { /* Inherit insertion error options (if positive). */ 50b38c15b3SStefano Zampini ((Mat_SeqSELL*)Bnew->data)->nonew = Bsell->nonew; 51b38c15b3SStefano Zampini } 52d4002b98SHong Zhang 53d4002b98SHong Zhang /* 54d4002b98SHong Zhang Ensure that B's nonzerostate is monotonically increasing. 55d4002b98SHong Zhang Or should this follow the MatSetValues() loop to preserve B's nonzerstate across a MatDisAssemble() call? 56d4002b98SHong Zhang */ 57d4002b98SHong Zhang Bnew->nonzerostate = B->nonzerostate; 58d4002b98SHong Zhang 59d4002b98SHong Zhang totalslices = B->rmap->n/8+((B->rmap->n & 0x07)?1:0); /* floor(n/8) */ 60d4002b98SHong Zhang for (i=0; i<totalslices; i++) { /* loop over slices */ 61d4002b98SHong Zhang for (j=Bsell->sliidx[i],row=0; j<Bsell->sliidx[i+1]; j++,row=((row+1)&0x07)) { 62d4002b98SHong Zhang isnonzero = (PetscBool)((j-Bsell->sliidx[i])/8 < Bsell->rlen[8*i+row]); 63d4002b98SHong Zhang if (isnonzero) { 64d4002b98SHong Zhang ierr = MatSetValue(Bnew,8*i+row,sell->garray[Bsell->colidx[j]],Bsell->val[j],B->insertmode);CHKERRQ(ierr); 65d4002b98SHong Zhang } 66d4002b98SHong Zhang } 67d4002b98SHong Zhang } 68d4002b98SHong Zhang 69d4002b98SHong Zhang ierr = PetscFree(sell->garray);CHKERRQ(ierr); 70d4002b98SHong Zhang ierr = PetscLogObjectMemory((PetscObject)A,-ec*sizeof(PetscInt));CHKERRQ(ierr); 71d4002b98SHong Zhang ierr = MatDestroy(&B);CHKERRQ(ierr); 72d4002b98SHong Zhang ierr = PetscLogObjectParent((PetscObject)A,(PetscObject)Bnew);CHKERRQ(ierr); 73d4002b98SHong Zhang 74d4002b98SHong Zhang sell->B = Bnew; 75d4002b98SHong Zhang A->was_assembled = PETSC_FALSE; 76d4002b98SHong Zhang A->assembled = PETSC_FALSE; 77d4002b98SHong Zhang PetscFunctionReturn(0); 78d4002b98SHong Zhang } 79d4002b98SHong Zhang 80d4002b98SHong Zhang PetscErrorCode MatSetUpMultiply_MPISELL(Mat mat) 81d4002b98SHong Zhang { 82d4002b98SHong Zhang Mat_MPISELL *sell=(Mat_MPISELL*)mat->data; 83d4002b98SHong Zhang Mat_SeqSELL *B=(Mat_SeqSELL*)(sell->B->data); 84d4002b98SHong Zhang PetscErrorCode ierr; 85d4002b98SHong Zhang PetscInt i,j,*bcolidx=B->colidx,ec=0,*garray,totalslices; 86d4002b98SHong Zhang IS from,to; 87d4002b98SHong Zhang Vec gvec; 88d4002b98SHong Zhang PetscBool isnonzero; 89d4002b98SHong Zhang #if defined(PETSC_USE_CTABLE) 90d4002b98SHong Zhang PetscTable gid1_lid1; 91d4002b98SHong Zhang PetscTablePosition tpos; 92d4002b98SHong Zhang PetscInt gid,lid; 93d4002b98SHong Zhang #else 94d4002b98SHong Zhang PetscInt N = mat->cmap->N,*indices; 95d4002b98SHong Zhang #endif 96d4002b98SHong Zhang 97d4002b98SHong Zhang PetscFunctionBegin; 98d4002b98SHong Zhang totalslices = sell->B->rmap->n/8+((sell->B->rmap->n & 0x07)?1:0); /* floor(n/8) */ 99d4002b98SHong Zhang 100d4002b98SHong Zhang /* ec counts the number of columns that contain nonzeros */ 101d4002b98SHong Zhang #if defined(PETSC_USE_CTABLE) 102d4002b98SHong Zhang /* use a table */ 103d4002b98SHong Zhang ierr = PetscTableCreate(sell->B->rmap->n,mat->cmap->N+1,&gid1_lid1);CHKERRQ(ierr); 104d4002b98SHong Zhang for (i=0; i<totalslices; i++) { /* loop over slices */ 105d4002b98SHong Zhang for (j=B->sliidx[i]; j<B->sliidx[i+1]; j++) { 106d4002b98SHong Zhang isnonzero = (PetscBool)((j-B->sliidx[i])/8 < B->rlen[(i<<3)+(j&0x07)]); 107d4002b98SHong Zhang if (isnonzero) { /* check the mask bit */ 108d4002b98SHong Zhang PetscInt data,gid1 = bcolidx[j] + 1; 109d4002b98SHong Zhang ierr = PetscTableFind(gid1_lid1,gid1,&data);CHKERRQ(ierr); 110d4002b98SHong Zhang if (!data) { 111d4002b98SHong Zhang /* one based table */ 112d4002b98SHong Zhang ierr = PetscTableAdd(gid1_lid1,gid1,++ec,INSERT_VALUES);CHKERRQ(ierr); 113d4002b98SHong Zhang } 114d4002b98SHong Zhang } 115d4002b98SHong Zhang } 116d4002b98SHong Zhang } 117d4002b98SHong Zhang 118d4002b98SHong Zhang /* form array of columns we need */ 119d4002b98SHong Zhang ierr = PetscMalloc1(ec+1,&garray);CHKERRQ(ierr); 120d4002b98SHong Zhang ierr = PetscTableGetHeadPosition(gid1_lid1,&tpos);CHKERRQ(ierr); 121d4002b98SHong Zhang while (tpos) { 122d4002b98SHong Zhang ierr = PetscTableGetNext(gid1_lid1,&tpos,&gid,&lid);CHKERRQ(ierr); 123d4002b98SHong Zhang gid--; 124d4002b98SHong Zhang lid--; 125d4002b98SHong Zhang garray[lid] = gid; 126d4002b98SHong Zhang } 127d4002b98SHong Zhang ierr = PetscSortInt(ec,garray);CHKERRQ(ierr); /* sort, and rebuild */ 128d4002b98SHong Zhang ierr = PetscTableRemoveAll(gid1_lid1);CHKERRQ(ierr); 129d4002b98SHong Zhang for (i=0; i<ec; i++) { 130d4002b98SHong Zhang ierr = PetscTableAdd(gid1_lid1,garray[i]+1,i+1,INSERT_VALUES);CHKERRQ(ierr); 131d4002b98SHong Zhang } 132d4002b98SHong Zhang 133d4002b98SHong Zhang /* compact out the extra columns in B */ 134d4002b98SHong Zhang for (i=0; i<totalslices; i++) { /* loop over slices */ 135d4002b98SHong Zhang for (j=B->sliidx[i]; j<B->sliidx[i+1]; j++) { 136d4002b98SHong Zhang isnonzero = (PetscBool)((j-B->sliidx[i])/8 < B->rlen[(i<<3)+(j&0x07)]); 137d4002b98SHong Zhang if (isnonzero) { 138d4002b98SHong Zhang PetscInt gid1 = bcolidx[j] + 1; 139d4002b98SHong Zhang ierr = PetscTableFind(gid1_lid1,gid1,&lid);CHKERRQ(ierr); 140d4002b98SHong Zhang lid--; 141d4002b98SHong Zhang bcolidx[j] = lid; 142d4002b98SHong Zhang } 143d4002b98SHong Zhang } 144d4002b98SHong Zhang } 145ca5434daSLawrence Mitchell ierr = PetscLayoutDestroy(&sell->B->cmap);CHKERRQ(ierr); 146ca5434daSLawrence Mitchell ierr = PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)sell->B),ec,ec,1,&sell->B->cmap);CHKERRQ(ierr); 147d4002b98SHong Zhang ierr = PetscTableDestroy(&gid1_lid1);CHKERRQ(ierr); 148d4002b98SHong Zhang #else 149d4002b98SHong Zhang /* Make an array as long as the number of columns */ 150d4002b98SHong Zhang ierr = PetscCalloc1(N+1,&indices);CHKERRQ(ierr); 151d4002b98SHong Zhang /* mark those columns that are in sell->B */ 152d4002b98SHong Zhang for (i=0; i<totalslices; i++) { /* loop over slices */ 153d4002b98SHong Zhang for (j=B->sliidx[i]; j<B->sliidx[i+1]; j++) { 154d4002b98SHong Zhang isnonzero = (PetscBool)((j-B->sliidx[i])/8 < B->rlen[(i<<3)+(j&0x07)]); 155d4002b98SHong Zhang if (isnonzero) { 156d4002b98SHong Zhang if (!indices[bcolidx[j]]) ec++; 157d4002b98SHong Zhang indices[bcolidx[j]] = 1; 158d4002b98SHong Zhang } 159d4002b98SHong Zhang } 160d4002b98SHong Zhang } 161d4002b98SHong Zhang 162d4002b98SHong Zhang /* form array of columns we need */ 163d4002b98SHong Zhang ierr = PetscMalloc1(ec+1,&garray);CHKERRQ(ierr); 164d4002b98SHong Zhang ec = 0; 165d4002b98SHong Zhang for (i=0; i<N; i++) { 166d4002b98SHong Zhang if (indices[i]) garray[ec++] = i; 167d4002b98SHong Zhang } 168d4002b98SHong Zhang 169d4002b98SHong Zhang /* make indices now point into garray */ 170d4002b98SHong Zhang for (i=0; i<ec; i++) { 171d4002b98SHong Zhang indices[garray[i]] = i; 172d4002b98SHong Zhang } 173d4002b98SHong Zhang 174d4002b98SHong Zhang /* compact out the extra columns in B */ 175d4002b98SHong Zhang for (i=0; i<totalslices; i++) { /* loop over slices */ 176d4002b98SHong Zhang for (j=B->sliidx[i]; j<B->sliidx[i+1]; j++) { 177d4002b98SHong Zhang isnonzero = (PetscBool)((j-B->sliidx[i])/8 < B->rlen[(i<<3)+(j&0x07)]); 178d4002b98SHong Zhang if (isnonzero) bcolidx[j] = indices[bcolidx[j]]; 179d4002b98SHong Zhang } 180d4002b98SHong Zhang } 181ca5434daSLawrence Mitchell ierr = PetscLayoutDestroy(&sell->B->cmap);CHKERRQ(ierr); 182ca5434daSLawrence Mitchell ierr = PetscLayoutCreateFromSizes(PetscObjectComm((PetscObject)sell->B),ec,ec,1,&sell->B->cmap);CHKERRQ(ierr); 183d4002b98SHong Zhang ierr = PetscFree(indices);CHKERRQ(ierr); 184d4002b98SHong Zhang #endif 185d4002b98SHong Zhang /* create local vector that is used to scatter into */ 186d4002b98SHong Zhang ierr = VecCreateSeq(PETSC_COMM_SELF,ec,&sell->lvec);CHKERRQ(ierr); 187d4002b98SHong Zhang /* create two temporary Index sets for build scatter gather */ 188a3ebf921SJunchao Zhang ierr = ISCreateGeneral(PETSC_COMM_SELF,ec,garray,PETSC_COPY_VALUES,&from);CHKERRQ(ierr); 189d4002b98SHong Zhang ierr = ISCreateStride(PETSC_COMM_SELF,ec,0,1,&to);CHKERRQ(ierr); 190d4002b98SHong Zhang 191d4002b98SHong Zhang /* create temporary global vector to generate scatter context */ 192d4002b98SHong Zhang /* This does not allocate the array's memory so is efficient */ 193d4002b98SHong Zhang ierr = VecCreateMPIWithArray(PetscObjectComm((PetscObject)mat),1,mat->cmap->n,mat->cmap->N,NULL,&gvec);CHKERRQ(ierr); 194d4002b98SHong Zhang 195d4002b98SHong Zhang /* generate the scatter context */ 1969448b7f1SJunchao Zhang ierr = VecScatterCreate(gvec,from,sell->lvec,to,&sell->Mvctx);CHKERRQ(ierr); 197d4002b98SHong Zhang ierr = PetscLogObjectParent((PetscObject)mat,(PetscObject)sell->Mvctx);CHKERRQ(ierr); 198d4002b98SHong Zhang ierr = PetscLogObjectParent((PetscObject)mat,(PetscObject)sell->lvec);CHKERRQ(ierr); 199d4002b98SHong Zhang ierr = PetscLogObjectParent((PetscObject)mat,(PetscObject)from);CHKERRQ(ierr); 200d4002b98SHong Zhang ierr = PetscLogObjectParent((PetscObject)mat,(PetscObject)to);CHKERRQ(ierr); 201d4002b98SHong Zhang 202d4002b98SHong Zhang sell->garray = garray; 203d4002b98SHong Zhang 204d4002b98SHong Zhang ierr = PetscLogObjectMemory((PetscObject)mat,(ec+1)*sizeof(PetscInt));CHKERRQ(ierr); 205d4002b98SHong Zhang ierr = ISDestroy(&from);CHKERRQ(ierr); 206d4002b98SHong Zhang ierr = ISDestroy(&to);CHKERRQ(ierr); 207d4002b98SHong Zhang ierr = VecDestroy(&gvec);CHKERRQ(ierr); 208d4002b98SHong Zhang PetscFunctionReturn(0); 209d4002b98SHong Zhang } 210d4002b98SHong Zhang 211d4002b98SHong Zhang /* ugly stuff added for Glenn someday we should fix this up */ 212*f4259b30SLisandro Dalcin static PetscInt *auglyrmapd = NULL,*auglyrmapo = NULL; /* mapping from the local ordering to the "diagonal" and "off-diagonal" parts of the local matrix */ 213*f4259b30SLisandro Dalcin static Vec auglydd = NULL,auglyoo = NULL; /* work vectors used to scale the two parts of the local matrix */ 214d4002b98SHong Zhang 215d4002b98SHong Zhang PetscErrorCode MatMPISELLDiagonalScaleLocalSetUp(Mat inA,Vec scale) 216d4002b98SHong Zhang { 217d4002b98SHong Zhang Mat_MPISELL *ina=(Mat_MPISELL*)inA->data; /*access private part of matrix */ 218d4002b98SHong Zhang PetscErrorCode ierr; 219d4002b98SHong Zhang PetscInt i,n,nt,cstart,cend,no,*garray=ina->garray,*lindices; 220d4002b98SHong Zhang PetscInt *r_rmapd,*r_rmapo; 221d4002b98SHong Zhang 222d4002b98SHong Zhang PetscFunctionBegin; 223d4002b98SHong Zhang ierr = MatGetOwnershipRange(inA,&cstart,&cend);CHKERRQ(ierr); 224d4002b98SHong Zhang ierr = MatGetSize(ina->A,NULL,&n);CHKERRQ(ierr); 225d4002b98SHong Zhang ierr = PetscCalloc1(inA->rmap->mapping->n+1,&r_rmapd);CHKERRQ(ierr); 226d4002b98SHong Zhang nt = 0; 227d4002b98SHong Zhang for (i=0; i<inA->rmap->mapping->n; i++) { 228d4002b98SHong Zhang if (inA->rmap->mapping->indices[i] >= cstart && inA->rmap->mapping->indices[i] < cend) { 229d4002b98SHong Zhang nt++; 230d4002b98SHong Zhang r_rmapd[i] = inA->rmap->mapping->indices[i] + 1; 231d4002b98SHong Zhang } 232d4002b98SHong Zhang } 233d4002b98SHong Zhang if (nt != n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Hmm nt %D n %D",nt,n); 234d4002b98SHong Zhang ierr = PetscMalloc1(n+1,&auglyrmapd);CHKERRQ(ierr); 235d4002b98SHong Zhang for (i=0; i<inA->rmap->mapping->n; i++) { 236d4002b98SHong Zhang if (r_rmapd[i]) { 237d4002b98SHong Zhang auglyrmapd[(r_rmapd[i]-1)-cstart] = i; 238d4002b98SHong Zhang } 239d4002b98SHong Zhang } 240d4002b98SHong Zhang ierr = PetscFree(r_rmapd);CHKERRQ(ierr); 241d4002b98SHong Zhang ierr = VecCreateSeq(PETSC_COMM_SELF,n,&auglydd);CHKERRQ(ierr); 242d4002b98SHong Zhang ierr = PetscCalloc1(inA->cmap->N+1,&lindices);CHKERRQ(ierr); 243d4002b98SHong Zhang for (i=0; i<ina->B->cmap->n; i++) { 244d4002b98SHong Zhang lindices[garray[i]] = i+1; 245d4002b98SHong Zhang } 246d4002b98SHong Zhang no = inA->rmap->mapping->n - nt; 247d4002b98SHong Zhang ierr = PetscCalloc1(inA->rmap->mapping->n+1,&r_rmapo);CHKERRQ(ierr); 248d4002b98SHong Zhang nt = 0; 249d4002b98SHong Zhang for (i=0; i<inA->rmap->mapping->n; i++) { 250d4002b98SHong Zhang if (lindices[inA->rmap->mapping->indices[i]]) { 251d4002b98SHong Zhang nt++; 252d4002b98SHong Zhang r_rmapo[i] = lindices[inA->rmap->mapping->indices[i]]; 253d4002b98SHong Zhang } 254d4002b98SHong Zhang } 255d4002b98SHong Zhang if (nt > no) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Hmm nt %D no %D",nt,n); 256d4002b98SHong Zhang ierr = PetscFree(lindices);CHKERRQ(ierr); 257d4002b98SHong Zhang ierr = PetscMalloc1(nt+1,&auglyrmapo);CHKERRQ(ierr); 258d4002b98SHong Zhang for (i=0; i<inA->rmap->mapping->n; i++) { 259d4002b98SHong Zhang if (r_rmapo[i]) { 260d4002b98SHong Zhang auglyrmapo[(r_rmapo[i]-1)] = i; 261d4002b98SHong Zhang } 262d4002b98SHong Zhang } 263d4002b98SHong Zhang ierr = PetscFree(r_rmapo);CHKERRQ(ierr); 264d4002b98SHong Zhang ierr = VecCreateSeq(PETSC_COMM_SELF,nt,&auglyoo);CHKERRQ(ierr); 265d4002b98SHong Zhang PetscFunctionReturn(0); 266d4002b98SHong Zhang } 267d4002b98SHong Zhang 268d4002b98SHong Zhang PetscErrorCode MatDiagonalScaleLocal_MPISELL(Mat A,Vec scale) 269d4002b98SHong Zhang { 270d4002b98SHong Zhang Mat_MPISELL *a=(Mat_MPISELL*)A->data; /*access private part of matrix */ 271d4002b98SHong Zhang PetscErrorCode ierr; 272d4002b98SHong Zhang PetscInt n,i; 273d4002b98SHong Zhang PetscScalar *d,*o; 274d4002b98SHong Zhang const PetscScalar *s; 275d4002b98SHong Zhang 276d4002b98SHong Zhang PetscFunctionBegin; 277d4002b98SHong Zhang if (!auglyrmapd) { 278d4002b98SHong Zhang ierr = MatMPISELLDiagonalScaleLocalSetUp(A,scale);CHKERRQ(ierr); 279d4002b98SHong Zhang } 280d4002b98SHong Zhang ierr = VecGetArrayRead(scale,&s);CHKERRQ(ierr); 281d4002b98SHong Zhang ierr = VecGetLocalSize(auglydd,&n);CHKERRQ(ierr); 282d4002b98SHong Zhang ierr = VecGetArray(auglydd,&d);CHKERRQ(ierr); 283d4002b98SHong Zhang for (i=0; i<n; i++) { 284d4002b98SHong Zhang d[i] = s[auglyrmapd[i]]; /* copy "diagonal" (true local) portion of scale into dd vector */ 285d4002b98SHong Zhang } 286d4002b98SHong Zhang ierr = VecRestoreArray(auglydd,&d);CHKERRQ(ierr); 287d4002b98SHong Zhang /* column scale "diagonal" portion of local matrix */ 288d4002b98SHong Zhang ierr = MatDiagonalScale(a->A,NULL,auglydd);CHKERRQ(ierr); 289d4002b98SHong Zhang ierr = VecGetLocalSize(auglyoo,&n);CHKERRQ(ierr); 290d4002b98SHong Zhang ierr = VecGetArray(auglyoo,&o);CHKERRQ(ierr); 291d4002b98SHong Zhang for (i=0; i<n; i++) { 292d4002b98SHong Zhang o[i] = s[auglyrmapo[i]]; /* copy "off-diagonal" portion of scale into oo vector */ 293d4002b98SHong Zhang } 294d4002b98SHong Zhang ierr = VecRestoreArrayRead(scale,&s);CHKERRQ(ierr); 295d4002b98SHong Zhang ierr = VecRestoreArray(auglyoo,&o);CHKERRQ(ierr); 296d4002b98SHong Zhang /* column scale "off-diagonal" portion of local matrix */ 297d4002b98SHong Zhang ierr = MatDiagonalScale(a->B,NULL,auglyoo);CHKERRQ(ierr); 298d4002b98SHong Zhang PetscFunctionReturn(0); 299d4002b98SHong Zhang } 300