1df826632SBarry Smith 2df826632SBarry Smith /* 3df826632SBarry Smith This file defines a "solve the problem redistributely on each subgroup of processor" preconditioner. 4df826632SBarry Smith */ 5af0996ceSBarry Smith #include <petsc/private/pcimpl.h> /*I "petscksp.h" I*/ 6c6db04a5SJed Brown #include <petscksp.h> 7df826632SBarry Smith 869ff637eSBarry Smith typedef struct _PC_FieldSplitLink *PC_FieldSplitLink; 969ff637eSBarry Smith struct _PC_FieldSplitLink { 1069ff637eSBarry Smith char *splitname; 1169ff637eSBarry Smith IS is; 1269ff637eSBarry Smith PC_FieldSplitLink next, previous; 1369ff637eSBarry Smith }; 1469ff637eSBarry Smith 15df826632SBarry Smith typedef struct { 16df826632SBarry Smith KSP ksp; 17df826632SBarry Smith Vec x, b; 18df826632SBarry Smith VecScatter scatter; 19911f9fe8SBarry Smith IS is; 20181dd334SBarry Smith PetscInt dcnt, *drows; /* these are the local rows that have only diagonal entry */ 21181dd334SBarry Smith PetscScalar *diag; 22181dd334SBarry Smith Vec work; 2387b47708SBarry Smith PetscBool zerodiag; 2469ff637eSBarry Smith 2569ff637eSBarry Smith PetscInt nsplits; 2669ff637eSBarry Smith PC_FieldSplitLink splitlinks; 27df826632SBarry Smith } PC_Redistribute; 28df826632SBarry Smith 2969ff637eSBarry Smith static PetscErrorCode PCFieldSplitSetIS_Redistribute(PC pc, const char splitname[], IS is) 3069ff637eSBarry Smith { 3169ff637eSBarry Smith PC_Redistribute *red = (PC_Redistribute *)pc->data; 3269ff637eSBarry Smith PC_FieldSplitLink *next = &red->splitlinks; 3369ff637eSBarry Smith 3469ff637eSBarry Smith PetscFunctionBegin; 3569ff637eSBarry Smith while (*next) next = &(*next)->next; 3669ff637eSBarry Smith PetscCall(PetscNew(next)); 3769ff637eSBarry Smith if (splitname) { 3869ff637eSBarry Smith PetscCall(PetscStrallocpy(splitname, &(*next)->splitname)); 3969ff637eSBarry Smith } else { 4069ff637eSBarry Smith PetscCall(PetscMalloc1(8, &(*next)->splitname)); 4169ff637eSBarry Smith PetscCall(PetscSNPrintf((*next)->splitname, 7, "%" PetscInt_FMT, red->nsplits++)); 4269ff637eSBarry Smith } 4369ff637eSBarry Smith PetscCall(PetscObjectReference((PetscObject)is)); 4469ff637eSBarry Smith PetscCall(ISDestroy(&(*next)->is)); 4569ff637eSBarry Smith (*next)->is = is; 4669ff637eSBarry Smith PetscFunctionReturn(PETSC_SUCCESS); 4769ff637eSBarry Smith } 4869ff637eSBarry Smith 49d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCView_Redistribute(PC pc, PetscViewer viewer) 50d71ae5a4SJacob Faibussowitsch { 51df826632SBarry Smith PC_Redistribute *red = (PC_Redistribute *)pc->data; 52ace3abfcSBarry Smith PetscBool iascii, isstring; 53181dd334SBarry Smith PetscInt ncnt, N; 54df826632SBarry Smith 55df826632SBarry Smith PetscFunctionBegin; 569566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 579566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring)); 58df826632SBarry Smith if (iascii) { 591c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(&red->dcnt, &ncnt, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)pc))); 609566063dSJacob Faibussowitsch PetscCall(MatGetSize(pc->pmat, &N, NULL)); 6163a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Number rows eliminated %" PetscInt_FMT " Percentage rows eliminated %g\n", ncnt, (double)(100.0 * ((PetscReal)ncnt) / ((PetscReal)N)))); 629566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, " Redistribute preconditioner: \n")); 639566063dSJacob Faibussowitsch PetscCall(KSPView(red->ksp, viewer)); 64df826632SBarry Smith } else if (isstring) { 659566063dSJacob Faibussowitsch PetscCall(PetscViewerStringSPrintf(viewer, " Redistribute preconditioner")); 669566063dSJacob Faibussowitsch PetscCall(KSPView(red->ksp, viewer)); 6711aeaf0aSBarry Smith } 683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 69df826632SBarry Smith } 70df826632SBarry Smith 71d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUp_Redistribute(PC pc) 72d71ae5a4SJacob Faibussowitsch { 73df826632SBarry Smith PC_Redistribute *red = (PC_Redistribute *)pc->data; 74df826632SBarry Smith MPI_Comm comm; 7569ff637eSBarry Smith PetscInt rstart, rend, nrstart, nrend, i, nz, cnt, *rows, ncnt, dcnt, *drows; 7626283091SBarry Smith PetscLayout map, nmap; 77ec4bef21SJose E. Roman PetscMPIInt size, tag, n; 78ec4bef21SJose E. Roman PETSC_UNUSED PetscMPIInt imdex; 790298fd71SBarry Smith PetscInt *source = NULL; 8076ec1555SBarry Smith PetscMPIInt *sizes = NULL, nrecvs; 81df826632SBarry Smith PetscInt j, nsends; 820298fd71SBarry Smith PetscInt *owner = NULL, *starts = NULL, count, slen; 83e8dd6687SHong Zhang PetscInt *rvalues, *svalues, recvtotal; 84df826632SBarry Smith PetscMPIInt *onodes1, *olengths1; 850298fd71SBarry Smith MPI_Request *send_waits = NULL, *recv_waits = NULL; 86df826632SBarry Smith MPI_Status recv_status, *send_status; 87181dd334SBarry Smith Vec tvec, diag; 88ca320bd4SBarry Smith Mat tmat; 89003249c0SBarry Smith const PetscScalar *d, *values; 90003249c0SBarry Smith const PetscInt *cols; 9169ff637eSBarry Smith PC_FieldSplitLink *next = &red->splitlinks; 92df826632SBarry Smith 93df826632SBarry Smith PetscFunctionBegin; 94dc9360f3SBarry Smith if (pc->setupcalled) { 9569ff637eSBarry Smith PetscCheck(pc->flag == SAME_NONZERO_PATTERN, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "PC is not supported for a change in the nonzero structure of the matrix"); 969566063dSJacob Faibussowitsch PetscCall(KSPGetOperators(red->ksp, NULL, &tmat)); 979566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(pc->pmat, red->is, red->is, MAT_REUSE_MATRIX, &tmat)); 989566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(red->ksp, tmat, tmat)); 99dc9360f3SBarry Smith } else { 100b862ddfaSBarry Smith PetscInt NN; 10169ff637eSBarry Smith PC ipc; 10269ff637eSBarry Smith PetscVoidFunction fptr; 103b862ddfaSBarry Smith 1049566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)pc, &comm)); 1059566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(comm, &size)); 1069566063dSJacob Faibussowitsch PetscCall(PetscObjectGetNewTag((PetscObject)pc, &tag)); 107df826632SBarry Smith 108ca320bd4SBarry Smith /* count non-diagonal rows on process */ 1099566063dSJacob Faibussowitsch PetscCall(MatGetOwnershipRange(pc->mat, &rstart, &rend)); 110ca320bd4SBarry Smith cnt = 0; 111df826632SBarry Smith for (i = rstart; i < rend; i++) { 1129566063dSJacob Faibussowitsch PetscCall(MatGetRow(pc->mat, i, &nz, &cols, &values)); 113003249c0SBarry Smith for (PetscInt j = 0; j < nz; j++) { 114003249c0SBarry Smith if (values[j] != 0 && cols[j] != i) { 115003249c0SBarry Smith cnt++; 116003249c0SBarry Smith break; 117003249c0SBarry Smith } 118003249c0SBarry Smith } 1199566063dSJacob Faibussowitsch PetscCall(MatRestoreRow(pc->mat, i, &nz, &cols, &values)); 120df826632SBarry Smith } 1219566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(cnt, &rows)); 1229566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(rend - rstart - cnt, &drows)); 123ca320bd4SBarry Smith 124ca320bd4SBarry Smith /* list non-diagonal rows on process */ 1259371c9d4SSatish Balay cnt = 0; 1269371c9d4SSatish Balay dcnt = 0; 127df826632SBarry Smith for (i = rstart; i < rend; i++) { 128003249c0SBarry Smith PetscBool diagonly = PETSC_TRUE; 1299566063dSJacob Faibussowitsch PetscCall(MatGetRow(pc->mat, i, &nz, &cols, &values)); 130003249c0SBarry Smith for (PetscInt j = 0; j < nz; j++) { 131003249c0SBarry Smith if (values[j] != 0 && cols[j] != i) { 132003249c0SBarry Smith diagonly = PETSC_FALSE; 133003249c0SBarry Smith break; 134003249c0SBarry Smith } 135003249c0SBarry Smith } 136003249c0SBarry Smith if (!diagonly) rows[cnt++] = i; 137181dd334SBarry Smith else drows[dcnt++] = i - rstart; 1389566063dSJacob Faibussowitsch PetscCall(MatRestoreRow(pc->mat, i, &nz, &cols, &values)); 139df826632SBarry Smith } 140ca320bd4SBarry Smith 14126283091SBarry Smith /* create PetscLayout for non-diagonal rows on each process */ 1429566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(comm, &map)); 1439566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(map, cnt)); 1449566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(map, 1)); 1459566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(map)); 14669ff637eSBarry Smith nrstart = map->rstart; 14769ff637eSBarry Smith nrend = map->rend; 148df826632SBarry Smith 14926283091SBarry Smith /* create PetscLayout for load-balanced non-diagonal rows on each process */ 1509566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(comm, &nmap)); 1511c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(&cnt, &ncnt, 1, MPIU_INT, MPI_SUM, comm)); 1529566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetSize(nmap, ncnt)); 1539566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(nmap, 1)); 1549566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(nmap)); 155df826632SBarry Smith 1569566063dSJacob Faibussowitsch PetscCall(MatGetSize(pc->pmat, &NN, NULL)); 15763a3b9bcSJacob Faibussowitsch PetscCall(PetscInfo(pc, "Number of diagonal rows eliminated %" PetscInt_FMT ", percentage eliminated %g\n", NN - ncnt, (double)(((PetscReal)(NN - ncnt)) / ((PetscReal)(NN))))); 158003249c0SBarry Smith 159003249c0SBarry Smith if (size > 1) { 160ca320bd4SBarry Smith /* 16169ff637eSBarry Smith the following block of code assumes MPI can send messages to self, which is not supported for MPI-uni hence we need to handle 16269ff637eSBarry Smith the size 1 case as a special case 16369ff637eSBarry Smith 164ca320bd4SBarry Smith this code is taken from VecScatterCreate_PtoS() 165ca320bd4SBarry Smith Determines what rows need to be moved where to 166ca320bd4SBarry Smith load balance the non-diagonal rows 167ca320bd4SBarry Smith */ 168df826632SBarry Smith /* count number of contributors to each processor */ 1699566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(size, &sizes, cnt, &owner)); 1709566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(sizes, size)); 171df826632SBarry Smith j = 0; 172df826632SBarry Smith nsends = 0; 17369ff637eSBarry Smith for (i = nrstart; i < nrend; i++) { 174df826632SBarry Smith if (i < nmap->range[j]) j = 0; 175df826632SBarry Smith for (; j < size; j++) { 176df826632SBarry Smith if (i < nmap->range[j + 1]) { 17776ec1555SBarry Smith if (!sizes[j]++) nsends++; 17869ff637eSBarry Smith owner[i - nrstart] = j; 179df826632SBarry Smith break; 180df826632SBarry Smith } 181df826632SBarry Smith } 182df826632SBarry Smith } 183df826632SBarry Smith /* inform other processors of number of messages and max length*/ 1849566063dSJacob Faibussowitsch PetscCall(PetscGatherNumberOfMessages(comm, NULL, sizes, &nrecvs)); 1859566063dSJacob Faibussowitsch PetscCall(PetscGatherMessageLengths(comm, nsends, nrecvs, sizes, &onodes1, &olengths1)); 1869566063dSJacob Faibussowitsch PetscCall(PetscSortMPIIntWithArray(nrecvs, onodes1, olengths1)); 1879371c9d4SSatish Balay recvtotal = 0; 1889371c9d4SSatish Balay for (i = 0; i < nrecvs; i++) recvtotal += olengths1[i]; 189df826632SBarry Smith 190df826632SBarry Smith /* post receives: rvalues - rows I will own; count - nu */ 1919566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(recvtotal, &rvalues, nrecvs, &source, nrecvs, &recv_waits)); 192df826632SBarry Smith count = 0; 193df826632SBarry Smith for (i = 0; i < nrecvs; i++) { 1949566063dSJacob Faibussowitsch PetscCallMPI(MPI_Irecv((rvalues + count), olengths1[i], MPIU_INT, onodes1[i], tag, comm, recv_waits + i)); 195df826632SBarry Smith count += olengths1[i]; 196df826632SBarry Smith } 197df826632SBarry Smith 198df826632SBarry Smith /* do sends: 199df826632SBarry Smith 1) starts[i] gives the starting index in svalues for stuff going to 200df826632SBarry Smith the ith processor 201df826632SBarry Smith */ 2029566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(cnt, &svalues, nsends, &send_waits, size, &starts)); 203df826632SBarry Smith starts[0] = 0; 20476ec1555SBarry Smith for (i = 1; i < size; i++) starts[i] = starts[i - 1] + sizes[i - 1]; 2052fa5cd67SKarl Rupp for (i = 0; i < cnt; i++) svalues[starts[owner[i]]++] = rows[i]; 20669ff637eSBarry Smith for (i = 0; i < cnt; i++) rows[i] = rows[i] - nrstart; 207181dd334SBarry Smith red->drows = drows; 208181dd334SBarry Smith red->dcnt = dcnt; 2099566063dSJacob Faibussowitsch PetscCall(PetscFree(rows)); 210181dd334SBarry Smith 211df826632SBarry Smith starts[0] = 0; 21276ec1555SBarry Smith for (i = 1; i < size; i++) starts[i] = starts[i - 1] + sizes[i - 1]; 213df826632SBarry Smith count = 0; 214df826632SBarry Smith for (i = 0; i < size; i++) { 21548a46eb9SPierre Jolivet if (sizes[i]) PetscCallMPI(MPI_Isend(svalues + starts[i], sizes[i], MPIU_INT, i, tag, comm, send_waits + count++)); 216df826632SBarry Smith } 217df826632SBarry Smith 218df826632SBarry Smith /* wait on receives */ 219df826632SBarry Smith count = nrecvs; 220df826632SBarry Smith slen = 0; 221df826632SBarry Smith while (count) { 2229566063dSJacob Faibussowitsch PetscCallMPI(MPI_Waitany(nrecvs, recv_waits, &imdex, &recv_status)); 223df826632SBarry Smith /* unpack receives into our local space */ 2249566063dSJacob Faibussowitsch PetscCallMPI(MPI_Get_count(&recv_status, MPIU_INT, &n)); 225df826632SBarry Smith slen += n; 226df826632SBarry Smith count--; 227df826632SBarry Smith } 22863a3b9bcSJacob Faibussowitsch PetscCheck(slen == recvtotal, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total message lengths %" PetscInt_FMT " not expected %" PetscInt_FMT, slen, recvtotal); 2299566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(comm, slen, rvalues, PETSC_COPY_VALUES, &red->is)); 230911f9fe8SBarry Smith 231003249c0SBarry Smith /* free all work space */ 2329566063dSJacob Faibussowitsch PetscCall(PetscFree(olengths1)); 2339566063dSJacob Faibussowitsch PetscCall(PetscFree(onodes1)); 2349566063dSJacob Faibussowitsch PetscCall(PetscFree3(rvalues, source, recv_waits)); 2359566063dSJacob Faibussowitsch PetscCall(PetscFree2(sizes, owner)); 236ca320bd4SBarry Smith if (nsends) { /* wait on sends */ 2379566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(nsends, &send_status)); 2389566063dSJacob Faibussowitsch PetscCallMPI(MPI_Waitall(nsends, send_waits, send_status)); 2399566063dSJacob Faibussowitsch PetscCall(PetscFree(send_status)); 240df826632SBarry Smith } 2419566063dSJacob Faibussowitsch PetscCall(PetscFree3(svalues, send_waits, starts)); 242003249c0SBarry Smith } else { 2439566063dSJacob Faibussowitsch PetscCall(ISCreateGeneral(comm, cnt, rows, PETSC_OWN_POINTER, &red->is)); 244003249c0SBarry Smith red->drows = drows; 245003249c0SBarry Smith red->dcnt = dcnt; 246003249c0SBarry Smith slen = cnt; 247003249c0SBarry Smith } 2489566063dSJacob Faibussowitsch PetscCall(PetscLayoutDestroy(&map)); 249df826632SBarry Smith 2509566063dSJacob Faibussowitsch PetscCall(VecCreateMPI(comm, slen, PETSC_DETERMINE, &red->b)); 2519566063dSJacob Faibussowitsch PetscCall(VecDuplicate(red->b, &red->x)); 2529566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(pc->pmat, &tvec, NULL)); 2539566063dSJacob Faibussowitsch PetscCall(VecScatterCreate(tvec, red->is, red->b, NULL, &red->scatter)); 25469ff637eSBarry Smith 25569ff637eSBarry Smith /* Map the PCFIELDSPLIT fields to redistributed KSP */ 25669ff637eSBarry Smith PetscCall(KSPGetPC(red->ksp, &ipc)); 25769ff637eSBarry Smith PetscCall(PetscObjectQueryFunction((PetscObject)ipc, "PCFieldSplitSetIS_C", &fptr)); 25869ff637eSBarry Smith if (fptr && *next) { 25969ff637eSBarry Smith PetscScalar *atvec; 26069ff637eSBarry Smith const PetscScalar *ab; 26169ff637eSBarry Smith PetscInt primes[] = {2, 3, 5, 7, 11, 13, 17, 19}; 26269ff637eSBarry Smith PetscInt cnt = 0; 26369ff637eSBarry Smith 26469ff637eSBarry Smith PetscCheck(red->nsplits <= (PetscInt)PETSC_STATIC_ARRAY_LENGTH(primes), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No support for this many fields"); 26569ff637eSBarry Smith PetscCall(VecSet(tvec, 1.0)); 26669ff637eSBarry Smith PetscCall(VecGetArray(tvec, &atvec)); 26769ff637eSBarry Smith 26869ff637eSBarry Smith while (*next) { 26969ff637eSBarry Smith const PetscInt *indices; 27069ff637eSBarry Smith PetscInt n; 27169ff637eSBarry Smith 27269ff637eSBarry Smith PetscCall(ISGetIndices((*next)->is, &indices)); 27369ff637eSBarry Smith PetscCall(ISGetLocalSize((*next)->is, &n)); 27469ff637eSBarry Smith for (PetscInt i = 0; i < n; i++) atvec[indices[i] - rstart] *= primes[cnt]; 27569ff637eSBarry Smith PetscCall(ISRestoreIndices((*next)->is, &indices)); 27669ff637eSBarry Smith cnt++; 27769ff637eSBarry Smith next = &(*next)->next; 27869ff637eSBarry Smith } 27969ff637eSBarry Smith PetscCall(VecRestoreArray(tvec, &atvec)); 28069ff637eSBarry Smith PetscCall(VecScatterBegin(red->scatter, tvec, red->b, INSERT_VALUES, SCATTER_FORWARD)); 28169ff637eSBarry Smith PetscCall(VecScatterEnd(red->scatter, tvec, red->b, INSERT_VALUES, SCATTER_FORWARD)); 28269ff637eSBarry Smith cnt = 0; 28369ff637eSBarry Smith PetscCall(VecGetArrayRead(red->b, &ab)); 28469ff637eSBarry Smith next = &red->splitlinks; 28569ff637eSBarry Smith while (*next) { 28669ff637eSBarry Smith PetscInt n = 0; 28769ff637eSBarry Smith PetscInt *indices; 28869ff637eSBarry Smith IS ris; 28969ff637eSBarry Smith 29069ff637eSBarry Smith for (PetscInt i = 0; i < nmap->rend - nmap->rstart; i++) { 29169ff637eSBarry Smith if (!(((PetscInt)PetscRealPart(ab[i])) % primes[cnt])) n++; 29269ff637eSBarry Smith } 29369ff637eSBarry Smith PetscCall(PetscMalloc1(n, &indices)); 29469ff637eSBarry Smith n = 0; 29569ff637eSBarry Smith for (PetscInt i = 0; i < nmap->rend - nmap->rstart; i++) { 29669ff637eSBarry Smith if (!(((PetscInt)PetscRealPart(ab[i])) % primes[cnt])) indices[n++] = i + nmap->rstart; 29769ff637eSBarry Smith } 29869ff637eSBarry Smith PetscCall(ISCreateGeneral(comm, n, indices, PETSC_OWN_POINTER, &ris)); 29969ff637eSBarry Smith PetscCall(PCFieldSplitSetIS(ipc, (*next)->splitname, ris)); 30069ff637eSBarry Smith 30169ff637eSBarry Smith PetscCall(ISDestroy(&ris)); 30269ff637eSBarry Smith cnt++; 30369ff637eSBarry Smith next = &(*next)->next; 30469ff637eSBarry Smith } 30569ff637eSBarry Smith PetscCall(VecRestoreArrayRead(red->b, &ab)); 30669ff637eSBarry Smith } 3079566063dSJacob Faibussowitsch PetscCall(VecDestroy(&tvec)); 3089566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrix(pc->pmat, red->is, red->is, MAT_INITIAL_MATRIX, &tmat)); 3099566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(red->ksp, tmat, tmat)); 3109566063dSJacob Faibussowitsch PetscCall(MatDestroy(&tmat)); 31169ff637eSBarry Smith PetscCall(PetscLayoutDestroy(&nmap)); 3121d805cfdSBarry Smith } 313181dd334SBarry Smith 314181dd334SBarry Smith /* get diagonal portion of matrix */ 3159566063dSJacob Faibussowitsch PetscCall(PetscFree(red->diag)); 3169566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(red->dcnt, &red->diag)); 3179566063dSJacob Faibussowitsch PetscCall(MatCreateVecs(pc->pmat, &diag, NULL)); 3189566063dSJacob Faibussowitsch PetscCall(MatGetDiagonal(pc->pmat, diag)); 3199566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(diag, &d)); 32087b47708SBarry Smith for (i = 0; i < red->dcnt; i++) { 32187b47708SBarry Smith if (d[red->drows[i]] != 0) red->diag[i] = 1.0 / d[red->drows[i]]; 32287b47708SBarry Smith else { 32387b47708SBarry Smith red->zerodiag = PETSC_TRUE; 32487b47708SBarry Smith red->diag[i] = 0.0; 32587b47708SBarry Smith } 32687b47708SBarry Smith } 3279566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(diag, &d)); 3289566063dSJacob Faibussowitsch PetscCall(VecDestroy(&diag)); 3299566063dSJacob Faibussowitsch PetscCall(KSPSetUp(red->ksp)); 3303ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 331df826632SBarry Smith } 332df826632SBarry Smith 333d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_Redistribute(PC pc, Vec b, Vec x) 334d71ae5a4SJacob Faibussowitsch { 335df826632SBarry Smith PC_Redistribute *red = (PC_Redistribute *)pc->data; 336181dd334SBarry Smith PetscInt dcnt = red->dcnt, i; 337181dd334SBarry Smith const PetscInt *drows = red->drows; 338181dd334SBarry Smith PetscScalar *xwork; 339181dd334SBarry Smith const PetscScalar *bwork, *diag = red->diag; 340df826632SBarry Smith 341df826632SBarry Smith PetscFunctionBegin; 34248a46eb9SPierre Jolivet if (!red->work) PetscCall(VecDuplicate(b, &red->work)); 343181dd334SBarry Smith /* compute the rows of solution that have diagonal entries only */ 3449566063dSJacob Faibussowitsch PetscCall(VecSet(x, 0.0)); /* x = diag(A)^{-1} b */ 3459566063dSJacob Faibussowitsch PetscCall(VecGetArray(x, &xwork)); 3469566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(b, &bwork)); 34787b47708SBarry Smith if (red->zerodiag) { 34887b47708SBarry Smith for (i = 0; i < dcnt; i++) { 34987b47708SBarry Smith if (diag[i] == 0.0 && bwork[drows[i]] != 0.0) { 35087b47708SBarry Smith PetscCheck(!pc->erroriffailure, PETSC_COMM_SELF, PETSC_ERR_CONV_FAILED, "Linear system is inconsistent, zero matrix row but nonzero right hand side"); 35187b47708SBarry Smith PetscCall(PetscInfo(pc, "Linear system is inconsistent, zero matrix row but nonzero right hand side")); 35287b47708SBarry Smith PetscCall(VecSetInf(x)); 35387b47708SBarry Smith pc->failedreasonrank = PC_INCONSISTENT_RHS; 35487b47708SBarry Smith } 35587b47708SBarry Smith } 35687b47708SBarry Smith } 3572fa5cd67SKarl Rupp for (i = 0; i < dcnt; i++) xwork[drows[i]] = diag[i] * bwork[drows[i]]; 3589566063dSJacob Faibussowitsch PetscCall(PetscLogFlops(dcnt)); 3599566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(red->work, &xwork)); 3609566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(b, &bwork)); 361181dd334SBarry Smith /* update the right hand side for the reduced system with diagonal rows (and corresponding columns) removed */ 3629566063dSJacob Faibussowitsch PetscCall(MatMult(pc->pmat, x, red->work)); 3639566063dSJacob Faibussowitsch PetscCall(VecAYPX(red->work, -1.0, b)); /* red->work = b - A x */ 364181dd334SBarry Smith 3659566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(red->scatter, red->work, red->b, INSERT_VALUES, SCATTER_FORWARD)); 3669566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(red->scatter, red->work, red->b, INSERT_VALUES, SCATTER_FORWARD)); 3679566063dSJacob Faibussowitsch PetscCall(KSPSolve(red->ksp, red->b, red->x)); 3689566063dSJacob Faibussowitsch PetscCall(KSPCheckSolve(red->ksp, pc, red->x)); 3699566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(red->scatter, red->x, x, INSERT_VALUES, SCATTER_REVERSE)); 3709566063dSJacob Faibussowitsch PetscCall(VecScatterEnd(red->scatter, red->x, x, INSERT_VALUES, SCATTER_REVERSE)); 3713ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 372df826632SBarry Smith } 373df826632SBarry Smith 374d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_Redistribute(PC pc) 375d71ae5a4SJacob Faibussowitsch { 376df826632SBarry Smith PC_Redistribute *red = (PC_Redistribute *)pc->data; 37769ff637eSBarry Smith PC_FieldSplitLink next = red->splitlinks; 378df826632SBarry Smith 379df826632SBarry Smith PetscFunctionBegin; 38069ff637eSBarry Smith PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", NULL)); 38169ff637eSBarry Smith 38269ff637eSBarry Smith while (next) { 38369ff637eSBarry Smith PC_FieldSplitLink ilink; 38469ff637eSBarry Smith PetscCall(PetscFree(next->splitname)); 38569ff637eSBarry Smith PetscCall(ISDestroy(&next->is)); 38669ff637eSBarry Smith ilink = next; 38769ff637eSBarry Smith next = next->next; 38869ff637eSBarry Smith PetscCall(PetscFree(ilink)); 38969ff637eSBarry Smith } 3909566063dSJacob Faibussowitsch PetscCall(VecScatterDestroy(&red->scatter)); 3919566063dSJacob Faibussowitsch PetscCall(ISDestroy(&red->is)); 3929566063dSJacob Faibussowitsch PetscCall(VecDestroy(&red->b)); 3939566063dSJacob Faibussowitsch PetscCall(VecDestroy(&red->x)); 3949566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&red->ksp)); 3959566063dSJacob Faibussowitsch PetscCall(VecDestroy(&red->work)); 3969566063dSJacob Faibussowitsch PetscCall(PetscFree(red->drows)); 3979566063dSJacob Faibussowitsch PetscCall(PetscFree(red->diag)); 3989566063dSJacob Faibussowitsch PetscCall(PetscFree(pc->data)); 3993ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 400df826632SBarry Smith } 401df826632SBarry Smith 402d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetFromOptions_Redistribute(PC pc, PetscOptionItems *PetscOptionsObject) 403d71ae5a4SJacob Faibussowitsch { 404df826632SBarry Smith PC_Redistribute *red = (PC_Redistribute *)pc->data; 405df826632SBarry Smith 406df826632SBarry Smith PetscFunctionBegin; 4079566063dSJacob Faibussowitsch PetscCall(KSPSetFromOptions(red->ksp)); 4083ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 409df826632SBarry Smith } 410df826632SBarry Smith 4115e7ef714SBarry Smith /*@ 412f1580f4eSBarry Smith PCRedistributeGetKSP - Gets the `KSP` created by the `PCREDISTRIBUTE` 4135e7ef714SBarry Smith 4145e7ef714SBarry Smith Not Collective 4155e7ef714SBarry Smith 4165e7ef714SBarry Smith Input Parameter: 4175e7ef714SBarry Smith . pc - the preconditioner context 4185e7ef714SBarry Smith 4195e7ef714SBarry Smith Output Parameter: 420f1580f4eSBarry Smith . innerksp - the inner `KSP` 4215e7ef714SBarry Smith 4225e7ef714SBarry Smith Level: advanced 4235e7ef714SBarry Smith 424f1580f4eSBarry Smith .seealso: `KSP`, `PCREDISTRIBUTE` 4255e7ef714SBarry Smith @*/ 426d71ae5a4SJacob Faibussowitsch PetscErrorCode PCRedistributeGetKSP(PC pc, KSP *innerksp) 427d71ae5a4SJacob Faibussowitsch { 4285e7ef714SBarry Smith PC_Redistribute *red = (PC_Redistribute *)pc->data; 4295e7ef714SBarry Smith 4305e7ef714SBarry Smith PetscFunctionBegin; 4315e7ef714SBarry Smith PetscValidHeaderSpecific(pc, PC_CLASSID, 1); 4324f572ea9SToby Isaac PetscAssertPointer(innerksp, 2); 4335e7ef714SBarry Smith *innerksp = red->ksp; 4343ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 4355e7ef714SBarry Smith } 4365e7ef714SBarry Smith 437df826632SBarry Smith /*MC 4387caa67d9SBarry Smith PCREDISTRIBUTE - Redistributes a matrix for load balancing, removing the rows (and the corresponding columns) that only have a diagonal entry and then 439f1580f4eSBarry Smith applies a `KSP` to that new smaller matrix 440df826632SBarry Smith 4417df6f684SBarry Smith Level: intermediate 4427df6f684SBarry Smith 44395452b02SPatrick Sanan Notes: 444f1580f4eSBarry Smith Options for the redistribute `KSP` and `PC` with the options database prefix -redistribute_ 445f1580f4eSBarry Smith 4467df6f684SBarry Smith Usually run this with `-ksp_type preonly` 447181dd334SBarry Smith 4487df6f684SBarry Smith If you have used `MatZeroRows()` to eliminate (for example, Dirichlet) boundary conditions for a symmetric problem then you can use, for example, `-ksp_type preonly 4497df6f684SBarry Smith -pc_type redistribute -redistribute_ksp_type cg -redistribute_pc_type bjacobi -redistribute_sub_pc_type icc` to take advantage of the symmetry. 450181dd334SBarry Smith 45169ff637eSBarry Smith Supports the function `PCFieldSplitSetIS()`; passs the appropriate reduced field indices to an inner `PCFIELDSPLIT`, set with, for example 45269ff637eSBarry Smith `-ksp_type preonly -pc_type redistribute -redistribute_pc_type fieldsplit. Does not support the `PCFIELDSPLIT` options database keys. 45369ff637eSBarry Smith 4547df6f684SBarry Smith This does NOT call a partitioner to reorder rows to lower communication; the ordering of the rows in the original matrix and redistributed matrix is the same. Rows are moved 4557df6f684SBarry Smith between MPI processes inside the preconditioner to balance the number of rows on each process. 4562dfef595SBarry Smith 457f1580f4eSBarry Smith Developer Note: 45895452b02SPatrick Sanan Should add an option to this preconditioner to use a partitioner to redistribute the rows to lower communication. 4592dfef595SBarry Smith 46069ff637eSBarry Smith .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PCRedistributeGetKSP()`, `MatZeroRows()`, `PCFieldSplitSetIS()`, `PCFIELDSPLIT` 461df826632SBarry Smith M*/ 462df826632SBarry Smith 463d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_Redistribute(PC pc) 464d71ae5a4SJacob Faibussowitsch { 465df826632SBarry Smith PC_Redistribute *red; 466911f9fe8SBarry Smith const char *prefix; 467df826632SBarry Smith 468df826632SBarry Smith PetscFunctionBegin; 4694dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&red)); 470df826632SBarry Smith pc->data = (void *)red; 471df826632SBarry Smith 472df826632SBarry Smith pc->ops->apply = PCApply_Redistribute; 4730a545947SLisandro Dalcin pc->ops->applytranspose = NULL; 474df826632SBarry Smith pc->ops->setup = PCSetUp_Redistribute; 475df826632SBarry Smith pc->ops->destroy = PCDestroy_Redistribute; 476df826632SBarry Smith pc->ops->setfromoptions = PCSetFromOptions_Redistribute; 477df826632SBarry Smith pc->ops->view = PCView_Redistribute; 478911f9fe8SBarry Smith 4799566063dSJacob Faibussowitsch PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &red->ksp)); 480*3821be0aSBarry Smith PetscCall(KSPSetNestLevel(red->ksp, pc->kspnestlevel)); 4819566063dSJacob Faibussowitsch PetscCall(KSPSetErrorIfNotConverged(red->ksp, pc->erroriffailure)); 4829566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)red->ksp, (PetscObject)pc, 1)); 4839566063dSJacob Faibussowitsch PetscCall(PCGetOptionsPrefix(pc, &prefix)); 4849566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(red->ksp, prefix)); 4859566063dSJacob Faibussowitsch PetscCall(KSPAppendOptionsPrefix(red->ksp, "redistribute_")); 48669ff637eSBarry Smith PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", PCFieldSplitSetIS_Redistribute)); 4873ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 488df826632SBarry Smith } 489