xref: /petsc/src/ksp/pc/impls/gamg/util.c (revision 4ffacfe27a72f4cdf51b68a3bbb6aed96040fb2f)
1 /*
2  GAMG geometric-algebric multigrid PC - Mark Adams 2011
3  */
4 #include <petsc/private/matimpl.h>
5 #include <../src/ksp/pc/impls/gamg/gamg.h>           /*I "petscpc.h" I*/
6 #include <petsc/private/kspimpl.h>
7 
8 /* -------------------------------------------------------------------------- */
9 /*
10    PCGAMGGetDataWithGhosts - Get array of local + ghost data with local data
11     hacks into Mat MPIAIJ so this must have size > 1
12 
13    Input Parameter:
14    . Gmat - MPIAIJ matrix for scatters
15    . data_sz - number of data terms per node (# cols in output)
16    . data_in[nloc*data_sz] - column oriented local data
17 
18    Output Parameter:
19    . a_stride - number of rows of output (locals+ghosts)
20    . a_data_out[stride*data_sz] - output data with ghosts
21 
22 */
23 PetscErrorCode PCGAMGGetDataWithGhosts(Mat Gmat,PetscInt data_sz,PetscReal data_in[],PetscInt *a_stride,PetscReal **a_data_out)
24 {
25   Vec            tmp_crds;
26   Mat_MPIAIJ     *mpimat = (Mat_MPIAIJ*)Gmat->data;
27   PetscInt       nnodes,num_ghosts,dir,kk,jj,my0,Iend,nloc;
28   PetscScalar    *data_arr;
29   PetscReal      *datas;
30   PetscBool      isMPIAIJ;
31 
32   PetscFunctionBegin;
33   PetscCall(PetscObjectBaseTypeCompare((PetscObject)Gmat, MATMPIAIJ, &isMPIAIJ));
34   PetscCall(MatGetOwnershipRange(Gmat, &my0, &Iend));
35   nloc      = Iend - my0;
36   PetscCall(VecGetLocalSize(mpimat->lvec, &num_ghosts));
37   nnodes    = num_ghosts + nloc;
38   *a_stride = nnodes;
39   PetscCall(MatCreateVecs(Gmat, &tmp_crds, NULL));
40 
41   PetscCall(PetscMalloc1(data_sz*nnodes, &datas));
42   for (dir=0; dir<data_sz; dir++) {
43     /* set local, and global */
44     for (kk=0; kk<nloc; kk++) {
45       PetscInt    gid = my0 + kk;
46       PetscScalar crd = (PetscScalar)data_in[dir*nloc + kk]; /* col oriented */
47       datas[dir*nnodes + kk] = PetscRealPart(crd); // get local part now
48 
49       PetscCall(VecSetValues(tmp_crds, 1, &gid, &crd, INSERT_VALUES));
50     }
51     PetscCall(VecAssemblyBegin(tmp_crds));
52     PetscCall(VecAssemblyEnd(tmp_crds));
53     /* scatter / gather ghost data and add to end of output data */
54     PetscCall(VecScatterBegin(mpimat->Mvctx,tmp_crds,mpimat->lvec,INSERT_VALUES,SCATTER_FORWARD));
55     PetscCall(VecScatterEnd(mpimat->Mvctx,tmp_crds,mpimat->lvec,INSERT_VALUES,SCATTER_FORWARD));
56     PetscCall(VecGetArray(mpimat->lvec, &data_arr));
57     for (kk=nloc,jj=0;jj<num_ghosts;kk++,jj++) datas[dir*nnodes + kk] = PetscRealPart(data_arr[jj]);
58     PetscCall(VecRestoreArray(mpimat->lvec, &data_arr));
59   }
60   PetscCall(VecDestroy(&tmp_crds));
61   *a_data_out = datas;
62   PetscFunctionReturn(0);
63 }
64 
65 PetscErrorCode PCGAMGHashTableCreate(PetscInt a_size, PCGAMGHashTable *a_tab)
66 {
67   PetscInt       kk;
68 
69   PetscFunctionBegin;
70   a_tab->size = a_size;
71   PetscCall(PetscMalloc2(a_size, &a_tab->table,a_size, &a_tab->data));
72   for (kk=0; kk<a_size; kk++) a_tab->table[kk] = -1;
73   PetscFunctionReturn(0);
74 }
75 
76 PetscErrorCode PCGAMGHashTableDestroy(PCGAMGHashTable *a_tab)
77 {
78   PetscFunctionBegin;
79   PetscCall(PetscFree2(a_tab->table,a_tab->data));
80   PetscFunctionReturn(0);
81 }
82 
83 PetscErrorCode PCGAMGHashTableAdd(PCGAMGHashTable *a_tab, PetscInt a_key, PetscInt a_data)
84 {
85   PetscInt kk,idx;
86 
87   PetscFunctionBegin;
88   PetscCheck(a_key>=0,PETSC_COMM_SELF,PETSC_ERR_USER,"Negative key %" PetscInt_FMT ".",a_key);
89   for (kk = 0, idx = GAMG_HASH(a_key); kk < a_tab->size; kk++, idx = (idx==(a_tab->size-1)) ? 0 : idx + 1) {
90     if (a_tab->table[idx] == a_key) {
91       /* exists */
92       a_tab->data[idx] = a_data;
93       break;
94     } else if (a_tab->table[idx] == -1) {
95       /* add */
96       a_tab->table[idx] = a_key;
97       a_tab->data[idx]  = a_data;
98       break;
99     }
100   }
101   if (kk==a_tab->size) {
102     /* this is not to efficient, waiting until completely full */
103     PetscInt       oldsize = a_tab->size, new_size = 2*a_tab->size + 5, *oldtable = a_tab->table, *olddata = a_tab->data;
104 
105     a_tab->size = new_size;
106     PetscCall(PetscMalloc2(a_tab->size, &a_tab->table,a_tab->size, &a_tab->data));
107     for (kk=0;kk<a_tab->size;kk++) a_tab->table[kk] = -1;
108     for (kk=0;kk<oldsize;kk++) {
109       if (oldtable[kk] != -1) {
110         PetscCall(PCGAMGHashTableAdd(a_tab, oldtable[kk], olddata[kk]));
111        }
112     }
113     PetscCall(PetscFree2(oldtable,olddata));
114     PetscCall(PCGAMGHashTableAdd(a_tab, a_key, a_data));
115   }
116   PetscFunctionReturn(0);
117 }
118