xref: /petsc/src/ksp/pc/impls/cp/cp.c (revision 18d3aa3f5b7b6cf3b58215079fab4e2a5c7adae3)
1 #define PETSCKSP_DLL
2 
3 #include "private/pcimpl.h"   /*I "petscpc.h" I*/
4 #include "../src/mat/impls/aij/seq/aij.h"
5 
6 /*
7    Private context (data structure) for the CP preconditioner.
8 */
9 typedef struct {
10   PetscInt    n,m;
11   Vec         work;
12   PetscScalar *d;       /* sum of squares of each column */
13   PetscScalar *a;       /* non-zeros by column */
14   PetscInt    *i,*j;    /* offsets of nonzeros by column, non-zero indices by column */
15 } PC_CP;
16 
17 
18 #undef __FUNCT__
19 #define __FUNCT__ "PCSetUp_CP"
20 static PetscErrorCode PCSetUp_CP(PC pc)
21 {
22   PC_CP          *cp = (PC_CP*)pc->data;
23   PetscInt       i,j,*colcnt;
24   PetscErrorCode ierr;
25   PetscBool      flg;
26   Mat_SeqAIJ     *aij = (Mat_SeqAIJ*)pc->pmat->data;
27 
28   PetscFunctionBegin;
29   ierr = PetscTypeCompare((PetscObject)pc->pmat,MATSEQAIJ,&flg);CHKERRQ(ierr);
30   if (!flg) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Currently only handles SeqAIJ matrices");
31 
32   ierr = MatGetLocalSize(pc->pmat,&cp->m,&cp->n);CHKERRQ(ierr);
33   if (cp->m != cp->n) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Currently only for square matrices");
34 
35   if (!cp->work) {ierr = MatGetVecs(pc->pmat,&cp->work,PETSC_NULL);CHKERRQ(ierr);}
36   if (!cp->d) {ierr = PetscMalloc(cp->n*sizeof(PetscScalar),&cp->d);CHKERRQ(ierr);}
37   if (cp->a && pc->flag != SAME_NONZERO_PATTERN) {
38     ierr  = PetscFree3(cp->a,cp->i,cp->j);CHKERRQ(ierr);
39     cp->a = 0;
40   }
41 
42   /* convert to column format */
43   if (!cp->a) {
44     ierr = PetscMalloc3(aij->nz,PetscScalar,&cp->a,cp->n+1,PetscInt,&cp->i,aij->nz,PetscInt,&cp->j);CHKERRQ(ierr);
45   }
46   ierr = PetscMalloc(cp->n*sizeof(PetscInt),&colcnt);CHKERRQ(ierr);
47   ierr = PetscMemzero(colcnt,cp->n*sizeof(PetscInt));CHKERRQ(ierr);
48 
49   for (i=0; i<aij->nz; i++) {
50     colcnt[aij->j[i]]++;
51   }
52   cp->i[0] = 0;
53   for (i=0; i<cp->n; i++) {
54     cp->i[i+1] = cp->i[i] + colcnt[i];
55   }
56   ierr = PetscMemzero(colcnt,cp->n*sizeof(PetscInt));CHKERRQ(ierr);
57   for (i=0; i<cp->m; i++) {  /* over rows */
58     for (j=aij->i[i]; j<aij->i[i+1]; j++) {  /* over columns in row */
59       cp->j[cp->i[aij->j[j]]+colcnt[aij->j[j]]]   = i;
60       cp->a[cp->i[aij->j[j]]+colcnt[aij->j[j]]++] = aij->a[j];
61     }
62   }
63   ierr = PetscFree(colcnt);CHKERRQ(ierr);
64 
65   /* compute sum of squares of each column d[] */
66   for (i=0; i<cp->n; i++) {  /* over columns */
67     cp->d[i] = 0.;
68     for (j=cp->i[i]; j<cp->i[i+1]; j++) { /* over rows in column */
69       cp->d[i] += cp->a[j]*cp->a[j];
70     }
71     cp->d[i] = 1.0/cp->d[i];
72   }
73   PetscFunctionReturn(0);
74 }
75 /* -------------------------------------------------------------------------- */
76 #undef __FUNCT__
77 #define __FUNCT__ "PCApply_CP"
78 static PetscErrorCode PCApply_CP(PC pc,Vec bb,Vec xx)
79 {
80   PC_CP          *cp = (PC_CP*)pc->data;
81   PetscErrorCode ierr;
82   PetscScalar    *b,*x,xt;
83   PetscInt       i,j;
84 
85   PetscFunctionBegin;
86   ierr = VecCopy(bb,cp->work);CHKERRQ(ierr);
87   ierr = VecGetArray(cp->work,&b);CHKERRQ(ierr);
88   ierr = VecGetArray(xx,&x);CHKERRQ(ierr);
89 
90   for (i=0; i<cp->n; i++) {  /* over columns */
91     xt = 0.;
92     for (j=cp->i[i]; j<cp->i[i+1]; j++) { /* over rows in column */
93         xt   += cp->a[j]*b[cp->j[j]];
94     }
95     xt   *= cp->d[i];
96     x[i] = xt;
97     for (j=cp->i[i]; j<cp->i[i+1]; j++) { /* over rows in column updating b*/
98       b[cp->j[j]] -= xt*cp->a[j];
99     }
100   }
101   for (i=cp->n-1; i>-1; i--) {  /* over columns */
102     xt = 0.;
103     for (j=cp->i[i]; j<cp->i[i+1]; j++) { /* over rows in column */
104         xt   += cp->a[j]*b[cp->j[j]];
105     }
106     xt   *= cp->d[i];
107     x[i] = xt;
108     for (j=cp->i[i]; j<cp->i[i+1]; j++) { /* over rows in column updating b*/
109       b[cp->j[j]] -= xt*cp->a[j];
110     }
111   }
112 
113   ierr = VecRestoreArray(cp->work,&b);CHKERRQ(ierr);
114   ierr = VecRestoreArray(xx,&x);CHKERRQ(ierr);
115   PetscFunctionReturn(0);
116 }
117 /* -------------------------------------------------------------------------- */
118 #undef __FUNCT__
119 #define __FUNCT__ "PCReset_CP"
120 static PetscErrorCode PCReset_CP(PC pc)
121 {
122   PC_CP          *cp = (PC_CP*)pc->data;
123   PetscErrorCode ierr;
124 
125   PetscFunctionBegin;
126   ierr = PetscFree(cp->d);CHKERRQ(ierr);
127   if (cp->work) {ierr = VecDestroy(cp->work);CHKERRQ(ierr);}
128   ierr = PetscFree3(cp->a,cp->i,cp->j);CHKERRQ(ierr);
129   PetscFunctionReturn(0);
130 }
131 
132 #undef __FUNCT__
133 #define __FUNCT__ "PCDestroy_CP"
134 static PetscErrorCode PCDestroy_CP(PC pc)
135 {
136   PC_CP          *cp = (PC_CP*)pc->data;
137   PetscErrorCode ierr;
138 
139   PetscFunctionBegin;
140   ierr = PCReset_CP(pc);CHKERRQ(ierr);
141   ierr = PetscFree(cp->d);CHKERRQ(ierr);
142   ierr = PetscFree3(cp->a,cp->i,cp->j);CHKERRQ(ierr);
143   ierr = PetscFree(pc->data);CHKERRQ(ierr);
144   PetscFunctionReturn(0);
145 }
146 
147 #undef __FUNCT__
148 #define __FUNCT__ "PCSetFromOptions_CP"
149 static PetscErrorCode PCSetFromOptions_CP(PC pc)
150 {
151   PetscFunctionBegin;
152   PetscFunctionReturn(0);
153 }
154 
155 
156 /*MC
157      PCCP - a "column-projection" preconditioner
158 
159      This is a terrible preconditioner and is not recommended, ever!
160 
161      Loops over the entries of x computing dx_i to
162 $
163 $        min || b - A(x + dx_i e_i ||_2
164 $        dx_i
165 $
166 $    That is, it changes a single entry of x to minimize the new residual.
167 $   Let A_i represent the ith column of A, then the minimization can be written as
168 $
169 $       min || r - (dx_i) A e_i ||_2
170 $       dx_i
171 $   or   min || r - (dx_i) A_i ||_2
172 $        dx_i
173 $
174 $    take the derivative with respect to dx_i to obtain
175 $        dx_i = (A_i^T A_i)^(-1) A_i^T r
176 $
177 $    This algorithm can be thought of as Gauss-Seidel on the normal equations
178 
179     Notes: This proceedure can also be done with block columns or any groups of columns
180         but this is not coded.
181 
182       These "projections" can be done simultaneously for all columns (similar to Jacobi)
183          or sequentially (similar to Gauss-Seidel/SOR). This is only coded for SOR type.
184 
185       This is related to, but not the same as "row projection" methods.
186 
187       This is currently coded only for SeqAIJ matrices in sequential (SOR) form.
188 
189   Level: intermediate
190 
191 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PCJACOBI, PCSOR
192 
193 M*/
194 
195 EXTERN_C_BEGIN
196 #undef __FUNCT__
197 #define __FUNCT__ "PCCreate_CP"
198 PetscErrorCode  PCCreate_CP(PC pc)
199 {
200   PC_CP          *cp;
201   PetscErrorCode ierr;
202 
203   PetscFunctionBegin;
204   ierr      = PetscNewLog(pc,PC_CP,&cp);CHKERRQ(ierr);
205   pc->data  = (void*)cp;
206 
207   pc->ops->apply               = PCApply_CP;
208   pc->ops->applytranspose      = PCApply_CP;
209   pc->ops->setup               = PCSetUp_CP;
210   pc->ops->reset               = PCReset_CP;
211   pc->ops->destroy             = PCDestroy_CP;
212   pc->ops->setfromoptions      = PCSetFromOptions_CP;
213   pc->ops->view                = 0;
214   pc->ops->applyrichardson     = 0;
215   PetscFunctionReturn(0);
216 }
217 EXTERN_C_END
218 
219 
220