14b9ad928SBarry Smith 2c6db04a5SJed Brown #include <../src/ksp/pc/impls/is/nn/nn.h> 34b9ad928SBarry Smith 44b9ad928SBarry Smith /* -------------------------------------------------------------------------- */ 54b9ad928SBarry Smith /* 64b9ad928SBarry Smith PCSetUp_NN - Prepares for the use of the NN preconditioner 74b9ad928SBarry Smith by setting data structures and options. 84b9ad928SBarry Smith 94b9ad928SBarry Smith Input Parameter: 104b9ad928SBarry Smith . pc - the preconditioner context 114b9ad928SBarry Smith 124b9ad928SBarry Smith Application Interface Routine: PCSetUp() 134b9ad928SBarry Smith 144b9ad928SBarry Smith Notes: 154b9ad928SBarry Smith The interface routine PCSetUp() is not usually called directly by 164b9ad928SBarry Smith the user, but instead is called by PCApply() if necessary. 174b9ad928SBarry Smith */ 186849ba73SBarry Smith static PetscErrorCode PCSetUp_NN(PC pc) 194b9ad928SBarry Smith { 204b9ad928SBarry Smith PetscFunctionBegin; 214b9ad928SBarry Smith if (!pc->setupcalled) { 224b9ad928SBarry Smith /* Set up all the "iterative substructuring" common block */ 23*9566063dSJacob Faibussowitsch PetscCall(PCISSetUp(pc,PETSC_TRUE,PETSC_TRUE)); 244b9ad928SBarry Smith /* Create the coarse matrix. */ 25*9566063dSJacob Faibussowitsch PetscCall(PCNNCreateCoarseMatrix(pc)); 264b9ad928SBarry Smith } 274b9ad928SBarry Smith PetscFunctionReturn(0); 284b9ad928SBarry Smith } 294b9ad928SBarry Smith 304b9ad928SBarry Smith /* -------------------------------------------------------------------------- */ 314b9ad928SBarry Smith /* 324b9ad928SBarry Smith PCApply_NN - Applies the NN preconditioner to a vector. 334b9ad928SBarry Smith 344b9ad928SBarry Smith Input Parameters: 354b9ad928SBarry Smith . pc - the preconditioner context 364b9ad928SBarry Smith . r - input vector (global) 374b9ad928SBarry Smith 384b9ad928SBarry Smith Output Parameter: 394b9ad928SBarry Smith . z - output vector (global) 404b9ad928SBarry Smith 414b9ad928SBarry Smith Application Interface Routine: PCApply() 424b9ad928SBarry Smith */ 436849ba73SBarry Smith static PetscErrorCode PCApply_NN(PC pc,Vec r,Vec z) 444b9ad928SBarry Smith { 454b9ad928SBarry Smith PC_IS *pcis = (PC_IS*)(pc->data); 46dfbe8321SBarry Smith PetscErrorCode ierr; 474b9ad928SBarry Smith PetscScalar m_one = -1.0; 484b9ad928SBarry Smith Vec w = pcis->vec1_global; 494b9ad928SBarry Smith 504b9ad928SBarry Smith PetscFunctionBegin; 514b9ad928SBarry Smith /* 524b9ad928SBarry Smith Dirichlet solvers. 534b9ad928SBarry Smith Solving $ B_I^{(i)}r_I^{(i)} $ at each processor. 544b9ad928SBarry Smith Storing the local results at vec2_D 554b9ad928SBarry Smith */ 56*9566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD)); 57*9566063dSJacob Faibussowitsch PetscCall(VecScatterEnd (pcis->global_to_D,r,pcis->vec1_D,INSERT_VALUES,SCATTER_FORWARD)); 58*9566063dSJacob Faibussowitsch PetscCall(KSPSolve(pcis->ksp_D,pcis->vec1_D,pcis->vec2_D)); 594b9ad928SBarry Smith 604b9ad928SBarry Smith /* 614b9ad928SBarry Smith Computing $ r_B - \sum_j \tilde R_j^T A_{BI}^{(j)} (B_I^{(j)}r_I^{(j)}) $ . 624b9ad928SBarry Smith Storing the result in the interface portion of the global vector w. 634b9ad928SBarry Smith */ 64*9566063dSJacob Faibussowitsch PetscCall(MatMult(pcis->A_BI,pcis->vec2_D,pcis->vec1_B)); 65*9566063dSJacob Faibussowitsch PetscCall(VecScale(pcis->vec1_B,m_one)); 66*9566063dSJacob Faibussowitsch PetscCall(VecCopy(r,w)); 67*9566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(pcis->global_to_B,pcis->vec1_B,w,ADD_VALUES,SCATTER_REVERSE)); 68*9566063dSJacob Faibussowitsch PetscCall(VecScatterEnd (pcis->global_to_B,pcis->vec1_B,w,ADD_VALUES,SCATTER_REVERSE)); 694b9ad928SBarry Smith 704b9ad928SBarry Smith /* 714b9ad928SBarry Smith Apply the interface preconditioner 724b9ad928SBarry Smith */ 734b9ad928SBarry Smith ierr = PCNNApplyInterfacePreconditioner(pc,w,z,pcis->work_N,pcis->vec1_B,pcis->vec2_B,pcis->vec3_B,pcis->vec1_D, 74*9566063dSJacob Faibussowitsch pcis->vec3_D,pcis->vec1_N,pcis->vec2_N);PetscCall(ierr); 754b9ad928SBarry Smith 764b9ad928SBarry Smith /* 774b9ad928SBarry Smith Computing $ t_I^{(i)} = A_{IB}^{(i)} \tilde R_i z_B $ 784b9ad928SBarry Smith The result is stored in vec1_D. 794b9ad928SBarry Smith */ 80*9566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(pcis->global_to_B,z,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD)); 81*9566063dSJacob Faibussowitsch PetscCall(VecScatterEnd (pcis->global_to_B,z,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD)); 82*9566063dSJacob Faibussowitsch PetscCall(MatMult(pcis->A_IB,pcis->vec1_B,pcis->vec1_D)); 834b9ad928SBarry Smith 844b9ad928SBarry Smith /* 854b9ad928SBarry Smith Dirichlet solvers. 864b9ad928SBarry Smith Computing $ B_I^{(i)}t_I^{(i)} $ and sticking into the global vector the blocks 874b9ad928SBarry Smith $ B_I^{(i)}r_I^{(i)} - B_I^{(i)}t_I^{(i)} $. 884b9ad928SBarry Smith */ 89*9566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(pcis->global_to_D,pcis->vec2_D,z,INSERT_VALUES,SCATTER_REVERSE)); 90*9566063dSJacob Faibussowitsch PetscCall(VecScatterEnd (pcis->global_to_D,pcis->vec2_D,z,INSERT_VALUES,SCATTER_REVERSE)); 91*9566063dSJacob Faibussowitsch PetscCall(KSPSolve(pcis->ksp_D,pcis->vec1_D,pcis->vec2_D)); 92*9566063dSJacob Faibussowitsch PetscCall(VecScale(pcis->vec2_D,m_one)); 93*9566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(pcis->global_to_D,pcis->vec2_D,z,ADD_VALUES,SCATTER_REVERSE)); 94*9566063dSJacob Faibussowitsch PetscCall(VecScatterEnd (pcis->global_to_D,pcis->vec2_D,z,ADD_VALUES,SCATTER_REVERSE)); 954b9ad928SBarry Smith PetscFunctionReturn(0); 964b9ad928SBarry Smith } 974b9ad928SBarry Smith 984b9ad928SBarry Smith /* -------------------------------------------------------------------------- */ 994b9ad928SBarry Smith /* 1004b9ad928SBarry Smith PCDestroy_NN - Destroys the private context for the NN preconditioner 1014b9ad928SBarry Smith that was created with PCCreate_NN(). 1024b9ad928SBarry Smith 1034b9ad928SBarry Smith Input Parameter: 1044b9ad928SBarry Smith . pc - the preconditioner context 1054b9ad928SBarry Smith 1064b9ad928SBarry Smith Application Interface Routine: PCDestroy() 1074b9ad928SBarry Smith */ 1086849ba73SBarry Smith static PetscErrorCode PCDestroy_NN(PC pc) 1094b9ad928SBarry Smith { 1104b9ad928SBarry Smith PC_NN *pcnn = (PC_NN*)pc->data; 1114b9ad928SBarry Smith 1124b9ad928SBarry Smith PetscFunctionBegin; 113*9566063dSJacob Faibussowitsch PetscCall(PCISDestroy(pc)); 1144b9ad928SBarry Smith 115*9566063dSJacob Faibussowitsch PetscCall(MatDestroy(&pcnn->coarse_mat)); 116*9566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pcnn->coarse_x)); 117*9566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pcnn->coarse_b)); 118*9566063dSJacob Faibussowitsch PetscCall(KSPDestroy(&pcnn->ksp_coarse)); 1194b9ad928SBarry Smith if (pcnn->DZ_IN) { 120*9566063dSJacob Faibussowitsch PetscCall(PetscFree(pcnn->DZ_IN[0])); 121*9566063dSJacob Faibussowitsch PetscCall(PetscFree(pcnn->DZ_IN)); 1224b9ad928SBarry Smith } 1234b9ad928SBarry Smith 1244b9ad928SBarry Smith /* 1254b9ad928SBarry Smith Free the private data structure that was hanging off the PC 1264b9ad928SBarry Smith */ 127*9566063dSJacob Faibussowitsch PetscCall(PetscFree(pc->data)); 1284b9ad928SBarry Smith PetscFunctionReturn(0); 1294b9ad928SBarry Smith } 1304b9ad928SBarry Smith 1314b9ad928SBarry Smith /* -------------------------------------------------------------------------- */ 132dfc58137SBarry Smith /*MC 13337a17b4dSBarry Smith PCNN - Balancing Neumann-Neumann for scalar elliptic PDEs. 1344b9ad928SBarry Smith 13537a17b4dSBarry Smith Options Database Keys: 13637a17b4dSBarry Smith + -pc_nn_turn_off_first_balancing - do not balance the residual before solving the local Neumann problems 13737a17b4dSBarry Smith (this skips the first coarse grid solve in the preconditioner) 1385c9740d6SBarry Smith . -pc_nn_turn_off_second_balancing - do not balance the solution solving the local Neumann problems 13937a17b4dSBarry Smith (this skips the second coarse grid solve in the preconditioner) 1405c9740d6SBarry Smith . -pc_is_damp_fixed <fact> - 1415c9740d6SBarry Smith . -pc_is_remove_nullspace_fixed - 1425c9740d6SBarry Smith . -pc_is_set_damping_factor_floating <fact> - 1435c9740d6SBarry Smith . -pc_is_not_damp_floating - 144a2b725a8SWilliam Gropp - -pc_is_not_remove_nullspace_floating - 1454b9ad928SBarry Smith 1468eb2139fSSatish Balay Level: intermediate 14737a17b4dSBarry Smith 14895452b02SPatrick Sanan Notes: 14995452b02SPatrick Sanan The matrix used with this preconditioner must be of type MATIS 15037a17b4dSBarry Smith 1511b99c236SBarry Smith Unlike more 'conventional' Neumann-Neumann preconditioners this iterates over ALL the 1521b99c236SBarry Smith degrees of freedom, NOT just those on the interface (this allows the use of approximate solvers 1531b99c236SBarry Smith on the subdomains; though in our experience using approximate solvers is slower.). 1541b99c236SBarry Smith 1555c9740d6SBarry Smith Options for the coarse grid preconditioner can be set with -nn_coarse_pc_xxx 1565c9740d6SBarry Smith Options for the Dirichlet subproblem preconditioner can be set with -is_localD_pc_xxx 1575c9740d6SBarry Smith Options for the Neumann subproblem preconditioner can be set with -is_localN_pc_xxx 15837a17b4dSBarry Smith 15937a17b4dSBarry Smith Contributed by Paulo Goldfeld 16037a17b4dSBarry Smith 16178392ef1SBarry Smith .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, MATIS 16237a17b4dSBarry Smith M*/ 163b2573a8aSBarry Smith 1648cc058d9SJed Brown PETSC_EXTERN PetscErrorCode PCCreate_NN(PC pc) 1654b9ad928SBarry Smith { 1664b9ad928SBarry Smith PC_NN *pcnn; 1674b9ad928SBarry Smith 1684b9ad928SBarry Smith PetscFunctionBegin; 1694b9ad928SBarry Smith /* 1704b9ad928SBarry Smith Creates the private data structure for this preconditioner and 1714b9ad928SBarry Smith attach it to the PC object. 1724b9ad928SBarry Smith */ 173*9566063dSJacob Faibussowitsch PetscCall(PetscNewLog(pc,&pcnn)); 1744b9ad928SBarry Smith pc->data = (void*)pcnn; 1754b9ad928SBarry Smith 176*9566063dSJacob Faibussowitsch PetscCall(PCISCreate(pc)); 1770a545947SLisandro Dalcin pcnn->coarse_mat = NULL; 1780a545947SLisandro Dalcin pcnn->coarse_x = NULL; 1790a545947SLisandro Dalcin pcnn->coarse_b = NULL; 1800a545947SLisandro Dalcin pcnn->ksp_coarse = NULL; 1810a545947SLisandro Dalcin pcnn->DZ_IN = NULL; 1824b9ad928SBarry Smith 1834b9ad928SBarry Smith /* 1844b9ad928SBarry Smith Set the pointers for the functions that are provided above. 1854b9ad928SBarry Smith Now when the user-level routines (such as PCApply(), PCDestroy(), etc.) 1864b9ad928SBarry Smith are called, they will automatically call these functions. Note we 1874b9ad928SBarry Smith choose not to provide a couple of these functions since they are 1884b9ad928SBarry Smith not needed. 1894b9ad928SBarry Smith */ 1904b9ad928SBarry Smith pc->ops->apply = PCApply_NN; 1910a545947SLisandro Dalcin pc->ops->applytranspose = NULL; 1924b9ad928SBarry Smith pc->ops->setup = PCSetUp_NN; 1934b9ad928SBarry Smith pc->ops->destroy = PCDestroy_NN; 1940a545947SLisandro Dalcin pc->ops->view = NULL; 1950a545947SLisandro Dalcin pc->ops->applyrichardson = NULL; 1960a545947SLisandro Dalcin pc->ops->applysymmetricleft = NULL; 1970a545947SLisandro Dalcin pc->ops->applysymmetricright = NULL; 1984b9ad928SBarry Smith PetscFunctionReturn(0); 1994b9ad928SBarry Smith } 2004b9ad928SBarry Smith 2014b9ad928SBarry Smith /* -------------------------------------------------------------------------- */ 2024b9ad928SBarry Smith /* 2034b9ad928SBarry Smith PCNNCreateCoarseMatrix - 2044b9ad928SBarry Smith */ 205dfbe8321SBarry Smith PetscErrorCode PCNNCreateCoarseMatrix(PC pc) 2064b9ad928SBarry Smith { 2074b9ad928SBarry Smith MPI_Request *send_request, *recv_request; 20813f74950SBarry Smith PetscInt i, j, k; 2094b9ad928SBarry Smith PetscScalar *mat; /* Sub-matrix with this subdomain's contribution to the coarse matrix */ 2104b9ad928SBarry Smith PetscScalar **DZ_OUT; /* proc[k].DZ_OUT[i][] = bit of vector to be sent from processor k to processor i */ 2114b9ad928SBarry Smith 2124b9ad928SBarry Smith /* aliasing some names */ 2134b9ad928SBarry Smith PC_IS *pcis = (PC_IS*)(pc->data); 2144b9ad928SBarry Smith PC_NN *pcnn = (PC_NN*)pc->data; 21513f74950SBarry Smith PetscInt n_neigh = pcis->n_neigh; 21613f74950SBarry Smith PetscInt *neigh = pcis->neigh; 21713f74950SBarry Smith PetscInt *n_shared = pcis->n_shared; 21813f74950SBarry Smith PetscInt **shared = pcis->shared; 2194b9ad928SBarry Smith PetscScalar **DZ_IN; /* Must be initialized after memory allocation. */ 2204b9ad928SBarry Smith 2214b9ad928SBarry Smith PetscFunctionBegin; 2224b9ad928SBarry Smith /* Allocate memory for mat (the +1 is to handle the case n_neigh equal to zero) */ 223*9566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n_neigh*n_neigh+1,&mat)); 2244b9ad928SBarry Smith 2254b9ad928SBarry Smith /* Allocate memory for DZ */ 2264b9ad928SBarry Smith /* Notice that DZ_OUT[0] is allocated some space that is never used. */ 2274b9ad928SBarry Smith /* This is just in order to DZ_OUT and DZ_IN to have exactly the same form. */ 2284b9ad928SBarry Smith { 22913f74950SBarry Smith PetscInt size_of_Z = 0; 230*9566063dSJacob Faibussowitsch PetscCall(PetscMalloc ((n_neigh+1)*sizeof(PetscScalar*),&pcnn->DZ_IN)); 2314b9ad928SBarry Smith DZ_IN = pcnn->DZ_IN; 232*9566063dSJacob Faibussowitsch PetscCall(PetscMalloc ((n_neigh+1)*sizeof(PetscScalar*),&DZ_OUT)); 2332fa5cd67SKarl Rupp for (i=0; i<n_neigh; i++) size_of_Z += n_shared[i]; 234*9566063dSJacob Faibussowitsch PetscCall(PetscMalloc ((size_of_Z+1)*sizeof(PetscScalar),&DZ_IN[0])); 235*9566063dSJacob Faibussowitsch PetscCall(PetscMalloc ((size_of_Z+1)*sizeof(PetscScalar),&DZ_OUT[0])); 2364b9ad928SBarry Smith } 2374b9ad928SBarry Smith for (i=1; i<n_neigh; i++) { 2384b9ad928SBarry Smith DZ_IN[i] = DZ_IN [i-1] + n_shared[i-1]; 2394b9ad928SBarry Smith DZ_OUT[i] = DZ_OUT[i-1] + n_shared[i-1]; 2404b9ad928SBarry Smith } 2414b9ad928SBarry Smith 2424b9ad928SBarry Smith /* Set the values of DZ_OUT, in order to send this info to the neighbours */ 2434b9ad928SBarry Smith /* First, set the auxiliary array pcis->work_N. */ 244*9566063dSJacob Faibussowitsch PetscCall(PCISScatterArrayNToVecB(pcis->work_N,pcis->D,INSERT_VALUES,SCATTER_REVERSE,pc)); 2454b9ad928SBarry Smith for (i=1; i<n_neigh; i++) { 2464b9ad928SBarry Smith for (j=0; j<n_shared[i]; j++) { 2474b9ad928SBarry Smith DZ_OUT[i][j] = pcis->work_N[shared[i][j]]; 2484b9ad928SBarry Smith } 2494b9ad928SBarry Smith } 2504b9ad928SBarry Smith 2514b9ad928SBarry Smith /* Non-blocking send/receive the common-interface chunks of scaled nullspaces */ 2524b9ad928SBarry Smith /* Notice that send_request[] and recv_request[] could have one less element. */ 2534b9ad928SBarry Smith /* We make them longer to have request[i] corresponding to neigh[i]. */ 2544b9ad928SBarry Smith { 25513f74950SBarry Smith PetscMPIInt tag; 256*9566063dSJacob Faibussowitsch PetscCall(PetscObjectGetNewTag((PetscObject)pc,&tag)); 257*9566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(n_neigh+1,&send_request,n_neigh+1,&recv_request)); 2584b9ad928SBarry Smith for (i=1; i<n_neigh; i++) { 259*9566063dSJacob Faibussowitsch PetscCallMPI(MPI_Isend((void*)(DZ_OUT[i]),n_shared[i],MPIU_SCALAR,neigh[i],tag,PetscObjectComm((PetscObject)pc),&(send_request[i]))); 260*9566063dSJacob Faibussowitsch PetscCallMPI(MPI_Irecv((void*)(DZ_IN [i]),n_shared[i],MPIU_SCALAR,neigh[i],tag,PetscObjectComm((PetscObject)pc),&(recv_request[i]))); 2614b9ad928SBarry Smith } 2624b9ad928SBarry Smith } 2634b9ad928SBarry Smith 2644b9ad928SBarry Smith /* Set DZ_IN[0][] (recall that neigh[0]==rank, always) */ 2652fa5cd67SKarl Rupp for (j=0; j<n_shared[0]; j++) DZ_IN[0][j] = pcis->work_N[shared[0][j]]; 2664b9ad928SBarry Smith 2674b9ad928SBarry Smith /* Start computing with local D*Z while communication goes on. */ 2684b9ad928SBarry Smith /* Apply Schur complement. The result is "stored" in vec (more */ 2694b9ad928SBarry Smith /* precisely, vec points to the result, stored in pc_nn->vec1_B) */ 2704b9ad928SBarry Smith /* and also scattered to pcnn->work_N. */ 271*9566063dSJacob Faibussowitsch PetscCall(PCNNApplySchurToChunk(pc,n_shared[0],shared[0],DZ_IN[0],pcis->work_N,pcis->vec1_B,pcis->vec2_B,pcis->vec1_D,pcis->vec2_D)); 2724b9ad928SBarry Smith 2734b9ad928SBarry Smith /* Compute the first column, while completing the receiving. */ 2744b9ad928SBarry Smith for (i=0; i<n_neigh; i++) { 2754b9ad928SBarry Smith MPI_Status stat; 27613f74950SBarry Smith PetscMPIInt ind=0; 277*9566063dSJacob Faibussowitsch if (i>0) {PetscCallMPI(MPI_Waitany(n_neigh-1,recv_request+1,&ind,&stat)); ind++;} 2784b9ad928SBarry Smith mat[ind*n_neigh+0] = 0.0; 2792fa5cd67SKarl Rupp for (k=0; k<n_shared[ind]; k++) mat[ind*n_neigh+0] += DZ_IN[ind][k] * pcis->work_N[shared[ind][k]]; 2804b9ad928SBarry Smith } 2814b9ad928SBarry Smith 2824b9ad928SBarry Smith /* Compute the remaining of the columns */ 2834b9ad928SBarry Smith for (j=1; j<n_neigh; j++) { 284*9566063dSJacob Faibussowitsch PetscCall(PCNNApplySchurToChunk(pc,n_shared[j],shared[j],DZ_IN[j],pcis->work_N,pcis->vec1_B,pcis->vec2_B,pcis->vec1_D,pcis->vec2_D)); 2854b9ad928SBarry Smith for (i=0; i<n_neigh; i++) { 2864b9ad928SBarry Smith mat[i*n_neigh+j] = 0.0; 2872fa5cd67SKarl Rupp for (k=0; k<n_shared[i]; k++) mat[i*n_neigh+j] += DZ_IN[i][k] * pcis->work_N[shared[i][k]]; 2884b9ad928SBarry Smith } 2894b9ad928SBarry Smith } 2904b9ad928SBarry Smith 2914b9ad928SBarry Smith /* Complete the sending. */ 2924b9ad928SBarry Smith if (n_neigh>1) { 2934b9ad928SBarry Smith MPI_Status *stat; 294*9566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n_neigh-1,&stat)); 295*9566063dSJacob Faibussowitsch if (n_neigh-1) PetscCallMPI(MPI_Waitall(n_neigh-1,&(send_request[1]),stat)); 296*9566063dSJacob Faibussowitsch PetscCall(PetscFree(stat)); 2974b9ad928SBarry Smith } 2984b9ad928SBarry Smith 2994b9ad928SBarry Smith /* Free the memory for the MPI requests */ 300*9566063dSJacob Faibussowitsch PetscCall(PetscFree2(send_request,recv_request)); 3014b9ad928SBarry Smith 3024b9ad928SBarry Smith /* Free the memory for DZ_OUT */ 3034b9ad928SBarry Smith if (DZ_OUT) { 304*9566063dSJacob Faibussowitsch PetscCall(PetscFree(DZ_OUT[0])); 305*9566063dSJacob Faibussowitsch PetscCall(PetscFree(DZ_OUT)); 3064b9ad928SBarry Smith } 3074b9ad928SBarry Smith 3084b9ad928SBarry Smith { 30913f74950SBarry Smith PetscMPIInt size; 310*9566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)pc),&size)); 3114b9ad928SBarry Smith /* Create the global coarse vectors (rhs and solution). */ 312*9566063dSJacob Faibussowitsch PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)pc),1,size,&(pcnn->coarse_b))); 313*9566063dSJacob Faibussowitsch PetscCall(VecDuplicate(pcnn->coarse_b,&(pcnn->coarse_x))); 314f204ca49SKris Buschelman /* Create and set the global coarse AIJ matrix. */ 315*9566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)pc),&(pcnn->coarse_mat))); 316*9566063dSJacob Faibussowitsch PetscCall(MatSetSizes(pcnn->coarse_mat,1,1,size,size)); 317*9566063dSJacob Faibussowitsch PetscCall(MatSetType(pcnn->coarse_mat,MATAIJ)); 318*9566063dSJacob Faibussowitsch PetscCall(MatSeqAIJSetPreallocation(pcnn->coarse_mat,1,NULL)); 319*9566063dSJacob Faibussowitsch PetscCall(MatMPIAIJSetPreallocation(pcnn->coarse_mat,1,NULL,n_neigh,NULL)); 320*9566063dSJacob Faibussowitsch PetscCall(MatSetOption(pcnn->coarse_mat,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_FALSE)); 321*9566063dSJacob Faibussowitsch PetscCall(MatSetOption(pcnn->coarse_mat,MAT_NEW_NONZERO_LOCATION_ERR,PETSC_FALSE)); 322*9566063dSJacob Faibussowitsch PetscCall(MatSetValues(pcnn->coarse_mat,n_neigh,neigh,n_neigh,neigh,mat,ADD_VALUES)); 323*9566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(pcnn->coarse_mat,MAT_FINAL_ASSEMBLY)); 324*9566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd (pcnn->coarse_mat,MAT_FINAL_ASSEMBLY)); 3254b9ad928SBarry Smith } 3264b9ad928SBarry Smith 3274b9ad928SBarry Smith { 32813f74950SBarry Smith PetscMPIInt rank; 3294b9ad928SBarry Smith PetscScalar one = 1.0; 330*9566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc),&rank)); 3314b9ad928SBarry Smith /* "Zero out" rows of not-purely-Neumann subdomains */ 3324b9ad928SBarry Smith if (pcis->pure_neumann) { /* does NOT zero the row; create an empty index set. The reason is that MatZeroRows() is collective. */ 333*9566063dSJacob Faibussowitsch PetscCall(MatZeroRows(pcnn->coarse_mat,0,NULL,one,NULL,NULL)); 3344b9ad928SBarry Smith } else { /* here it DOES zero the row, since it's not a floating subdomain. */ 3351c82e0cfSMatthew Knepley PetscInt row = (PetscInt) rank; 336*9566063dSJacob Faibussowitsch PetscCall(MatZeroRows(pcnn->coarse_mat,1,&row,one,NULL,NULL)); 3374b9ad928SBarry Smith } 3384b9ad928SBarry Smith } 3394b9ad928SBarry Smith 3404b9ad928SBarry Smith /* Create the coarse linear solver context */ 3414b9ad928SBarry Smith { 3424b9ad928SBarry Smith PC pc_ctx, inner_pc; 34383ab6a24SBarry Smith KSP inner_ksp; 34483ab6a24SBarry Smith 345*9566063dSJacob Faibussowitsch PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc),&pcnn->ksp_coarse)); 346*9566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)pcnn->ksp_coarse,(PetscObject)pc,2)); 347*9566063dSJacob Faibussowitsch PetscCall(KSPSetOperators(pcnn->ksp_coarse,pcnn->coarse_mat,pcnn->coarse_mat)); 348*9566063dSJacob Faibussowitsch PetscCall(KSPGetPC(pcnn->ksp_coarse,&pc_ctx)); 349*9566063dSJacob Faibussowitsch PetscCall(PCSetType(pc_ctx,PCREDUNDANT)); 350*9566063dSJacob Faibussowitsch PetscCall(KSPSetType(pcnn->ksp_coarse,KSPPREONLY)); 351*9566063dSJacob Faibussowitsch PetscCall(PCRedundantGetKSP(pc_ctx,&inner_ksp)); 352*9566063dSJacob Faibussowitsch PetscCall(KSPGetPC(inner_ksp,&inner_pc)); 353*9566063dSJacob Faibussowitsch PetscCall(PCSetType(inner_pc,PCLU)); 354*9566063dSJacob Faibussowitsch PetscCall(KSPSetOptionsPrefix(pcnn->ksp_coarse,"nn_coarse_")); 355*9566063dSJacob Faibussowitsch PetscCall(KSPSetFromOptions(pcnn->ksp_coarse)); 3564b9ad928SBarry Smith /* the vectors in the following line are dummy arguments, just telling the KSP the vector size. Values are not used */ 357*9566063dSJacob Faibussowitsch PetscCall(KSPSetUp(pcnn->ksp_coarse)); 3584b9ad928SBarry Smith } 3594b9ad928SBarry Smith 3604b9ad928SBarry Smith /* Free the memory for mat */ 361*9566063dSJacob Faibussowitsch PetscCall(PetscFree(mat)); 3624b9ad928SBarry Smith 3634b9ad928SBarry Smith /* for DEBUGGING, save the coarse matrix to a file. */ 3644b9ad928SBarry Smith { 365ace3abfcSBarry Smith PetscBool flg = PETSC_FALSE; 366*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(NULL,NULL,"-pc_nn_save_coarse_matrix",&flg,NULL)); 3674b9ad928SBarry Smith if (flg) { 3684b9ad928SBarry Smith PetscViewer viewer; 369*9566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIOpen(PETSC_COMM_WORLD,"coarse.m",&viewer)); 370*9566063dSJacob Faibussowitsch PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_MATLAB)); 371*9566063dSJacob Faibussowitsch PetscCall(MatView(pcnn->coarse_mat,viewer)); 372*9566063dSJacob Faibussowitsch PetscCall(PetscViewerPopFormat(viewer)); 373*9566063dSJacob Faibussowitsch PetscCall(PetscViewerDestroy(&viewer)); 3744b9ad928SBarry Smith } 3754b9ad928SBarry Smith } 3764b9ad928SBarry Smith 3774b9ad928SBarry Smith /* Set the variable pcnn->factor_coarse_rhs. */ 3784b9ad928SBarry Smith pcnn->factor_coarse_rhs = (pcis->pure_neumann) ? 1.0 : 0.0; 3794b9ad928SBarry Smith 3804b9ad928SBarry Smith /* See historical note 02, at the bottom of this file. */ 3814b9ad928SBarry Smith PetscFunctionReturn(0); 3824b9ad928SBarry Smith } 3834b9ad928SBarry Smith 3844b9ad928SBarry Smith /* -------------------------------------------------------------------------- */ 3854b9ad928SBarry Smith /* 3864b9ad928SBarry Smith PCNNApplySchurToChunk - 3874b9ad928SBarry Smith 3884b9ad928SBarry Smith Input parameters: 3894b9ad928SBarry Smith . pcnn 3904b9ad928SBarry Smith . n - size of chunk 3914b9ad928SBarry Smith . idx - indices of chunk 3924b9ad928SBarry Smith . chunk - values 3934b9ad928SBarry Smith 3944b9ad928SBarry Smith Output parameters: 3954b9ad928SBarry Smith . array_N - result of Schur complement applied to chunk, scattered to big array 3964b9ad928SBarry Smith . vec1_B - result of Schur complement applied to chunk 3974b9ad928SBarry Smith . vec2_B - garbage (used as work space) 3984b9ad928SBarry Smith . vec1_D - garbage (used as work space) 3994b9ad928SBarry Smith . vec2_D - garbage (used as work space) 4004b9ad928SBarry Smith 4014b9ad928SBarry Smith */ 40213f74950SBarry Smith PetscErrorCode PCNNApplySchurToChunk(PC pc, PetscInt n, PetscInt *idx, PetscScalar *chunk, PetscScalar *array_N, Vec vec1_B, Vec vec2_B, Vec vec1_D, Vec vec2_D) 4034b9ad928SBarry Smith { 40413f74950SBarry Smith PetscInt i; 4054b9ad928SBarry Smith PC_IS *pcis = (PC_IS*)(pc->data); 4064b9ad928SBarry Smith 4074b9ad928SBarry Smith PetscFunctionBegin; 408*9566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(array_N, pcis->n)); 4092fa5cd67SKarl Rupp for (i=0; i<n; i++) array_N[idx[i]] = chunk[i]; 410*9566063dSJacob Faibussowitsch PetscCall(PCISScatterArrayNToVecB(array_N,vec2_B,INSERT_VALUES,SCATTER_FORWARD,pc)); 411*9566063dSJacob Faibussowitsch PetscCall(PCISApplySchur(pc,vec2_B,vec1_B,(Vec)0,vec1_D,vec2_D)); 412*9566063dSJacob Faibussowitsch PetscCall(PCISScatterArrayNToVecB(array_N,vec1_B,INSERT_VALUES,SCATTER_REVERSE,pc)); 4134b9ad928SBarry Smith PetscFunctionReturn(0); 4144b9ad928SBarry Smith } 4154b9ad928SBarry Smith 4164b9ad928SBarry Smith /* -------------------------------------------------------------------------- */ 4174b9ad928SBarry Smith /* 4184b9ad928SBarry Smith PCNNApplyInterfacePreconditioner - Apply the interface preconditioner, i.e., 4194b9ad928SBarry Smith the preconditioner for the Schur complement. 4204b9ad928SBarry Smith 4214b9ad928SBarry Smith Input parameter: 4224b9ad928SBarry Smith . r - global vector of interior and interface nodes. The values on the interior nodes are NOT used. 4234b9ad928SBarry Smith 4244b9ad928SBarry Smith Output parameters: 4254b9ad928SBarry Smith . z - global vector of interior and interface nodes. The values on the interface are the result of 4264b9ad928SBarry Smith the application of the interface preconditioner to the interface part of r. The values on the 4274b9ad928SBarry Smith interior nodes are garbage. 4284b9ad928SBarry Smith . work_N - array of local nodes (interior and interface, including ghosts); returns garbage (used as work space) 4294b9ad928SBarry Smith . vec1_B - vector of local interface nodes (including ghosts); returns garbage (used as work space) 4304b9ad928SBarry Smith . vec2_B - vector of local interface nodes (including ghosts); returns garbage (used as work space) 4314b9ad928SBarry Smith . vec3_B - vector of local interface nodes (including ghosts); returns garbage (used as work space) 4324b9ad928SBarry Smith . vec1_D - vector of local interior nodes; returns garbage (used as work space) 4334b9ad928SBarry Smith . vec2_D - vector of local interior nodes; returns garbage (used as work space) 4344b9ad928SBarry Smith . vec1_N - vector of local nodes (interior and interface, including ghosts); returns garbage (used as work space) 4354b9ad928SBarry Smith . vec2_N - vector of local nodes (interior and interface, including ghosts); returns garbage (used as work space) 4364b9ad928SBarry Smith 4374b9ad928SBarry Smith */ 4382fa5cd67SKarl Rupp PetscErrorCode PCNNApplyInterfacePreconditioner(PC pc, Vec r, Vec z, PetscScalar *work_N, Vec vec1_B, Vec vec2_B, Vec vec3_B, Vec vec1_D,Vec vec2_D, Vec vec1_N, Vec vec2_N) 4394b9ad928SBarry Smith { 4404b9ad928SBarry Smith PC_IS *pcis = (PC_IS*)(pc->data); 4414b9ad928SBarry Smith 4424b9ad928SBarry Smith PetscFunctionBegin; 4434b9ad928SBarry Smith /* 4444b9ad928SBarry Smith First balancing step. 4454b9ad928SBarry Smith */ 4464b9ad928SBarry Smith { 447ace3abfcSBarry Smith PetscBool flg = PETSC_FALSE; 448*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(NULL,NULL,"-pc_nn_turn_off_first_balancing",&flg,NULL)); 4494b9ad928SBarry Smith if (!flg) { 450*9566063dSJacob Faibussowitsch PetscCall(PCNNBalancing(pc,r,(Vec)0,z,vec1_B,vec2_B,(Vec)0,vec1_D,vec2_D,work_N)); 4514b9ad928SBarry Smith } else { 452*9566063dSJacob Faibussowitsch PetscCall(VecCopy(r,z)); 4534b9ad928SBarry Smith } 4544b9ad928SBarry Smith } 4554b9ad928SBarry Smith 4564b9ad928SBarry Smith /* 4574b9ad928SBarry Smith Extract the local interface part of z and scale it by D 4584b9ad928SBarry Smith */ 459*9566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(pcis->global_to_B,z,vec1_B,INSERT_VALUES,SCATTER_FORWARD)); 460*9566063dSJacob Faibussowitsch PetscCall(VecScatterEnd (pcis->global_to_B,z,vec1_B,INSERT_VALUES,SCATTER_FORWARD)); 461*9566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(vec2_B,pcis->D,vec1_B)); 4624b9ad928SBarry Smith 4634b9ad928SBarry Smith /* Neumann Solver */ 464*9566063dSJacob Faibussowitsch PetscCall(PCISApplyInvSchur(pc,vec2_B,vec1_B,vec1_N,vec2_N)); 4654b9ad928SBarry Smith 4664b9ad928SBarry Smith /* 4674b9ad928SBarry Smith Second balancing step. 4684b9ad928SBarry Smith */ 4694b9ad928SBarry Smith { 470ace3abfcSBarry Smith PetscBool flg = PETSC_FALSE; 471*9566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(NULL,NULL,"-pc_turn_off_second_balancing",&flg,NULL)); 4724b9ad928SBarry Smith if (!flg) { 473*9566063dSJacob Faibussowitsch PetscCall(PCNNBalancing(pc,r,vec1_B,z,vec2_B,vec3_B,(Vec)0,vec1_D,vec2_D,work_N)); 4744b9ad928SBarry Smith } else { 475*9566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(vec2_B,pcis->D,vec1_B)); 476*9566063dSJacob Faibussowitsch PetscCall(VecSet(z,0.0)); 477*9566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(pcis->global_to_B,vec2_B,z,ADD_VALUES,SCATTER_REVERSE)); 478*9566063dSJacob Faibussowitsch PetscCall(VecScatterEnd (pcis->global_to_B,vec2_B,z,ADD_VALUES,SCATTER_REVERSE)); 4794b9ad928SBarry Smith } 4804b9ad928SBarry Smith } 4814b9ad928SBarry Smith PetscFunctionReturn(0); 4824b9ad928SBarry Smith } 4834b9ad928SBarry Smith 4844b9ad928SBarry Smith /* -------------------------------------------------------------------------- */ 4854b9ad928SBarry Smith /* 4864b9ad928SBarry Smith PCNNBalancing - Computes z, as given in equations (15) and (16) (if the 4874b9ad928SBarry Smith input argument u is provided), or s, as given in equations 4884b9ad928SBarry Smith (12) and (13), if the input argument u is a null vector. 4894b9ad928SBarry Smith Notice that the input argument u plays the role of u_i in 4904b9ad928SBarry Smith equation (14). The equation numbers refer to [Man93]. 4914b9ad928SBarry Smith 4924b9ad928SBarry Smith Input Parameters: 4934b9ad928SBarry Smith . pcnn - NN preconditioner context. 4944b9ad928SBarry Smith . r - MPI vector of all nodes (interior and interface). It's preserved. 4954b9ad928SBarry Smith . u - (Optional) sequential vector of local interface nodes. It's preserved UNLESS vec3_B is null. 4964b9ad928SBarry Smith 4974b9ad928SBarry Smith Output Parameters: 4984b9ad928SBarry Smith . z - MPI vector of interior and interface nodes. Returns s or z (see description above). 4994b9ad928SBarry Smith . vec1_B - Sequential vector of local interface nodes. Workspace. 5004b9ad928SBarry Smith . vec2_B - Sequential vector of local interface nodes. Workspace. 5014b9ad928SBarry Smith . vec3_B - (Optional) sequential vector of local interface nodes. Workspace. 5024b9ad928SBarry Smith . vec1_D - Sequential vector of local interior nodes. Workspace. 5034b9ad928SBarry Smith . vec2_D - Sequential vector of local interior nodes. Workspace. 5044b9ad928SBarry Smith . work_N - Array of all local nodes (interior and interface). Workspace. 5054b9ad928SBarry Smith 5064b9ad928SBarry Smith */ 5072fa5cd67SKarl Rupp PetscErrorCode PCNNBalancing(PC pc, Vec r, Vec u, Vec z, Vec vec1_B, Vec vec2_B, Vec vec3_B,Vec vec1_D, Vec vec2_D, PetscScalar *work_N) 5084b9ad928SBarry Smith { 50913f74950SBarry Smith PetscInt k; 5104b9ad928SBarry Smith PetscScalar value; 5114b9ad928SBarry Smith PetscScalar *lambda; 5124b9ad928SBarry Smith PC_NN *pcnn = (PC_NN*)(pc->data); 5134b9ad928SBarry Smith PC_IS *pcis = (PC_IS*)(pc->data); 5144b9ad928SBarry Smith 5154b9ad928SBarry Smith PetscFunctionBegin; 516*9566063dSJacob Faibussowitsch PetscCall(PetscLogEventBegin(PC_ApplyCoarse,pc,0,0,0)); 5174b9ad928SBarry Smith if (u) { 5182fa5cd67SKarl Rupp if (!vec3_B) vec3_B = u; 519*9566063dSJacob Faibussowitsch PetscCall(VecPointwiseMult(vec1_B,pcis->D,u)); 520*9566063dSJacob Faibussowitsch PetscCall(VecSet(z,0.0)); 521*9566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(pcis->global_to_B,vec1_B,z,ADD_VALUES,SCATTER_REVERSE)); 522*9566063dSJacob Faibussowitsch PetscCall(VecScatterEnd (pcis->global_to_B,vec1_B,z,ADD_VALUES,SCATTER_REVERSE)); 523*9566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(pcis->global_to_B,z,vec2_B,INSERT_VALUES,SCATTER_FORWARD)); 524*9566063dSJacob Faibussowitsch PetscCall(VecScatterEnd (pcis->global_to_B,z,vec2_B,INSERT_VALUES,SCATTER_FORWARD)); 525*9566063dSJacob Faibussowitsch PetscCall(PCISApplySchur(pc,vec2_B,vec3_B,(Vec)0,vec1_D,vec2_D)); 526*9566063dSJacob Faibussowitsch PetscCall(VecScale(vec3_B,-1.0)); 527*9566063dSJacob Faibussowitsch PetscCall(VecCopy(r,z)); 528*9566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(pcis->global_to_B,vec3_B,z,ADD_VALUES,SCATTER_REVERSE)); 529*9566063dSJacob Faibussowitsch PetscCall(VecScatterEnd (pcis->global_to_B,vec3_B,z,ADD_VALUES,SCATTER_REVERSE)); 5304b9ad928SBarry Smith } else { 531*9566063dSJacob Faibussowitsch PetscCall(VecCopy(r,z)); 5324b9ad928SBarry Smith } 533*9566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(pcis->global_to_B,z,vec2_B,INSERT_VALUES,SCATTER_FORWARD)); 534*9566063dSJacob Faibussowitsch PetscCall(VecScatterEnd (pcis->global_to_B,z,vec2_B,INSERT_VALUES,SCATTER_FORWARD)); 535*9566063dSJacob Faibussowitsch PetscCall(PCISScatterArrayNToVecB(work_N,vec2_B,INSERT_VALUES,SCATTER_REVERSE,pc)); 5362fa5cd67SKarl Rupp for (k=0, value=0.0; k<pcis->n_shared[0]; k++) value += pcnn->DZ_IN[0][k] * work_N[pcis->shared[0][k]]; 5374b9ad928SBarry Smith value *= pcnn->factor_coarse_rhs; /* This factor is set in CreateCoarseMatrix(). */ 5384b9ad928SBarry Smith { 53913f74950SBarry Smith PetscMPIInt rank; 540*9566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)pc),&rank)); 541*9566063dSJacob Faibussowitsch PetscCall(VecSetValue(pcnn->coarse_b,rank,value,INSERT_VALUES)); 5424b9ad928SBarry Smith /* 5434b9ad928SBarry Smith Since we are only inserting local values (one value actually) we don't need to do the 5444b9ad928SBarry Smith reduction that tells us there is no data that needs to be moved. Hence we comment out these 545*9566063dSJacob Faibussowitsch PetscCall(VecAssemblyBegin(pcnn->coarse_b)); 546*9566063dSJacob Faibussowitsch PetscCall(VecAssemblyEnd (pcnn->coarse_b)); 5474b9ad928SBarry Smith */ 5484b9ad928SBarry Smith } 549*9566063dSJacob Faibussowitsch PetscCall(KSPSolve(pcnn->ksp_coarse,pcnn->coarse_b,pcnn->coarse_x)); 550*9566063dSJacob Faibussowitsch if (!u) PetscCall(VecScale(pcnn->coarse_x,-1.0)); 551*9566063dSJacob Faibussowitsch PetscCall(VecGetArray(pcnn->coarse_x,&lambda)); 5522fa5cd67SKarl Rupp for (k=0; k<pcis->n_shared[0]; k++) work_N[pcis->shared[0][k]] = *lambda * pcnn->DZ_IN[0][k]; 553*9566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(pcnn->coarse_x,&lambda)); 554*9566063dSJacob Faibussowitsch PetscCall(PCISScatterArrayNToVecB(work_N,vec2_B,INSERT_VALUES,SCATTER_FORWARD,pc)); 555*9566063dSJacob Faibussowitsch PetscCall(VecSet(z,0.0)); 556*9566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(pcis->global_to_B,vec2_B,z,ADD_VALUES,SCATTER_REVERSE)); 557*9566063dSJacob Faibussowitsch PetscCall(VecScatterEnd (pcis->global_to_B,vec2_B,z,ADD_VALUES,SCATTER_REVERSE)); 5584b9ad928SBarry Smith if (!u) { 559*9566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(pcis->global_to_B,z,vec2_B,INSERT_VALUES,SCATTER_FORWARD)); 560*9566063dSJacob Faibussowitsch PetscCall(VecScatterEnd (pcis->global_to_B,z,vec2_B,INSERT_VALUES,SCATTER_FORWARD)); 561*9566063dSJacob Faibussowitsch PetscCall(PCISApplySchur(pc,vec2_B,vec1_B,(Vec)0,vec1_D,vec2_D)); 562*9566063dSJacob Faibussowitsch PetscCall(VecCopy(r,z)); 5634b9ad928SBarry Smith } 564*9566063dSJacob Faibussowitsch PetscCall(VecScatterBegin(pcis->global_to_B,vec1_B,z,ADD_VALUES,SCATTER_REVERSE)); 565*9566063dSJacob Faibussowitsch PetscCall(VecScatterEnd (pcis->global_to_B,vec1_B,z,ADD_VALUES,SCATTER_REVERSE)); 566*9566063dSJacob Faibussowitsch PetscCall(PetscLogEventEnd(PC_ApplyCoarse,pc,0,0,0)); 5674b9ad928SBarry Smith PetscFunctionReturn(0); 5684b9ad928SBarry Smith } 5694b9ad928SBarry Smith 5704b9ad928SBarry Smith /* ------- E N D O F T H E C O D E ------- */ 5714b9ad928SBarry Smith /* */ 5724b9ad928SBarry Smith /* From now on, "footnotes" (or "historical notes"). */ 5734b9ad928SBarry Smith /* */ 5744b9ad928SBarry Smith /* ------------------------------------------------- */ 5754b9ad928SBarry Smith 5764b9ad928SBarry Smith /* -------------------------------------------------------------------------- 5774b9ad928SBarry Smith Historical note 01 5784b9ad928SBarry Smith -------------------------------------------------------------------------- */ 5794b9ad928SBarry Smith /* 5804b9ad928SBarry Smith We considered the possibility of an alternative D_i that would still 5814b9ad928SBarry Smith provide a partition of unity (i.e., $ \sum_i N_i D_i N_i^T = I $). 5824b9ad928SBarry Smith The basic principle was still the pseudo-inverse of the counting 5834b9ad928SBarry Smith function; the difference was that we would not count subdomains 5844b9ad928SBarry Smith that do not contribute to the coarse space (i.e., not pure-Neumann 5854b9ad928SBarry Smith subdomains). 5864b9ad928SBarry Smith 5874b9ad928SBarry Smith This turned out to be a bad idea: we would solve trivial Neumann 5884b9ad928SBarry Smith problems in the not pure-Neumann subdomains, since we would be scaling 5894b9ad928SBarry Smith the balanced residual by zero. 5904b9ad928SBarry Smith */ 5914b9ad928SBarry Smith 5924b9ad928SBarry Smith /* -------------------------------------------------------------------------- 5934b9ad928SBarry Smith Historical note 02 5944b9ad928SBarry Smith -------------------------------------------------------------------------- */ 5954b9ad928SBarry Smith /* 5964b9ad928SBarry Smith We tried an alternative coarse problem, that would eliminate exactly a 5974b9ad928SBarry Smith constant error. Turned out not to improve the overall convergence. 5984b9ad928SBarry Smith */ 599