xref: /petsc/src/mat/impls/aij/seq/superlu/superlu.c (revision a2ec6df8280ae283e8b0f45d20ebe04f5d3dfc7b)
1 /*$Id: superlu.c,v 1.10 2001/08/15 15:56:50 bsmith Exp $*/
2 
3 /*
4         Provides an interface to the SuperLU sparse solver
5           Modified for SuperLU 2.0 by Matthew Knepley
6 */
7 
8 #include "src/mat/impls/aij/seq/aij.h"
9 
10 EXTERN_C_BEGIN
11 #if defined(PETSC_USE_COMPLEX)
12 #include "zsp_defs.h"
13 #else
14 #include "dsp_defs.h"
15 #endif
16 #include "util.h"
17 EXTERN_C_END
18 
19 typedef struct {
20   SuperMatrix  A,B,AC,L,U;
21   int          *perm_r,*perm_c,ispec,relax,panel_size;
22   double       pivot_threshold;
23   NCformat     *store;
24   MatStructure flg;
25   PetscTruth   SuperluMatOdering;
26 
27   /* A few function pointers for inheritance */
28   int (*MatDuplicate)(Mat,MatDuplicateOption,Mat*);
29   int (*MatView)(Mat,PetscViewer);
30   int (*MatAssemblyEnd)(Mat,MatAssemblyType);
31   int (*MatLUFactorSymbolic)(Mat,IS,IS,MatFactorInfo*,Mat*);
32   int (*MatDestroy)(Mat);
33 
34   /* Flag to clean up (non-global) SuperLU objects during Destroy */
35   PetscTruth CleanUpSuperLU;
36 } Mat_SuperLU;
37 
38 
39 EXTERN int MatFactorInfo_SuperLU(Mat,PetscViewer);
40 EXTERN int MatLUFactorSymbolic_SuperLU(Mat,IS,IS,MatFactorInfo*,Mat*);
41 
42 EXTERN_C_BEGIN
43 EXTERN int MatConvert_SuperLU_SeqAIJ(Mat,MatType,Mat*);
44 EXTERN int MatConvert_SeqAIJ_SuperLU(Mat,MatType,Mat*);
45 EXTERN_C_END
46 
47 #undef __FUNCT__
48 #define __FUNCT__ "MatDestroy_SuperLU"
49 int MatDestroy_SuperLU(Mat A)
50 {
51   int         ierr;
52   Mat_SuperLU *lu = (Mat_SuperLU*)A->spptr;
53 
54   PetscFunctionBegin;
55   if (lu->CleanUpSuperLU) {
56     /* We have to free the global data or SuperLU crashes (sucky design)*/
57     /* Since we don't know if more solves on other matrices may be done
58        we cannot free the yucky SuperLU global data
59        StatFree();
60     */
61 
62     /* Free the SuperLU datastructures */
63     Destroy_CompCol_Permuted(&lu->AC);
64     Destroy_SuperNode_Matrix(&lu->L);
65     Destroy_CompCol_Matrix(&lu->U);
66     ierr = PetscFree(lu->B.Store);CHKERRQ(ierr);
67     ierr = PetscFree(lu->A.Store);CHKERRQ(ierr);
68     ierr = PetscFree(lu->perm_r);CHKERRQ(ierr);
69     ierr = PetscFree(lu->perm_c);CHKERRQ(ierr);
70   }
71   ierr = MatConvert_SuperLU_SeqAIJ(A,MATSEQAIJ,&A);CHKERRQ(ierr);
72   ierr = (*A->ops->destroy)(A);CHKERRQ(ierr);
73   PetscFunctionReturn(0);
74 }
75 
76 #undef __FUNCT__
77 #define __FUNCT__ "MatView_SuperLU"
78 int MatView_SuperLU(Mat A,PetscViewer viewer)
79 {
80   int               ierr;
81   PetscTruth        isascii;
82   PetscViewerFormat format;
83   Mat_SuperLU       *lu=(Mat_SuperLU*)(A->spptr);
84 
85   PetscFunctionBegin;
86   ierr = (*lu->MatView)(A,viewer);CHKERRQ(ierr);
87 
88   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);CHKERRQ(ierr);
89   if (isascii) {
90     ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr);
91     if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) {
92       ierr = MatFactorInfo_SuperLU(A,viewer);CHKERRQ(ierr);
93     }
94   }
95   PetscFunctionReturn(0);
96 }
97 
98 #undef __FUNCT__
99 #define __FUNCT__ "MatAssemblyEnd_SuperLU"
100 int MatAssemblyEnd_SuperLU(Mat A,MatAssemblyType mode) {
101   int         ierr;
102   Mat_SuperLU *lu=(Mat_SuperLU*)(A->spptr);
103 
104   PetscFunctionBegin;
105   ierr = (*lu->MatAssemblyEnd)(A,mode);CHKERRQ(ierr);
106 
107   lu->MatLUFactorSymbolic  = A->ops->lufactorsymbolic;
108   A->ops->lufactorsymbolic = MatLUFactorSymbolic_SuperLU;
109   PetscFunctionReturn(0);
110 }
111 
112 #include "src/mat/impls/dense/seq/dense.h"
113 #undef __FUNCT__
114 #define __FUNCT__ "MatCreateNull_SuperLU"
115 int MatCreateNull_SuperLU(Mat A,Mat *nullMat)
116 {
117   Mat_SuperLU   *lu = (Mat_SuperLU*)A->spptr;
118   int           numRows = A->m,numCols = A->n;
119   SCformat      *Lstore;
120   int           numNullCols,size;
121 #if defined(PETSC_USE_COMPLEX)
122   doublecomplex *nullVals,*workVals;
123 #else
124   PetscScalar   *nullVals,*workVals;
125 #endif
126   int           row,newRow,col,newCol,block,b,ierr;
127 
128   PetscFunctionBegin;
129   PetscValidHeaderSpecific(A,MAT_COOKIE);
130   PetscValidPointer(nullMat);
131   if (!A->factor) SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Unfactored matrix");
132   numNullCols = numCols - numRows;
133   if (numNullCols < 0) SETERRQ(PETSC_ERR_ARG_WRONG,"Function only applies to underdetermined problems");
134   /* Create the null matrix */
135   ierr = MatCreateSeqDense(A->comm,numRows,numNullCols,PETSC_NULL,nullMat);CHKERRQ(ierr);
136   if (numNullCols == 0) {
137     ierr = MatAssemblyBegin(*nullMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
138     ierr = MatAssemblyEnd(*nullMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
139     PetscFunctionReturn(0);
140   }
141 #if defined(PETSC_USE_COMPLEX)
142   nullVals = (doublecomplex*)((Mat_SeqDense*)(*nullMat)->data)->v;
143 #else
144   nullVals = ((Mat_SeqDense*)(*nullMat)->data)->v;
145 #endif
146   /* Copy in the columns */
147   Lstore = (SCformat*)lu->L.Store;
148   for(block = 0; block <= Lstore->nsuper; block++) {
149     newRow = Lstore->sup_to_col[block];
150     size   = Lstore->sup_to_col[block+1] - Lstore->sup_to_col[block];
151     for(col = Lstore->rowind_colptr[newRow]; col < Lstore->rowind_colptr[newRow+1]; col++) {
152       newCol = Lstore->rowind[col];
153       if (newCol >= numRows) {
154         for(b = 0; b < size; b++)
155 #if defined(PETSC_USE_COMPLEX)
156           nullVals[(newCol-numRows)*numRows+newRow+b] = ((doublecomplex*)Lstore->nzval)[Lstore->nzval_colptr[newRow+b]+col];
157 #else
158           nullVals[(newCol-numRows)*numRows+newRow+b] = ((double*)Lstore->nzval)[Lstore->nzval_colptr[newRow+b]+col];
159 #endif
160       }
161     }
162   }
163   /* Permute rhs to form P^T_c B */
164   ierr = PetscMalloc(numRows*sizeof(double),&workVals);CHKERRQ(ierr);
165   for(b = 0; b < numNullCols; b++) {
166     for(row = 0; row < numRows; row++) workVals[lu->perm_c[row]] = nullVals[b*numRows+row];
167     for(row = 0; row < numRows; row++) nullVals[b*numRows+row]   = workVals[row];
168   }
169   /* Backward solve the upper triangle A x = b */
170   for(b = 0; b < numNullCols; b++) {
171 #if defined(PETSC_USE_COMPLEX)
172     sp_ztrsv("L","T","U",&lu->L,&lu->U,&nullVals[b*numRows],&ierr);
173 #else
174     sp_dtrsv("L","T","U",&lu->L,&lu->U,&nullVals[b*numRows],&ierr);
175 #endif
176     if (ierr < 0)
177       SETERRQ1(PETSC_ERR_ARG_WRONG,"The argument %d was invalid",-ierr);
178   }
179   ierr = PetscFree(workVals);CHKERRQ(ierr);
180 
181   ierr = MatAssemblyBegin(*nullMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
182   ierr = MatAssemblyEnd(*nullMat,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
183   PetscFunctionReturn(0);
184 }
185 
186 #undef __FUNCT__
187 #define __FUNCT__ "MatSolve_SuperLU"
188 int MatSolve_SuperLU(Mat A,Vec b,Vec x)
189 {
190   Mat_SuperLU *lu = (Mat_SuperLU*)A->spptr;
191   PetscScalar *array;
192   int         m,ierr;
193 
194   PetscFunctionBegin;
195   ierr = VecGetLocalSize(b,&m);CHKERRQ(ierr);
196   ierr = VecCopy(b,x);CHKERRQ(ierr);
197   ierr = VecGetArray(x,&array);CHKERRQ(ierr);
198   /* Create the Rhs */
199   lu->B.Stype        = SLU_DN;
200   lu->B.Mtype        = SLU_GE;
201   lu->B.nrow         = m;
202   lu->B.ncol         = 1;
203   ((DNformat*)lu->B.Store)->lda   = m;
204   ((DNformat*)lu->B.Store)->nzval = array;
205 #if defined(PETSC_USE_COMPLEX)
206   lu->B.Dtype        = SLU_Z;
207   zgstrs("T",&lu->L,&lu->U,lu->perm_r,lu->perm_c,&lu->B,&ierr);
208 #else
209   lu->B.Dtype        = SLU_D;
210   dgstrs("T",&lu->L,&lu->U,lu->perm_r,lu->perm_c,&lu->B,&ierr);
211 #endif
212   if (ierr < 0) SETERRQ1(PETSC_ERR_ARG_WRONG,"The diagonal element of row %d was invalid",-ierr);
213   ierr = VecRestoreArray(x,&array);CHKERRQ(ierr);
214   PetscFunctionReturn(0);
215 }
216 
217 static int StatInitCalled = 0;
218 
219 #undef __FUNCT__
220 #define __FUNCT__ "MatLUFactorNumeric_SuperLU"
221 int MatLUFactorNumeric_SuperLU(Mat A,Mat *F)
222 {
223   Mat_SeqAIJ  *aa = (Mat_SeqAIJ*)(A)->data;
224   Mat_SuperLU *lu = (Mat_SuperLU*)(*F)->spptr;
225   int         *etree,ierr;
226   PetscTruth  flag;
227 
228   PetscFunctionBegin;
229   /* Create the SuperMatrix for A^T:
230        Since SuperLU only likes column-oriented matrices,we pass it the transpose,
231        and then solve A^T X = B in MatSolve().
232   */
233 
234   if ( lu->flg == DIFFERENT_NONZERO_PATTERN){ /* first numerical factorization */
235     lu->A.Stype   = SLU_NC;
236 #if defined(PETSC_USE_COMPLEX)
237     lu->A.Dtype   = SLU_Z;
238 #else
239     lu->A.Dtype   = SLU_D;
240 #endif
241     lu->A.Mtype   = SLU_GE;
242     lu->A.nrow    = A->n;
243     lu->A.ncol    = A->m;
244 
245     ierr = PetscMalloc(sizeof(NCformat),&lu->store);CHKERRQ(ierr);
246     ierr = PetscMalloc(sizeof(DNformat),&lu->B.Store);CHKERRQ(ierr);
247   }
248   lu->store->nnz    = aa->nz;
249   lu->store->colptr = aa->i;
250   lu->store->rowind = aa->j;
251   lu->store->nzval  = aa->a;
252   lu->A.Store       = lu->store;
253 
254   /* Set SuperLU options */
255   lu->relax      = sp_ienv(2);
256   lu->panel_size = sp_ienv(1);
257   /* We have to initialize global data or SuperLU crashes (sucky design) */
258   if (!StatInitCalled) {
259     StatInit(lu->panel_size,lu->relax);
260   }
261   StatInitCalled++;
262 
263   ierr = PetscOptionsBegin(A->comm,A->prefix,"SuperLU Options","Mat");CHKERRQ(ierr);
264   /* use SuperLU mat ordeing */
265   ierr = PetscOptionsInt("-mat_superlu_ordering","SuperLU ordering type (one of 0, 1, 2, 3)\n   0: natural ordering;\n   1: MMD applied to A'*A;\n   2: MMD applied to A'+A;\n   3: COLAMD, approximate minimum degree column ordering","None",lu->ispec,&lu->ispec,&flag);CHKERRQ(ierr);
266   if (flag) {
267     get_perm_c(lu->ispec, &lu->A, lu->perm_c);
268     lu->SuperluMatOdering = PETSC_TRUE;
269   }
270   PetscOptionsEnd();
271 
272   /* Create the elimination tree */
273   ierr = PetscMalloc(A->n*sizeof(int),&etree);CHKERRQ(ierr);
274   sp_preorder("N",&lu->A,lu->perm_c,etree,&lu->AC);
275   /* Factor the matrix */
276 #if defined(PETSC_USE_COMPLEX)
277   zgstrf("N",&lu->AC,lu->pivot_threshold,0.0,lu->relax,lu->panel_size,etree,PETSC_NULL,0,lu->perm_r,lu->perm_c,&lu->L,&lu->U,&ierr);
278 #else
279   dgstrf("N",&lu->AC,lu->pivot_threshold,0.0,lu->relax,lu->panel_size,etree,PETSC_NULL,0,lu->perm_r,lu->perm_c,&lu->L,&lu->U,&ierr);
280 #endif
281   if (ierr < 0) {
282     SETERRQ1(PETSC_ERR_ARG_WRONG,"The diagonal element of row %d was invalid",-ierr);
283   } else if (ierr > 0) {
284     if (ierr <= A->m) {
285       SETERRQ1(PETSC_ERR_ARG_WRONG,"The diagonal element %d of U is exactly zero",ierr);
286     } else {
287       SETERRQ1(PETSC_ERR_ARG_WRONG,"Memory allocation failure after %d bytes were allocated",ierr-A->m);
288     }
289   }
290 
291   /* Cleanup */
292   ierr = PetscFree(etree);CHKERRQ(ierr);
293 
294   lu->flg = SAME_NONZERO_PATTERN;
295   PetscFunctionReturn(0);
296 }
297 
298 /*
299    Note the r permutation is ignored
300 */
301 #undef __FUNCT__
302 #define __FUNCT__ "MatLUFactorSymbolic_SuperLU"
303 int MatLUFactorSymbolic_SuperLU(Mat A,IS r,IS c,MatFactorInfo *info,Mat *F)
304 {
305   Mat                 B;
306   Mat_SuperLU  *lu;
307   int                 ierr,*ca;
308 
309   PetscFunctionBegin;
310 
311   ierr = MatCreate(A->comm,A->m,A->n,PETSC_DETERMINE,PETSC_DETERMINE,&B);CHKERRQ(ierr);
312   ierr = MatSetType(B,MATSUPERLU);CHKERRQ(ierr);
313   ierr = MatSeqAIJSetPreallocation(B,0,PETSC_NULL);CHKERRQ(ierr);
314 
315   B->ops->lufactornumeric = MatLUFactorNumeric_SuperLU;
316   B->ops->solve           = MatSolve_SuperLU;
317   B->factor               = FACTOR_LU;
318   B->assembled            = PETSC_TRUE;  /* required by -sles_view */
319 
320   lu = (Mat_SuperLU*)(B->spptr);
321   ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatCreateNull","MatCreateNull_SuperLU",
322                                     (void(*)(void))MatCreateNull_SuperLU);CHKERRQ(ierr);
323 
324   /* Allocate the work arrays required by SuperLU (notice sizes are for the transpose) */
325   ierr = PetscMalloc(A->n*sizeof(int),&lu->perm_r);CHKERRQ(ierr);
326   ierr = PetscMalloc(A->m*sizeof(int),&lu->perm_c);CHKERRQ(ierr);
327 
328   /* use PETSc mat ordering */
329   ierr = ISGetIndices(c,&ca);CHKERRQ(ierr);
330   ierr = PetscMemcpy(lu->perm_c,ca,A->m*sizeof(int));CHKERRQ(ierr);
331   ierr = ISRestoreIndices(c,&ca);CHKERRQ(ierr);
332   lu->SuperluMatOdering = PETSC_FALSE;
333 
334   lu->pivot_threshold = info->dtcol;
335   PetscLogObjectMemory(B,(A->m+A->n)*sizeof(int)+sizeof(Mat_SuperLU));
336 
337   lu->flg            = DIFFERENT_NONZERO_PATTERN;
338   lu->CleanUpSuperLU = PETSC_TRUE;
339 
340   *F = B;
341   PetscFunctionReturn(0);
342 }
343 
344 /* used by -sles_view */
345 #undef __FUNCT__
346 #define __FUNCT__ "MatFactorInfo_SuperLU"
347 int MatFactorInfo_SuperLU(Mat A,PetscViewer viewer)
348 {
349   Mat_SuperLU *lu= (Mat_SuperLU*)A->spptr;
350   int         ierr;
351 
352   PetscFunctionBegin;
353   ierr = PetscViewerASCIIPrintf(viewer,"SuperLU run parameters:\n");CHKERRQ(ierr);
354   if(lu->SuperluMatOdering) {
355     ierr = PetscViewerASCIIPrintf(viewer,"  SuperLU mat ordering: %d\n",lu->ispec);CHKERRQ(ierr);
356   }
357   PetscFunctionReturn(0);
358 }
359 
360 #undef __FUNCT__
361 #define __FUNCT__ "MatDuplicate_SuperLU"
362 int MatDuplicate_SuperLU(Mat A, MatDuplicateOption op, Mat *M) {
363   int ierr;
364   PetscFunctionBegin;
365   ierr = (*A->ops->duplicate)(A,op,M);CHKERRQ(ierr);
366   ierr = MatConvert_SeqAIJ_SuperLU(*M,MATSUPERLU,M);CHKERRQ(ierr);
367   PetscFunctionReturn(0);
368 }
369 
370 EXTERN_C_BEGIN
371 #undef __FUNCT__
372 #define __FUNCT__ "MatConvert_SuperLU_SeqAIJ"
373 int MatConvert_SuperLU_SeqAIJ(Mat A,MatType type,Mat *newmat) {
374   /* This routine is only called to convert an unfactored PETSc-SuperLU matrix */
375   /* to its base PETSc type, so we will ignore 'MatType type'. */
376   int                  ierr;
377   Mat                  B=*newmat;
378   Mat_SuperLU   *lu=(Mat_SuperLU *)A->spptr;
379 
380   PetscFunctionBegin;
381   if (B != A) {
382     ierr = MatDuplicate(A,MAT_COPY_VALUES,&B);CHKERRQ(ierr);
383   }
384   /* Reset the original function pointers */
385   B->ops->duplicate        = lu->MatDuplicate;
386   B->ops->view             = lu->MatView;
387   B->ops->assemblyend      = lu->MatAssemblyEnd;
388   B->ops->lufactorsymbolic = lu->MatLUFactorSymbolic;
389   B->ops->destroy          = lu->MatDestroy;
390   /* lu is only a function pointer stash unless we've factored the matrix, which we haven't! */
391   ierr = PetscFree(lu);CHKERRQ(ierr);
392   ierr = PetscObjectChangeTypeName((PetscObject)B,MATSEQAIJ);CHKERRQ(ierr);
393   *newmat = B;
394   PetscFunctionReturn(0);
395 }
396 EXTERN_C_END
397 
398 EXTERN_C_BEGIN
399 #undef __FUNCT__
400 #define __FUNCT__ "MatConvert_SeqAIJ_SuperLU"
401 int MatConvert_SeqAIJ_SuperLU(Mat A,MatType type,Mat *newmat) {
402   /* This routine is only called to convert to MATSUPERLU */
403   /* from MATSEQAIJ, so we will ignore 'MatType type'. */
404   int         ierr;
405   Mat         B=*newmat;
406   Mat_SuperLU *lu;
407 
408   PetscFunctionBegin;
409   if (B != A) {
410     ierr = MatDuplicate(A,MAT_COPY_VALUES,&B);CHKERRQ(ierr);
411   }
412 
413   ierr = PetscNew(Mat_SuperLU,&lu);CHKERRQ(ierr);
414   lu->MatDuplicate         = A->ops->duplicate;
415   lu->MatView              = A->ops->view;
416   lu->MatAssemblyEnd       = A->ops->assemblyend;
417   lu->MatLUFactorSymbolic  = A->ops->lufactorsymbolic;
418   lu->MatDestroy           = A->ops->destroy;
419   lu->CleanUpSuperLU       = PETSC_FALSE;
420 
421   B->spptr                 = (void*)lu;
422   B->ops->duplicate        = MatDuplicate_SuperLU;
423   B->ops->view             = MatView_SuperLU;
424   B->ops->assemblyend      = MatAssemblyEnd_SuperLU;
425   B->ops->lufactorsymbolic = MatLUFactorSymbolic_SuperLU;
426   B->ops->destroy          = MatDestroy_SuperLU;
427 
428   ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_seqaij_superlu_C",
429                                            "MatConvert_SeqAIJ_SuperLU",MatConvert_SeqAIJ_SuperLU);CHKERRQ(ierr);
430   ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatConvert_superlu_seqaij_C",
431                                            "MatConvert_SuperLU_SeqAIJ",MatConvert_SuperLU_SeqAIJ);CHKERRQ(ierr);
432   PetscLogInfo(0,"Using SuperLU for SeqAIJ LU factorization and solves.");
433   ierr = PetscObjectChangeTypeName((PetscObject)B,MATSUPERLU);CHKERRQ(ierr);
434   *newmat = B;
435   PetscFunctionReturn(0);
436 }
437 EXTERN_C_END
438 
439 /*MC
440   MATSUPERLU = "superlu" - A matrix type providing direct solvers (LU) for sequential matrices
441   via the external package SuperLU.
442 
443   If SuperLU is installed (see the manual for
444   instructions on how to declare the existence of external packages),
445   a matrix type can be constructed which invokes SuperLU solvers.
446   After calling MatCreate(...,A), simply call MatSetType(A,MATSUPERLU).
447   This matrix type is only supported for double precision real.
448 
449   This matrix inherits from MATSEQAIJ.  As a result, MatSeqAIJSetPreallocation is
450   supported for this matrix type.  One can also call MatConvert for an inplace conversion to or from
451   the MATSEQAIJ type without data copy.
452 
453   Options Database Keys:
454 + -mat_type superlu - sets the matrix type to "superlu" during a call to MatSetFromOptions()
455 - -mat_superlu_ordering <0,1,2,3> - 0: natural ordering,
456                                     1: MMD applied to A'*A,
457                                     2: MMD applied to A'+A,
458                                     3: COLAMD, approximate minimum degree column ordering
459 
460    Level: beginner
461 
462 .seealso: PCLU
463 M*/
464 
465 EXTERN_C_BEGIN
466 #undef __FUNCT__
467 #define __FUNCT__ "MatCreate_SuperLU"
468 int MatCreate_SuperLU(Mat A) {
469   int ierr;
470 
471   PetscFunctionBegin;
472   /* Change type name before calling MatSetType to force proper construction of SeqAIJ and SUPERLU types */
473   ierr = PetscObjectChangeTypeName((PetscObject)A,MATSUPERLU);CHKERRQ(ierr);
474   ierr = MatSetType(A,MATSEQAIJ);CHKERRQ(ierr);
475   ierr = MatConvert_SeqAIJ_SuperLU(A,MATSUPERLU,&A);CHKERRQ(ierr);
476   PetscFunctionReturn(0);
477 }
478 EXTERN_C_END
479