xref: /petsc/src/mat/impls/shell/shell.c (revision e51e0e81b6a557b5bee3c11524ff450ba6c1b94e)
1*e51e0e81SBarry Smith 
2*e51e0e81SBarry Smith /*
3*e51e0e81SBarry Smith    This is where the abstract matrix operations are defined
4*e51e0e81SBarry Smith */
5*e51e0e81SBarry Smith 
6*e51e0e81SBarry Smith #include "petsc.h"
7*e51e0e81SBarry Smith #include "matimpl.h"        /*I "mat.h" I*/
8*e51e0e81SBarry Smith #include "vec/vecimpl.h"
9*e51e0e81SBarry Smith 
10*e51e0e81SBarry Smith /*@
11*e51e0e81SBarry Smith     MatGetReordering -
12*e51e0e81SBarry Smith 
13*e51e0e81SBarry Smith   Input Parameters:
14*e51e0e81SBarry Smith .  mat - the matrix
15*e51e0e81SBarry Smith .  type - type of reordering; one of:ORDER_ND,ORDER_1WD,ORDER_RCM,ORDER_QMD
16*e51e0e81SBarry Smith 
17*e51e0e81SBarry Smith   OutPut Parameters:
18*e51e0e81SBarry Smith .  rperm - row permutation indices
19*e51e0e81SBarry Smith .  cperm - column permutation indices
20*e51e0e81SBarry Smith 
21*e51e0e81SBarry Smith   If the column permutations and row permutations are the same, then
22*e51e0e81SBarry Smith returns 0 in cperm.
23*e51e0e81SBarry Smith @*/
24*e51e0e81SBarry Smith int MatGetReordering(Mat mat,int type,IS *rperm,IS *cperm)
25*e51e0e81SBarry Smith {
26*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
27*e51e0e81SBarry Smith   if (!mat->ops->order) SETERR(1,"Cannot reorder this matrix");
28*e51e0e81SBarry Smith   return (*mat->ops->order)(mat,type,rperm,cperm);
29*e51e0e81SBarry Smith }
30*e51e0e81SBarry Smith 
31*e51e0e81SBarry Smith /*@
32*e51e0e81SBarry Smith     MatGetRow - gets a row of a matrix. This routine is provided
33*e51e0e81SBarry Smith                for people who need to have direct address to the
34*e51e0e81SBarry Smith                structure of a matrix, we hope that we provide
35*e51e0e81SBarry Smith                enough high level matrix routines so that few users
36*e51e0e81SBarry Smith                need it. You MUST call MatRestoreRow() for each row
37*e51e0e81SBarry Smith                that you get to insure that your application does
38*e51e0e81SBarry Smith                not bleed memory.
39*e51e0e81SBarry Smith 
40*e51e0e81SBarry Smith   Input Parameters:
41*e51e0e81SBarry Smith .  mat - the matrix
42*e51e0e81SBarry Smith .  row - the row to get
43*e51e0e81SBarry Smith 
44*e51e0e81SBarry Smith   OutPut Parameters:
45*e51e0e81SBarry Smith .  ncols, cols - the number of nonzeros and their columns
46*e51e0e81SBarry Smith .  vals - if nonzero the column values
47*e51e0e81SBarry Smith @*/
48*e51e0e81SBarry Smith int MatGetRow(Mat mat,int row,int *ncols,int **cols,Scalar **vals)
49*e51e0e81SBarry Smith {
50*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
51*e51e0e81SBarry Smith   return (*mat->ops->getrow)(mat,row,ncols,cols,vals);
52*e51e0e81SBarry Smith }
53*e51e0e81SBarry Smith 
54*e51e0e81SBarry Smith /*@
55*e51e0e81SBarry Smith      MatRestoreRow - frees any temporary space malloced by
56*e51e0e81SBarry Smith                      MatGetRow().
57*e51e0e81SBarry Smith 
58*e51e0e81SBarry Smith   Input Parameters:
59*e51e0e81SBarry Smith .  mat - the matrix
60*e51e0e81SBarry Smith .  row - the row to get
61*e51e0e81SBarry Smith .  ncols, cols - the number of nonzeros and their columns
62*e51e0e81SBarry Smith .  vals - if nonzero the column values
63*e51e0e81SBarry Smith @*/
64*e51e0e81SBarry Smith int MatRestoreRow(Mat mat,int row,int *ncols,int **cols,Scalar **vals)
65*e51e0e81SBarry Smith {
66*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
67*e51e0e81SBarry Smith   if (!mat->ops->restorerow) return 0;
68*e51e0e81SBarry Smith   return (*mat->ops->restorerow)(mat,row,ncols,cols,vals);
69*e51e0e81SBarry Smith }
70*e51e0e81SBarry Smith /*@
71*e51e0e81SBarry Smith     MatView - visualize a matrix object.
72*e51e0e81SBarry Smith 
73*e51e0e81SBarry Smith   Input Parameters:
74*e51e0e81SBarry Smith .   mat - the matrix
75*e51e0e81SBarry Smith .   ptr - a visualization context
76*e51e0e81SBarry Smith @*/
77*e51e0e81SBarry Smith int MatView(Mat mat,Viewer ptr)
78*e51e0e81SBarry Smith {
79*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
80*e51e0e81SBarry Smith   return (*mat->view)((PetscObject)mat,ptr);
81*e51e0e81SBarry Smith }
82*e51e0e81SBarry Smith /*@
83*e51e0e81SBarry Smith     MatDestroy - frees space taken by matrix
84*e51e0e81SBarry Smith 
85*e51e0e81SBarry Smith   Input Parameters:
86*e51e0e81SBarry Smith .  mat the matrix
87*e51e0e81SBarry Smith @*/
88*e51e0e81SBarry Smith int MatDestroy(Mat mat)
89*e51e0e81SBarry Smith {
90*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
91*e51e0e81SBarry Smith   return (*mat->destroy)((PetscObject)mat);
92*e51e0e81SBarry Smith }
93*e51e0e81SBarry Smith /*@
94*e51e0e81SBarry Smith     MatValidMatrix - returns 1 if a valid matrix else 0
95*e51e0e81SBarry Smith 
96*e51e0e81SBarry Smith   Input Parameter:
97*e51e0e81SBarry Smith .   m - the matrix to check
98*e51e0e81SBarry Smith @*/
99*e51e0e81SBarry Smith int MatValidMatrix(Mat m)
100*e51e0e81SBarry Smith {
101*e51e0e81SBarry Smith   if (!m) return 0;
102*e51e0e81SBarry Smith   if (m->cookie != MAT_COOKIE) return 0;
103*e51e0e81SBarry Smith   return 1;
104*e51e0e81SBarry Smith }
105*e51e0e81SBarry Smith 
106*e51e0e81SBarry Smith /*@
107*e51e0e81SBarry Smith     MatInsertValues - inserts a block of values into a matrix
108*e51e0e81SBarry Smith 
109*e51e0e81SBarry Smith   Input Parameters:
110*e51e0e81SBarry Smith .  mat - the matrix
111*e51e0e81SBarry Smith .  v - a logically two dimensional array of values, Fortran ordering
112*e51e0e81SBarry Smith .  m, indexm - the number of rows and their indices
113*e51e0e81SBarry Smith .  n, indexn - the number of columns and their indices
114*e51e0e81SBarry Smith @*/
115*e51e0e81SBarry Smith int MatInsertValues(Mat mat,Scalar *v,int m,int *indexm,int n,int *indexn)
116*e51e0e81SBarry Smith {
117*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
118*e51e0e81SBarry Smith   return (*mat->ops->insert)(mat,v,m,indexm,n,indexn);
119*e51e0e81SBarry Smith }
120*e51e0e81SBarry Smith /*@
121*e51e0e81SBarry Smith     MatAddValues - adds a block of values into a matrix
122*e51e0e81SBarry Smith 
123*e51e0e81SBarry Smith   Input Parameters:
124*e51e0e81SBarry Smith .  mat - the matrix
125*e51e0e81SBarry Smith .  v - a logically two dimensional array of values, Fortran ordering
126*e51e0e81SBarry Smith .  m, indexm - the number of rows and their indices
127*e51e0e81SBarry Smith .  n, indexn - the number of columns and their indices
128*e51e0e81SBarry Smith @*/
129*e51e0e81SBarry Smith int MatAddValues(Mat mat,Scalar *v,int m,int *indexm,int n,int *indexn)
130*e51e0e81SBarry Smith {
131*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
132*e51e0e81SBarry Smith   return (*mat->ops->insertadd)(mat,v,m,indexm,n,indexn);
133*e51e0e81SBarry Smith }
134*e51e0e81SBarry Smith /* --------------------------------------------------------*/
135*e51e0e81SBarry Smith /*@
136*e51e0e81SBarry Smith     MatMult - Matrix vector multiply
137*e51e0e81SBarry Smith 
138*e51e0e81SBarry Smith   Input Parameters:
139*e51e0e81SBarry Smith .    mat -the matrix
140*e51e0e81SBarry Smith .     x  - the vector to be multilplied
141*e51e0e81SBarry Smith   Output Parameters:
142*e51e0e81SBarry Smith .      y - the result
143*e51e0e81SBarry Smith @*/
144*e51e0e81SBarry Smith int MatMult(Mat mat,Vec x,Vec y)
145*e51e0e81SBarry Smith {
146*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
147*e51e0e81SBarry Smith   VALIDHEADER(x,VEC_COOKIE);VALIDHEADER(y,VEC_COOKIE);
148*e51e0e81SBarry Smith   return (*mat->ops->mult)(mat,x,y);
149*e51e0e81SBarry Smith }
150*e51e0e81SBarry Smith /*@
151*e51e0e81SBarry Smith     MatMultTrans - Matrix transpose times a vector
152*e51e0e81SBarry Smith 
153*e51e0e81SBarry Smith   Input Parameters:
154*e51e0e81SBarry Smith .    mat -the matrix
155*e51e0e81SBarry Smith .     x  - the vector to be multilplied
156*e51e0e81SBarry Smith   Output Parameters:
157*e51e0e81SBarry Smith .      y - the result
158*e51e0e81SBarry Smith @*/
159*e51e0e81SBarry Smith int MatMultTrans(Mat mat,Vec x,Vec y)
160*e51e0e81SBarry Smith {
161*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
162*e51e0e81SBarry Smith   VALIDHEADER(x,VEC_COOKIE); VALIDHEADER(y,VEC_COOKIE);
163*e51e0e81SBarry Smith   return (*mat->ops->multtrans)(mat,x,y);
164*e51e0e81SBarry Smith }
165*e51e0e81SBarry Smith /*@
166*e51e0e81SBarry Smith     MatMultAdd -  v3 = v2 + A v1
167*e51e0e81SBarry Smith 
168*e51e0e81SBarry Smith   Input Parameters:
169*e51e0e81SBarry Smith .    mat -the matrix
170*e51e0e81SBarry Smith .     v1, v2  - the vectors
171*e51e0e81SBarry Smith   Output Parameters:
172*e51e0e81SBarry Smith .     v3 - the result
173*e51e0e81SBarry Smith @*/
174*e51e0e81SBarry Smith int MatMultAdd(Mat mat,Vec v1,Vec v2,Vec v3)
175*e51e0e81SBarry Smith {
176*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);VALIDHEADER(v1,VEC_COOKIE);
177*e51e0e81SBarry Smith   VALIDHEADER(v2,VEC_COOKIE); VALIDHEADER(v3,VEC_COOKIE);
178*e51e0e81SBarry Smith   return (*mat->ops->multadd)(mat,v1,v2,v3);
179*e51e0e81SBarry Smith }
180*e51e0e81SBarry Smith /*@
181*e51e0e81SBarry Smith     MatMultTransAdd -  v3 = v2 + A' v1
182*e51e0e81SBarry Smith 
183*e51e0e81SBarry Smith   Input Parameters:
184*e51e0e81SBarry Smith .    mat -the matrix
185*e51e0e81SBarry Smith .     v1, v2  - the vectors
186*e51e0e81SBarry Smith   Output Parameters:
187*e51e0e81SBarry Smith .     v3 - the result
188*e51e0e81SBarry Smith @*/
189*e51e0e81SBarry Smith int MatMultTransAdd(Mat mat,Vec v1,Vec v2,Vec v3)
190*e51e0e81SBarry Smith {
191*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE); VALIDHEADER(v1,VEC_COOKIE);
192*e51e0e81SBarry Smith   VALIDHEADER(v2,VEC_COOKIE); VALIDHEADER(v3,VEC_COOKIE);
193*e51e0e81SBarry Smith   return (*mat->ops->multtransadd)(mat,v1,v2,v3);
194*e51e0e81SBarry Smith }
195*e51e0e81SBarry Smith /* ------------------------------------------------------------*/
196*e51e0e81SBarry Smith /*@
197*e51e0e81SBarry Smith      MatNonZeros - returns the number of nonzeros in a matrix
198*e51e0e81SBarry Smith 
199*e51e0e81SBarry Smith   Input Parameters:
200*e51e0e81SBarry Smith .   mat - the matrix
201*e51e0e81SBarry Smith 
202*e51e0e81SBarry Smith   Output Parameters:
203*e51e0e81SBarry Smith .   returns the number of nonzeros
204*e51e0e81SBarry Smith @*/
205*e51e0e81SBarry Smith int MatNonZeros(Mat mat,int *nz)
206*e51e0e81SBarry Smith {
207*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
208*e51e0e81SBarry Smith   return  (*mat->ops->NZ)(mat,nz);
209*e51e0e81SBarry Smith }
210*e51e0e81SBarry Smith /*@
211*e51e0e81SBarry Smith      MatMemoryUsed - returns the amount of memory used to store matrix.
212*e51e0e81SBarry Smith 
213*e51e0e81SBarry Smith   Input Parameters:
214*e51e0e81SBarry Smith .   mat - the matrix
215*e51e0e81SBarry Smith 
216*e51e0e81SBarry Smith   Output Parameters:
217*e51e0e81SBarry Smith .   mem - memory used
218*e51e0e81SBarry Smith @*/
219*e51e0e81SBarry Smith int MatMemoryUsed(Mat mat,int *mem)
220*e51e0e81SBarry Smith {
221*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
222*e51e0e81SBarry Smith   return  (*mat->ops->memory)(mat,mem);
223*e51e0e81SBarry Smith }
224*e51e0e81SBarry Smith /* ----------------------------------------------------------*/
225*e51e0e81SBarry Smith /*@
226*e51e0e81SBarry Smith     MatLUFactor - performs an inplace LU factorization of matrix.
227*e51e0e81SBarry Smith              See MatLUFactorSymbolic() and MatLUFactorNumeric() for
228*e51e0e81SBarry Smith              out-of-place factorization. See MatCholeskyFactor()
229*e51e0e81SBarry Smith              for symmetric, positive definite case.
230*e51e0e81SBarry Smith 
231*e51e0e81SBarry Smith   Input Parameters:
232*e51e0e81SBarry Smith .   mat - the matrix
233*e51e0e81SBarry Smith .   row, col - row and  column permutations
234*e51e0e81SBarry Smith 
235*e51e0e81SBarry Smith @*/
236*e51e0e81SBarry Smith int MatLUFactor(Mat mat,IS row,IS col)
237*e51e0e81SBarry Smith {
238*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
239*e51e0e81SBarry Smith   if (mat->ops->lufactor) return (*mat->ops->lufactor)(mat,row,col);
240*e51e0e81SBarry Smith   SETERR(1,"No MatLUFactor for implementation");
241*e51e0e81SBarry Smith }
242*e51e0e81SBarry Smith /*@
243*e51e0e81SBarry Smith     MatLUFactorSymbolic - performs a symbolic LU factorization of matrix.
244*e51e0e81SBarry Smith              See MatLUFactor() for in-place factorization. See
245*e51e0e81SBarry Smith              MatCholeskyFactor() for symmetric, positive definite case.
246*e51e0e81SBarry Smith 
247*e51e0e81SBarry Smith   Input Parameters:
248*e51e0e81SBarry Smith .   mat - the matrix
249*e51e0e81SBarry Smith .   row, col - row and  column permutations
250*e51e0e81SBarry Smith 
251*e51e0e81SBarry Smith   Output Parameters:
252*e51e0e81SBarry Smith .   fact - puts factor else does inplace factorization
253*e51e0e81SBarry Smith @*/
254*e51e0e81SBarry Smith int MatLUFactorSymbolic(Mat mat,IS row,IS col,Mat *fact)
255*e51e0e81SBarry Smith {
256*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
257*e51e0e81SBarry Smith   if (!fact) SETERR(1,"Missing slot for symbolic factorization");
258*e51e0e81SBarry Smith   if (mat->ops->lufactorsymbolic) return (*mat->ops->lufactorsymbolic)(mat,row,
259*e51e0e81SBarry Smith                                                                     col,fact);
260*e51e0e81SBarry Smith   SETERR(1,"No MatLUFactorSymbolic for implementation");
261*e51e0e81SBarry Smith }
262*e51e0e81SBarry Smith /*@
263*e51e0e81SBarry Smith     MatLUFactorNumeric - performs a numeric LU factorization of matrix.
264*e51e0e81SBarry Smith              See MatLUFactor() for in-place factorization. See
265*e51e0e81SBarry Smith              MatCholeskyFactor() for symmetric, positive definite case.
266*e51e0e81SBarry Smith 
267*e51e0e81SBarry Smith   Input Parameters:
268*e51e0e81SBarry Smith .   mat - the matrix
269*e51e0e81SBarry Smith .   row, col - row and  column permutations
270*e51e0e81SBarry Smith 
271*e51e0e81SBarry Smith   Output Parameters:
272*e51e0e81SBarry Smith .   fact - must have been obtained with MatLUFactorSymbolic()
273*e51e0e81SBarry Smith @*/
274*e51e0e81SBarry Smith int MatLUFactorNumeric(Mat mat,Mat fact)
275*e51e0e81SBarry Smith {
276*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
277*e51e0e81SBarry Smith   if (!fact) SETERR(1,"Missing symbolic factorization");
278*e51e0e81SBarry Smith   if (mat->ops->lufactornumeric) return (*mat->ops->lufactornumeric)(mat,fact);
279*e51e0e81SBarry Smith   SETERR(1,"No MatLUFactorNumeric for implementation");
280*e51e0e81SBarry Smith }
281*e51e0e81SBarry Smith /*@
282*e51e0e81SBarry Smith     MatCholeskyFactor - performs an inplace CC' factorization of matrix.
283*e51e0e81SBarry Smith           See also MatLUFactor(), MatCholeskyFactorSymbolic() and
284*e51e0e81SBarry Smith           MatCholeskyFactorNumeric().
285*e51e0e81SBarry Smith 
286*e51e0e81SBarry Smith   Input Parameters:
287*e51e0e81SBarry Smith .   mat - the matrix
288*e51e0e81SBarry Smith .   perm - row and column permutations
289*e51e0e81SBarry Smith 
290*e51e0e81SBarry Smith @*/
291*e51e0e81SBarry Smith int MatCholeskyFactor(Mat mat,IS perm)
292*e51e0e81SBarry Smith {
293*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
294*e51e0e81SBarry Smith   if (mat->ops->chfactor) return (*mat->ops->chfactor)(mat,perm);
295*e51e0e81SBarry Smith   SETERR(1,"No MatCholeskyFactor for implementation");
296*e51e0e81SBarry Smith }
297*e51e0e81SBarry Smith /*@
298*e51e0e81SBarry Smith     MatCholeskyFactorSymbolic - performs a symbolic Cholesky factorization.
299*e51e0e81SBarry Smith           See also MatLUFactor(), MatCholeskyFactorSymbolic() and
300*e51e0e81SBarry Smith           MatCholeskyFactorNumeric().
301*e51e0e81SBarry Smith 
302*e51e0e81SBarry Smith   Input Parameters:
303*e51e0e81SBarry Smith .   mat - the matrix
304*e51e0e81SBarry Smith .   perm - row and column permutations
305*e51e0e81SBarry Smith 
306*e51e0e81SBarry Smith @*/
307*e51e0e81SBarry Smith int MatCholeskyFactorSymbolic(Mat mat,IS perm,Mat *fact)
308*e51e0e81SBarry Smith {
309*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
310*e51e0e81SBarry Smith   if (!fact) SETERR(1,"Missing slot for symbolic factorization");
311*e51e0e81SBarry Smith   if (mat->ops->chfactorsymbolic) return (*mat->ops->chfactorsymbolic)(mat,
312*e51e0e81SBarry Smith                                             perm,fact);
313*e51e0e81SBarry Smith   SETERR(1,"No MatCholeskyFactorSymbolic for implementation");
314*e51e0e81SBarry Smith }
315*e51e0e81SBarry Smith /*@
316*e51e0e81SBarry Smith     MatCholeskyFactorNumeric - performs a numeric Cholesky factorization.
317*e51e0e81SBarry Smith           See also MatLUFactor(),  MatCholeskyFactor() and
318*e51e0e81SBarry Smith           MatCholeskyFactorSymbolic().
319*e51e0e81SBarry Smith 
320*e51e0e81SBarry Smith   Input Parameters:
321*e51e0e81SBarry Smith .   mat - the matrix
322*e51e0e81SBarry Smith 
323*e51e0e81SBarry Smith 
324*e51e0e81SBarry Smith @*/
325*e51e0e81SBarry Smith int MatCholeskyFactorNumeric(Mat mat,Mat fact)
326*e51e0e81SBarry Smith {
327*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
328*e51e0e81SBarry Smith   if (!fact) SETERR(1,"Missing symbolic factorization");
329*e51e0e81SBarry Smith   if (mat->ops->chfactornumeric) return (*mat->ops->chfactornumeric)(mat,
330*e51e0e81SBarry Smith                                             fact);
331*e51e0e81SBarry Smith   SETERR(1,"No MatCholeskyFactorNumeric for implementation");
332*e51e0e81SBarry Smith }
333*e51e0e81SBarry Smith /* ----------------------------------------------------------------*/
334*e51e0e81SBarry Smith /*@
335*e51e0e81SBarry Smith     MatSolve - solve A x = b
336*e51e0e81SBarry Smith 
337*e51e0e81SBarry Smith   Input Parameters:
338*e51e0e81SBarry Smith .   mat - the  factored matrix
339*e51e0e81SBarry Smith .    b - the right hand side
340*e51e0e81SBarry Smith 
341*e51e0e81SBarry Smith   Output Parameter:
342*e51e0e81SBarry Smith .    x- the result
343*e51e0e81SBarry Smith @*/
344*e51e0e81SBarry Smith int MatSolve(Mat mat,Vec b,Vec x)
345*e51e0e81SBarry Smith {
346*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
347*e51e0e81SBarry Smith   VALIDHEADER(b,VEC_COOKIE);  VALIDHEADER(x,VEC_COOKIE);
348*e51e0e81SBarry Smith   if (!mat->factor) SETERR(1,"Attempt solve on nonfactored matrix");
349*e51e0e81SBarry Smith   if (mat->ops->solve) return (*mat->ops->solve)(mat,b,x);
350*e51e0e81SBarry Smith   SETERR(1,"No MatSolve for implementation");
351*e51e0e81SBarry Smith }
352*e51e0e81SBarry Smith /*@
353*e51e0e81SBarry Smith     MatSolveAdd - x = y + A^-1 b
354*e51e0e81SBarry Smith 
355*e51e0e81SBarry Smith   Input Parameters:
356*e51e0e81SBarry Smith .   mat - the  factored matrix
357*e51e0e81SBarry Smith .    b - the right hand side
358*e51e0e81SBarry Smith .    y - te vector to be added to
359*e51e0e81SBarry Smith 
360*e51e0e81SBarry Smith   Output Parameter:
361*e51e0e81SBarry Smith .    x- the result
362*e51e0e81SBarry Smith @*/
363*e51e0e81SBarry Smith int MatSolveAdd(Mat mat,Vec b,Vec y,Vec x)
364*e51e0e81SBarry Smith {
365*e51e0e81SBarry Smith   Scalar one = 1.0;
366*e51e0e81SBarry Smith   Vec    tmp;
367*e51e0e81SBarry Smith   int    ierr;
368*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);VALIDHEADER(y,VEC_COOKIE);
369*e51e0e81SBarry Smith   VALIDHEADER(b,VEC_COOKIE);  VALIDHEADER(x,VEC_COOKIE);
370*e51e0e81SBarry Smith   if (!mat->factor) SETERR(1,"Attempt solve on nonfactored matrix");
371*e51e0e81SBarry Smith   if (mat->ops->solveadd) return (*mat->ops->solveadd)(mat,b,y,x);
372*e51e0e81SBarry Smith   /* do the solve then the add manually */
373*e51e0e81SBarry Smith   if (x != y) {
374*e51e0e81SBarry Smith     ierr = MatSolve(mat,b,x); CHKERR(ierr);
375*e51e0e81SBarry Smith     ierr = VecAXPY(&one,y,x); CHKERR(ierr);
376*e51e0e81SBarry Smith     return 0;
377*e51e0e81SBarry Smith   }
378*e51e0e81SBarry Smith   else {
379*e51e0e81SBarry Smith     ierr = VecCreate(x,&tmp); CHKERR(ierr);
380*e51e0e81SBarry Smith     ierr = VecCopy(x,tmp); CHKERR(ierr);
381*e51e0e81SBarry Smith     ierr = MatSolve(mat,b,x); CHKERR(ierr);
382*e51e0e81SBarry Smith     ierr = VecAXPY(&one,tmp,x); CHKERR(ierr);
383*e51e0e81SBarry Smith     ierr = VecDestroy(tmp); CHKERR(ierr);
384*e51e0e81SBarry Smith     return 0;
385*e51e0e81SBarry Smith   }
386*e51e0e81SBarry Smith }
387*e51e0e81SBarry Smith /*@
388*e51e0e81SBarry Smith     MatSolveTrans - solve A' x = b
389*e51e0e81SBarry Smith 
390*e51e0e81SBarry Smith   Input Parameters:
391*e51e0e81SBarry Smith .   mat - the  factored matrix
392*e51e0e81SBarry Smith .    b - the right hand side
393*e51e0e81SBarry Smith 
394*e51e0e81SBarry Smith   Output Parameter:
395*e51e0e81SBarry Smith .    x- the result
396*e51e0e81SBarry Smith @*/
397*e51e0e81SBarry Smith int MatSolveTrans(Mat mat,Vec b,Vec x)
398*e51e0e81SBarry Smith {
399*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
400*e51e0e81SBarry Smith   VALIDHEADER(b,VEC_COOKIE);  VALIDHEADER(x,VEC_COOKIE);
401*e51e0e81SBarry Smith   if (!mat->factor) SETERR(1,"Attempt solve on nonfactored matrix");
402*e51e0e81SBarry Smith   if (mat->ops->solvetrans) return (*mat->ops->solvetrans)(mat,b,x);
403*e51e0e81SBarry Smith   SETERR(1,"No MatSolveTrans for implementation");
404*e51e0e81SBarry Smith }
405*e51e0e81SBarry Smith /*@
406*e51e0e81SBarry Smith     MatSolveTransAdd - x = y + A^-T b
407*e51e0e81SBarry Smith 
408*e51e0e81SBarry Smith   Input Parameters:
409*e51e0e81SBarry Smith .   mat - the  factored matrix
410*e51e0e81SBarry Smith .    b - the right hand side
411*e51e0e81SBarry Smith .    y - te vector to be added to
412*e51e0e81SBarry Smith 
413*e51e0e81SBarry Smith   Output Parameter:
414*e51e0e81SBarry Smith .    x- the result
415*e51e0e81SBarry Smith @*/
416*e51e0e81SBarry Smith int MatSolveTransAdd(Mat mat,Vec b,Vec y,Vec x)
417*e51e0e81SBarry Smith {
418*e51e0e81SBarry Smith   Scalar one = 1.0;
419*e51e0e81SBarry Smith   int    ierr;
420*e51e0e81SBarry Smith   Vec    tmp;
421*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);VALIDHEADER(y,VEC_COOKIE);
422*e51e0e81SBarry Smith   VALIDHEADER(b,VEC_COOKIE);  VALIDHEADER(x,VEC_COOKIE);
423*e51e0e81SBarry Smith   if (!mat->factor) SETERR(1,"Attempt solve on nonfactored matrix");
424*e51e0e81SBarry Smith   if (mat->ops->solvetransadd) return (*mat->ops->solvetransadd)(mat,b,y,x);
425*e51e0e81SBarry Smith   /* do the solve then the add manually */
426*e51e0e81SBarry Smith   if (x != y) {
427*e51e0e81SBarry Smith     ierr = MatSolveTrans(mat,b,x); CHKERR(ierr);
428*e51e0e81SBarry Smith     ierr = VecAXPY(&one,y,x); CHKERR(ierr);
429*e51e0e81SBarry Smith     return 0;
430*e51e0e81SBarry Smith   }
431*e51e0e81SBarry Smith   else {
432*e51e0e81SBarry Smith     ierr = VecCreate(x,&tmp); CHKERR(ierr);
433*e51e0e81SBarry Smith     ierr = VecCopy(x,tmp); CHKERR(ierr);
434*e51e0e81SBarry Smith     ierr = MatSolveTrans(mat,b,x); CHKERR(ierr);
435*e51e0e81SBarry Smith     ierr = VecAXPY(&one,tmp,x); CHKERR(ierr);
436*e51e0e81SBarry Smith     ierr = VecDestroy(tmp); CHKERR(ierr);
437*e51e0e81SBarry Smith     return 0;
438*e51e0e81SBarry Smith   }
439*e51e0e81SBarry Smith }
440*e51e0e81SBarry Smith /* ----------------------------------------------------------------*/
441*e51e0e81SBarry Smith 
442*e51e0e81SBarry Smith /*@
443*e51e0e81SBarry Smith     MatRelax - one relaxation sweep
444*e51e0e81SBarry Smith 
445*e51e0e81SBarry Smith   Input Parameters:
446*e51e0e81SBarry Smith .  mat - the matrix
447*e51e0e81SBarry Smith .  b - the right hand side
448*e51e0e81SBarry Smith .  omega - the relaxation factor
449*e51e0e81SBarry Smith .  flag - or together from  SOR_FORWARD_SWEEP, SOR_BACKWARD_SWEEP,
450*e51e0e81SBarry Smith .         SOR_ZERO_INITIAL_GUESS. (SOR_SYMMETRIC_SWEEP is
451*e51e0e81SBarry Smith .         equivalent to SOR_FORWARD_SWEEP | SOR_BACKWARD_SWEEP)
452*e51e0e81SBarry Smith .  is - optional index set indicating ordering
453*e51e0e81SBarry Smith .  its - the number of iterations
454*e51e0e81SBarry Smith 
455*e51e0e81SBarry Smith   Output Parameters:
456*e51e0e81SBarry Smith .  x - the solution - can contain initial guess
457*e51e0e81SBarry Smith @*/
458*e51e0e81SBarry Smith int MatRelax(Mat mat,Vec b,double omega,int flag,IS is,int its,Vec x)
459*e51e0e81SBarry Smith {
460*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
461*e51e0e81SBarry Smith   VALIDHEADER(b,VEC_COOKIE);  VALIDHEADER(x,VEC_COOKIE);
462*e51e0e81SBarry Smith   if (flag < 1 || flag > 7) SETERR(1,"Bad relaxation type");
463*e51e0e81SBarry Smith   if (mat->ops->relax) return (*mat->ops->relax)(mat,b,omega,flag,is,its,x);
464*e51e0e81SBarry Smith   SETERR(1,"No MatRelax for implementation");
465*e51e0e81SBarry Smith }
466*e51e0e81SBarry Smith 
467*e51e0e81SBarry Smith /* ----------------------------------------------------------------*/
468*e51e0e81SBarry Smith /*@
469*e51e0e81SBarry Smith     MatCopy - copies a matrix
470*e51e0e81SBarry Smith 
471*e51e0e81SBarry Smith   Input Parameters:
472*e51e0e81SBarry Smith .   mat - the matrix
473*e51e0e81SBarry Smith 
474*e51e0e81SBarry Smith   Output Parameters:
475*e51e0e81SBarry Smith .    M - pointer to place new matrix
476*e51e0e81SBarry Smith @*/
477*e51e0e81SBarry Smith int MatCopy(Mat mat,Mat *M)
478*e51e0e81SBarry Smith {
479*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
480*e51e0e81SBarry Smith   if (mat->ops->copy) return (*mat->ops->copy)(mat,M);
481*e51e0e81SBarry Smith   SETERR(1,"No MatCopy for implementation");
482*e51e0e81SBarry Smith }
483*e51e0e81SBarry Smith 
484*e51e0e81SBarry Smith /*@
485*e51e0e81SBarry Smith      MatGetDiagonal - get diagonal of matrix
486*e51e0e81SBarry Smith 
487*e51e0e81SBarry Smith   Input Parameters:
488*e51e0e81SBarry Smith .  mat - the matrix
489*e51e0e81SBarry Smith 
490*e51e0e81SBarry Smith   Output Parameters:
491*e51e0e81SBarry Smith .  v - the vector to store the diagonal in
492*e51e0e81SBarry Smith @*/
493*e51e0e81SBarry Smith int MatGetDiagonal(Mat mat,Vec v)
494*e51e0e81SBarry Smith {
495*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
496*e51e0e81SBarry Smith   VALIDHEADER(v,VEC_COOKIE);
497*e51e0e81SBarry Smith   if (mat->ops->getdiag) return (*mat->ops->getdiag)(mat,v);
498*e51e0e81SBarry Smith   SETERR(1,"No MatGetDiagonal for implementaion");
499*e51e0e81SBarry Smith }
500*e51e0e81SBarry Smith 
501*e51e0e81SBarry Smith /*@
502*e51e0e81SBarry Smith      MatTranspose - in place transpose of matrix
503*e51e0e81SBarry Smith 
504*e51e0e81SBarry Smith   Input Parameters:
505*e51e0e81SBarry Smith .   mat - the matrix to transpose
506*e51e0e81SBarry Smith @*/
507*e51e0e81SBarry Smith int MatTranspose(Mat mat)
508*e51e0e81SBarry Smith {
509*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
510*e51e0e81SBarry Smith   if (mat->ops->trans) return (*mat->ops->trans)(mat);
511*e51e0e81SBarry Smith   SETERR(1,"No MatTranspose for implementaion");
512*e51e0e81SBarry Smith }
513*e51e0e81SBarry Smith 
514*e51e0e81SBarry Smith /*@
515*e51e0e81SBarry Smith     MatEqual - returns 1 if two matrices are equal
516*e51e0e81SBarry Smith 
517*e51e0e81SBarry Smith   Input Parameters:
518*e51e0e81SBarry Smith .  mat1, mat2 - the matrices
519*e51e0e81SBarry Smith 
520*e51e0e81SBarry Smith   OutPut Parameter:
521*e51e0e81SBarry Smith .   returns 1 if matrices are equal
522*e51e0e81SBarry Smith @*/
523*e51e0e81SBarry Smith int MatEqual(Mat mat1,Mat mat2)
524*e51e0e81SBarry Smith {
525*e51e0e81SBarry Smith   VALIDHEADER(mat1,MAT_COOKIE); VALIDHEADER(mat2,MAT_COOKIE);
526*e51e0e81SBarry Smith   if (mat1->ops->equal) return (*mat1->ops->equal)(mat1,mat2);
527*e51e0e81SBarry Smith   SETERR(1,"No MatEqual for implementaion");
528*e51e0e81SBarry Smith }
529*e51e0e81SBarry Smith 
530*e51e0e81SBarry Smith /*@
531*e51e0e81SBarry Smith      MatScale - scale a matrix on the left and right by diagonal
532*e51e0e81SBarry Smith                 matrices stored as vectors. Either of the two may be
533*e51e0e81SBarry Smith                 null.
534*e51e0e81SBarry Smith 
535*e51e0e81SBarry Smith   Input Parameters:
536*e51e0e81SBarry Smith .   mat - the matrix to be scaled
537*e51e0e81SBarry Smith .   l,r - the left and right scaling vectors
538*e51e0e81SBarry Smith @*/
539*e51e0e81SBarry Smith int MatScale(Mat mat,Vec l,Vec r)
540*e51e0e81SBarry Smith {
541*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
542*e51e0e81SBarry Smith   VALIDHEADER(l,VEC_COOKIE); VALIDHEADER(r,VEC_COOKIE);
543*e51e0e81SBarry Smith   if (mat->ops->scale) return (*mat->ops->scale)(mat,l,r);
544*e51e0e81SBarry Smith   SETERR(1,"No MatScale for implementaion");
545*e51e0e81SBarry Smith }
546*e51e0e81SBarry Smith 
547*e51e0e81SBarry Smith /*@
548*e51e0e81SBarry Smith      MatNorm - calculate various norms of a matrix
549*e51e0e81SBarry Smith 
550*e51e0e81SBarry Smith   Input Parameters:
551*e51e0e81SBarry Smith .  mat - the matrix
552*e51e0e81SBarry Smith .  type - the type of norm, NORM_1, NORM_2, NORM_FROBENIUS, NORM_INFINITY
553*e51e0e81SBarry Smith 
554*e51e0e81SBarry Smith   Output Parameters:
555*e51e0e81SBarry Smith .  norm - the resulting norm
556*e51e0e81SBarry Smith @*/
557*e51e0e81SBarry Smith int MatNorm(Mat mat,int type,double *norm)
558*e51e0e81SBarry Smith {
559*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
560*e51e0e81SBarry Smith   if (mat->ops->norm) return (*mat->ops->norm)(mat,type,norm);
561*e51e0e81SBarry Smith   SETERR(1,"No MatNorm for implementaion");
562*e51e0e81SBarry Smith }
563*e51e0e81SBarry Smith 
564*e51e0e81SBarry Smith /*@
565*e51e0e81SBarry Smith      MatBeginAssembly - begin assemblying the matrix. This should
566*e51e0e81SBarry Smith                         be called after all the calls to MatInsertValues()
567*e51e0e81SBarry Smith                         and MatAddValues().
568*e51e0e81SBarry Smith 
569*e51e0e81SBarry Smith   Input Parameters:
570*e51e0e81SBarry Smith .  mat - the matrix
571*e51e0e81SBarry Smith 
572*e51e0e81SBarry Smith    Note: when you call MatInsertValues() it generally caches the values
573*e51e0e81SBarry Smith          only after you have called MatBeginAssembly() and
574*e51e0e81SBarry Smith          MatEndAssembly() is the matrix ready to be used.
575*e51e0e81SBarry Smith @*/
576*e51e0e81SBarry Smith int MatBeginAssembly(Mat mat)
577*e51e0e81SBarry Smith {
578*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
579*e51e0e81SBarry Smith   if (mat->ops->bassembly) return (*mat->ops->bassembly)(mat);
580*e51e0e81SBarry Smith   return 0;
581*e51e0e81SBarry Smith }
582*e51e0e81SBarry Smith /*@
583*e51e0e81SBarry Smith      MatEndAssembly - begin assemblying the matrix. This should
584*e51e0e81SBarry Smith                         be called after all the calls to MatInsertValues()
585*e51e0e81SBarry Smith                         and MatAddValues() and after MatBeginAssembly().
586*e51e0e81SBarry Smith 
587*e51e0e81SBarry Smith   Input Parameters:
588*e51e0e81SBarry Smith .  mat - the matrix
589*e51e0e81SBarry Smith 
590*e51e0e81SBarry Smith    Note: when you call MatInsertValues() it generally caches the values
591*e51e0e81SBarry Smith          only after you have called MatBeginAssembly() and
592*e51e0e81SBarry Smith          MatEndAssembly() is the matrix ready to be used.
593*e51e0e81SBarry Smith @*/
594*e51e0e81SBarry Smith int MatEndAssembly(Mat mat)
595*e51e0e81SBarry Smith {
596*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
597*e51e0e81SBarry Smith   if (mat->ops->eassembly) return (*mat->ops->eassembly)(mat);
598*e51e0e81SBarry Smith   return 0;
599*e51e0e81SBarry Smith }
600*e51e0e81SBarry Smith /*@
601*e51e0e81SBarry Smith      MatCompress - trys to store matrix in as little space as
602*e51e0e81SBarry Smith         possible. May fail if memory is already fully used as
603*e51e0e81SBarry Smith         it tries to allocate new space.
604*e51e0e81SBarry Smith 
605*e51e0e81SBarry Smith   Input Parameters:
606*e51e0e81SBarry Smith .  mat - the matrix
607*e51e0e81SBarry Smith 
608*e51e0e81SBarry Smith @*/
609*e51e0e81SBarry Smith int MatCompress(Mat mat)
610*e51e0e81SBarry Smith {
611*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
612*e51e0e81SBarry Smith   if (mat->ops->compress) return (*mat->ops->compress)(mat);
613*e51e0e81SBarry Smith   return 0;
614*e51e0e81SBarry Smith }
615*e51e0e81SBarry Smith /*@
616*e51e0e81SBarry Smith      MatSetInsertOption - set parameter option on how you will insert
617*e51e0e81SBarry Smith          (or add) values. In general sorted, row oriented input will assemble
618*e51e0e81SBarry Smith          fastest. Defaults to row oriented, nonsorted input. Note that
619*e51e0e81SBarry Smith          if you are using a Fortran 77 module to compute an element
620*e51e0e81SBarry Smith          stiffness you may need to modify the module or use column
621*e51e0e81SBarry Smith          oriented input.
622*e51e0e81SBarry Smith 
623*e51e0e81SBarry Smith   Input Parameters:
624*e51e0e81SBarry Smith .  mat - the matrix
625*e51e0e81SBarry Smith .  option - one of ROW_ORIENTED, COLUMN_ORIENTED, ROWS_SORTED,
626*e51e0e81SBarry Smith                    COLUMNS_SORTED, NO_NEW_NONZERO_LOCATIONS
627*e51e0e81SBarry Smith 
628*e51e0e81SBarry Smith        NO_NEW_NONZERO_LOCATIONS indicates that any add or insertion
629*e51e0e81SBarry Smith that will generate a new entry in the nonzero structure is ignored.
630*e51e0e81SBarry Smith What this means is if memory is not allocated for this particular
631*e51e0e81SBarry Smith lot then the insertion is ignored. For dense matrices where
632*e51e0e81SBarry Smith the entire array is allocated no entries are every ignored. This
633*e51e0e81SBarry Smith may not be a good idea??
634*e51e0e81SBarry Smith 
635*e51e0e81SBarry Smith @*/
636*e51e0e81SBarry Smith int MatSetInsertOption(Mat mat,int op)
637*e51e0e81SBarry Smith {
638*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
639*e51e0e81SBarry Smith   if (op < 0 || op > 7) SETERR(1,"Invalid option to MatSetInsertOption");
640*e51e0e81SBarry Smith   if (mat->ops->insopt) return (*mat->ops->insopt)(mat,op);
641*e51e0e81SBarry Smith   return 0;
642*e51e0e81SBarry Smith }
643*e51e0e81SBarry Smith 
644*e51e0e81SBarry Smith /*@
645*e51e0e81SBarry Smith      MatZeroEntries - zeros all entries in a matrix. For sparse matrices
646*e51e0e81SBarry Smith          it keeps the old nonzero structure.
647*e51e0e81SBarry Smith 
648*e51e0e81SBarry Smith   Input Parameters:
649*e51e0e81SBarry Smith .  mat - the matrix
650*e51e0e81SBarry Smith 
651*e51e0e81SBarry Smith @*/
652*e51e0e81SBarry Smith int MatZeroEntries(Mat mat)
653*e51e0e81SBarry Smith {
654*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
655*e51e0e81SBarry Smith   if (mat->ops->zeroentries) return (*mat->ops->zeroentries)(mat);
656*e51e0e81SBarry Smith   SETERR(1,"No MatZeroEntries for implementation");
657*e51e0e81SBarry Smith }
658*e51e0e81SBarry Smith 
659*e51e0e81SBarry Smith /*@
660*e51e0e81SBarry Smith      MatZeroRow - zeros all entries in a row of a matrix. For sparse matrices
661*e51e0e81SBarry Smith          it removes the old nonzero structure.
662*e51e0e81SBarry Smith 
663*e51e0e81SBarry Smith   Input Parameters:
664*e51e0e81SBarry Smith .  mat - the matrix
665*e51e0e81SBarry Smith .  row - the row to zap
666*e51e0e81SBarry Smith 
667*e51e0e81SBarry Smith @*/
668*e51e0e81SBarry Smith int MatZeroRow(int row,Mat mat)
669*e51e0e81SBarry Smith {
670*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);
671*e51e0e81SBarry Smith   if (mat->ops->zerorow) return (*mat->ops->zerorow)(row,mat);
672*e51e0e81SBarry Smith   SETERR(1,"No MatZeroRow for implementation");
673*e51e0e81SBarry Smith }
674*e51e0e81SBarry Smith 
675*e51e0e81SBarry Smith /*@
676*e51e0e81SBarry Smith      MatScatterBegin - Begins a scatter of one matrix into another.
677*e51e0e81SBarry Smith          This is much more general than a standard scatter, it include
678*e51e0e81SBarry Smith          scatter, gather and cmobinations. In a parallel enviroment
679*e51e0e81SBarry Smith          it can be used to simultaneous gather from a global matrix
680*e51e0e81SBarry Smith          into local and vice-versa.
681*e51e0e81SBarry Smith 
682*e51e0e81SBarry Smith   Input Parameters:
683*e51e0e81SBarry Smith .  mat - the matrix
684*e51e0e81SBarry Smith .  is1,is2 - the rows and columns to snag
685*e51e0e81SBarry Smith .  is3,is4 - rows and columns to drop snagged in
686*e51e0e81SBarry Smith 
687*e51e0e81SBarry Smith   Output Paramters:
688*e51e0e81SBarry Smith .  out - matrix to receive
689*e51e0e81SBarry Smith .  ctx - optional pointer to MatScatterCtx - allows reuse of communcation
690*e51e0e81SBarry Smith          pattern if same scatter used more than once.
691*e51e0e81SBarry Smith 
692*e51e0e81SBarry Smith   Keywords: matrix, scatter, gather
693*e51e0e81SBarry Smith @*/
694*e51e0e81SBarry Smith int MatScatterBegin(Mat mat,IS is1,IS is2,Mat out,IS is3, IS is4,
695*e51e0e81SBarry Smith                                                  MatScatterCtx *ctx)
696*e51e0e81SBarry Smith {
697*e51e0e81SBarry Smith   VALIDHEADER(mat,MAT_COOKIE);  VALIDHEADER(out,MAT_COOKIE);
698*e51e0e81SBarry Smith   if (mat->ops->scatbegin)
699*e51e0e81SBarry Smith     return (*mat->ops->scatbegin)(mat,is1,is2,out,is3,is4,ctx);
700*e51e0e81SBarry Smith   SETERR(1,"No MatScatterBegin for implementation");
701*e51e0e81SBarry Smith }
702*e51e0e81SBarry Smith 
703