xref: /petsc/src/mat/impls/aij/seq/lusol/lusol.c (revision a6dfd86ebdf75fa024070af26d51b62fd16650a3)
1 
2 /*
3         Provides an interface to the LUSOL package of ....
4 
5 */
6 #include <../src/mat/impls/aij/seq/aij.h>
7 
8 #if defined(PETSC_HAVE_FORTRAN_UNDERSCORE)
9 #define LU1FAC   lu1fac_
10 #define LU6SOL   lu6sol_
11 #define M1PAGE   m1page_
12 #define M5SETX   m5setx_
13 #define M6RDEL   m6rdel_
14 #elif !defined(PETSC_HAVE_FORTRAN_CAPS)
15 #define LU1FAC   lu1fac
16 #define LU6SOL   lu6sol
17 #define M1PAGE   m1page
18 #define M5SETX   m5setx
19 #define M6RDEL   m6rdel
20 #endif
21 
22 EXTERN_C_BEGIN
23 /*
24     Dummy symbols that the MINOS files mi25bfac.f and mi15blas.f may require
25 */
26 void PETSC_STDCALL M1PAGE()
27 {
28   ;
29 }
30 void PETSC_STDCALL M5SETX()
31 {
32   ;
33 }
34 
35 void PETSC_STDCALL M6RDEL()
36 {
37   ;
38 }
39 
40 extern void PETSC_STDCALL LU1FAC (int *m, int *n, int *nnz, int *size, int *luparm,
41                         double *parmlu, double *data, int *indc, int *indr,
42                         int *rowperm, int *colperm, int *collen, int *rowlen,
43                         int *colstart, int *rowstart, int *rploc, int *cploc,
44                         int *rpinv, int *cpinv, double *w, int *inform);
45 
46 extern void PETSC_STDCALL LU6SOL (int *mode, int *m, int *n, double *rhs, double *x,
47                         int *size, int *luparm, double *parmlu, double *data,
48                         int *indc, int *indr, int *rowperm, int *colperm,
49                         int *collen, int *rowlen, int *colstart, int *rowstart,
50                         int *inform);
51 EXTERN_C_END
52 
53 extern PetscErrorCode MatDuplicate_LUSOL(Mat,MatDuplicateOption,Mat*);
54 
55 typedef struct  {
56   double *data;
57   int *indc;
58   int *indr;
59 
60   int *ip;
61   int *iq;
62   int *lenc;
63   int *lenr;
64   int *locc;
65   int *locr;
66   int *iploc;
67   int *iqloc;
68   int *ipinv;
69   int *iqinv;
70   double *mnsw;
71   double *mnsv;
72 
73   double elbowroom;
74   double luroom;                /* Extra space allocated when factor fails   */
75   double parmlu[30];            /* Input/output to LUSOL                     */
76 
77   int n;                        /* Number of rows/columns in matrix          */
78   int nz;                       /* Number of nonzeros                        */
79   int nnz;                      /* Number of nonzeros allocated for factors  */
80   int luparm[30];               /* Input/output to LUSOL                     */
81 
82   PetscBool  CleanUpLUSOL;
83 
84 } Mat_LUSOL;
85 
86 /*  LUSOL input/Output Parameters (Description uses C-style indexes
87  *
88  *  Input parameters                                        Typical value
89  *
90  *  luparm(0) = nout     File number for printed messages.         6
91  *  luparm(1) = lprint   Print level.                              0
92  *                    < 0 suppresses output.
93  *                    = 0 gives error messages.
94  *                    = 1 gives debug output from some of the
95  *                        other routines in LUSOL.
96  *                   >= 2 gives the pivot row and column and the
97  *                        no. of rows and columns involved at
98  *                        each elimination step in lu1fac.
99  *  luparm(2) = maxcol   lu1fac: maximum number of columns         5
100  *                        searched allowed in a Markowitz-type
101  *                        search for the next pivot element.
102  *                        For some of the factorization, the
103  *                        number of rows searched is
104  *                        maxrow = maxcol - 1.
105  *
106  *
107  *  Output parameters
108  *
109  *  luparm(9) = inform   Return code from last call to any LU routine.
110  *  luparm(10) = nsing    No. of singularities marked in the
111  *                        output array w(*).
112  *  luparm(11) = jsing    Column index of last singularity.
113  *  luparm(12) = minlen   Minimum recommended value for  lena.
114  *  luparm(13) = maxlen   ?
115  *  luparm(14) = nupdat   No. of updates performed by the lu8 routines.
116  *  luparm(15) = nrank    No. of nonempty rows of U.
117  *  luparm(16) = ndens1   No. of columns remaining when the density of
118  *                        the matrix being factorized reached dens1.
119  *  luparm(17) = ndens2   No. of columns remaining when the density of
120  *                        the matrix being factorized reached dens2.
121  *  luparm(18) = jumin    The column index associated with dumin.
122  *  luparm(19) = numl0    No. of columns in initial  L.
123  *  luparm(20) = lenl0    Size of initial  L  (no. of nonzeros).
124  *  luparm(21) = lenu0    Size of initial  U.
125  *  luparm(22) = lenl     Size of current  L.
126  *  luparm(23) = lenu     Size of current  U.
127  *  luparm(24) = lrow     Length of row file.
128  *  luparm(25) = ncp      No. of compressions of LU data structures.
129  *  luparm(26) = mersum   lu1fac: sum of Markowitz merit counts.
130  *  luparm(27) = nutri    lu1fac: triangular rows in U.
131  *  luparm(28) = nltri    lu1fac: triangular rows in L.
132  *  luparm(29) =
133  *
134  *
135  *  Input parameters                                        Typical value
136  *
137  *  parmlu(0) = elmax1   Max multiplier allowed in  L           10.0
138  *                        during factor.
139  *  parmlu(1) = elmax2   Max multiplier allowed in  L           10.0
140  *                        during updates.
141  *  parmlu(2) = small    Absolute tolerance for             eps**0.8
142  *                        treating reals as zero.     IBM double: 3.0d-13
143  *  parmlu(3) = utol1    Absolute tol for flagging          eps**0.66667
144  *                        small diagonals of U.       IBM double: 3.7d-11
145  *  parmlu(4) = utol2    Relative tol for flagging          eps**0.66667
146  *                        small diagonals of U.       IBM double: 3.7d-11
147  *  parmlu(5) = uspace   Factor limiting waste space in  U.      3.0
148  *                        In lu1fac, the row or column lists
149  *                        are compressed if their length
150  *                        exceeds uspace times the length of
151  *                        either file after the last compression.
152  *  parmlu(6) = dens1    The density at which the Markowitz      0.3
153  *                        strategy should search maxcol columns
154  *                        and no rows.
155  *  parmlu(7) = dens2    the density at which the Markowitz      0.6
156  *                        strategy should search only 1 column
157  *                        or (preferably) use a dense LU for
158  *                        all the remaining rows and columns.
159  *
160  *
161  *  Output parameters
162  *
163  *  parmlu(9) = amax     Maximum element in  A.
164  *  parmlu(10) = elmax    Maximum multiplier in current  L.
165  *  parmlu(11) = umax     Maximum element in current  U.
166  *  parmlu(12) = dumax    Maximum diagonal in  U.
167  *  parmlu(13) = dumin    Minimum diagonal in  U.
168  *  parmlu(14) =
169  *  parmlu(15) =
170  *  parmlu(16) =
171  *  parmlu(17) =
172  *  parmlu(18) =
173  *  parmlu(19) = resid    lu6sol: residual after solve with U or U'.
174  *  ...
175  *  parmlu(29) =
176  */
177 
178 #define Factorization_Tolerance       1e-1
179 #define Factorization_Pivot_Tolerance pow(2.2204460492503131E-16, 2.0 / 3.0)
180 #define Factorization_Small_Tolerance 1e-15 /* pow(DBL_EPSILON, 0.8) */
181 
182 #undef __FUNCT__
183 #define __FUNCT__ "MatDestroy_LUSOL"
184 PetscErrorCode MatDestroy_LUSOL(Mat A)
185 {
186   PetscErrorCode ierr;
187   Mat_LUSOL      *lusol=(Mat_LUSOL *)A->spptr;
188 
189   PetscFunctionBegin;
190   if (lusol && lusol->CleanUpLUSOL) {
191     ierr = PetscFree(lusol->ip);CHKERRQ(ierr);
192     ierr = PetscFree(lusol->iq);CHKERRQ(ierr);
193     ierr = PetscFree(lusol->lenc);CHKERRQ(ierr);
194     ierr = PetscFree(lusol->lenr);CHKERRQ(ierr);
195     ierr = PetscFree(lusol->locc);CHKERRQ(ierr);
196     ierr = PetscFree(lusol->locr);CHKERRQ(ierr);
197     ierr = PetscFree(lusol->iploc);CHKERRQ(ierr);
198     ierr = PetscFree(lusol->iqloc);CHKERRQ(ierr);
199     ierr = PetscFree(lusol->ipinv);CHKERRQ(ierr);
200     ierr = PetscFree(lusol->iqinv);CHKERRQ(ierr);
201     ierr = PetscFree(lusol->mnsw);CHKERRQ(ierr);
202     ierr = PetscFree(lusol->mnsv);CHKERRQ(ierr);
203     ierr = PetscFree3(lusol->data,lusol->indc,lusol->indr);CHKERRQ(ierr);
204   }
205   ierr = PetscFree(A->spptr);CHKERRQ(ierr);
206   ierr = MatDestroy_SeqAIJ(A);CHKERRQ(ierr);
207   PetscFunctionReturn(0);
208 }
209 
210 #undef __FUNCT__
211 #define __FUNCT__  "MatSolve_LUSOL"
212 PetscErrorCode MatSolve_LUSOL(Mat A,Vec b,Vec x)
213 {
214   Mat_LUSOL      *lusol=(Mat_LUSOL*)A->spptr;
215   double         *bb,*xx;
216   int            mode=5;
217   PetscErrorCode ierr;
218   int            i,m,n,nnz,status;
219 
220   PetscFunctionBegin;
221   ierr = VecGetArray(x, &xx);CHKERRQ(ierr);
222   ierr = VecGetArray(b, &bb);CHKERRQ(ierr);
223 
224   m = n = lusol->n;
225   nnz = lusol->nnz;
226 
227   for (i = 0; i < m; i++)
228     {
229       lusol->mnsv[i] = bb[i];
230     }
231 
232   LU6SOL(&mode, &m, &n, lusol->mnsv, xx, &nnz,
233          lusol->luparm, lusol->parmlu, lusol->data,
234          lusol->indc, lusol->indr, lusol->ip, lusol->iq,
235          lusol->lenc, lusol->lenr, lusol->locc, lusol->locr, &status);
236 
237   if (status) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"solve failed, error code %d",status);
238 
239   ierr = VecRestoreArray(x, &xx);CHKERRQ(ierr);
240   ierr = VecRestoreArray(b, &bb);CHKERRQ(ierr);
241   PetscFunctionReturn(0);
242 }
243 
244 #undef __FUNCT__
245 #define __FUNCT__ "MatLUFactorNumeric_LUSOL"
246 PetscErrorCode MatLUFactorNumeric_LUSOL(Mat F,Mat A,const MatFactorInfo *info)
247 {
248   Mat_SeqAIJ     *a;
249   Mat_LUSOL      *lusol = (Mat_LUSOL*)F->spptr;
250   PetscErrorCode ierr;
251   int            m, n, nz, nnz, status;
252   int            i, rs, re;
253   int            factorizations;
254 
255   PetscFunctionBegin;
256   ierr = MatGetSize(A,&m,&n);CHKERRQ(ierr);CHKERRQ(ierr);
257   a = (Mat_SeqAIJ *)A->data;
258 
259   if (m != lusol->n) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_SIZ,"factorization struct inconsistent");
260 
261   factorizations = 0;
262   do
263     {
264       /*******************************************************************/
265       /* Check the workspace allocation.                                 */
266       /*******************************************************************/
267 
268       nz = a->nz;
269       nnz = PetscMax(lusol->nnz, (int)(lusol->elbowroom*nz));
270       nnz = PetscMax(nnz, 5*n);
271 
272       if (nnz < lusol->luparm[12]) {
273         nnz = (int)(lusol->luroom * lusol->luparm[12]);
274       } else if ((factorizations > 0) && (lusol->luroom < 6)) {
275         lusol->luroom += 0.1;
276       }
277 
278       nnz = PetscMax(nnz, (int)(lusol->luroom*(lusol->luparm[22] + lusol->luparm[23])));
279 
280       if (nnz > lusol->nnz) {
281         ierr = PetscFree3(lusol->data,lusol->indc,lusol->indr);CHKERRQ(ierr);
282         ierr = PetscMalloc3(nnz,double,&lusol->data,nnz,PetscInt,&lusol->indc,nnz,PetscInt,&lusol->indr);CHKERRQ(ierr);
283         lusol->nnz  = nnz;
284       }
285 
286       /*******************************************************************/
287       /* Fill in the data for the problem.      (1-based Fortran style)  */
288       /*******************************************************************/
289 
290       nz = 0;
291       for (i = 0; i < n; i++)
292         {
293           rs = a->i[i];
294           re = a->i[i+1];
295 
296           while (rs < re)
297             {
298               if (a->a[rs] != 0.0)
299                 {
300                   lusol->indc[nz] = i + 1;
301                   lusol->indr[nz] = a->j[rs] + 1;
302                   lusol->data[nz] = a->a[rs];
303                   nz++;
304                 }
305               rs++;
306             }
307         }
308 
309       /*******************************************************************/
310       /* Do the factorization.                                           */
311       /*******************************************************************/
312 
313       LU1FAC(&m, &n, &nz, &nnz,
314              lusol->luparm, lusol->parmlu, lusol->data,
315              lusol->indc, lusol->indr, lusol->ip, lusol->iq,
316              lusol->lenc, lusol->lenr, lusol->locc, lusol->locr,
317              lusol->iploc, lusol->iqloc, lusol->ipinv,
318              lusol->iqinv, lusol->mnsw, &status);
319 
320       switch(status)
321         {
322         case 0:         /* factored */
323           break;
324 
325         case 7:         /* insufficient memory */
326           break;
327 
328         case 1:
329         case -1:        /* singular */
330           SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Singular matrix");
331 
332         case 3:
333         case 4:         /* error conditions */
334           SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"matrix error");
335 
336         default:        /* unknown condition */
337           SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"matrix unknown return code");
338         }
339 
340       factorizations++;
341     } while (status == 7);
342   F->ops->solve   = MatSolve_LUSOL;
343   F->assembled    = PETSC_TRUE;
344   F->preallocated = PETSC_TRUE;
345   PetscFunctionReturn(0);
346 }
347 
348 #undef __FUNCT__
349 #define __FUNCT__ "MatLUFactorSymbolic_LUSOL"
350 PetscErrorCode MatLUFactorSymbolic_LUSOL(Mat F,Mat A, IS r, IS c,const MatFactorInfo *info)
351 {
352   /************************************************************************/
353   /* Input                                                                */
354   /*     A  - matrix to factor                                            */
355   /*     r  - row permutation (ignored)                                   */
356   /*     c  - column permutation (ignored)                                */
357   /*                                                                      */
358   /* Output                                                               */
359   /*     F  - matrix storing the factorization;                           */
360   /************************************************************************/
361   Mat_LUSOL      *lusol;
362   PetscErrorCode ierr;
363   int            i, m, n, nz, nnz;
364 
365   PetscFunctionBegin;
366 
367   /************************************************************************/
368   /* Check the arguments.                                                 */
369   /************************************************************************/
370 
371   ierr = MatGetSize(A, &m, &n);CHKERRQ(ierr);
372   nz = ((Mat_SeqAIJ *)A->data)->nz;
373 
374   /************************************************************************/
375   /* Create the factorization.                                            */
376   /************************************************************************/
377 
378   F->ops->lufactornumeric = MatLUFactorNumeric_LUSOL;
379   lusol                   = (Mat_LUSOL*)(F->spptr);
380 
381   /************************************************************************/
382   /* Initialize parameters                                                */
383   /************************************************************************/
384 
385   for (i = 0; i < 30; i++)
386     {
387       lusol->luparm[i] = 0;
388       lusol->parmlu[i] = 0;
389     }
390 
391   lusol->luparm[1] = -1;
392   lusol->luparm[2] = 5;
393   lusol->luparm[7] = 1;
394 
395   lusol->parmlu[0] = 1 / Factorization_Tolerance;
396   lusol->parmlu[1] = 1 / Factorization_Tolerance;
397   lusol->parmlu[2] = Factorization_Small_Tolerance;
398   lusol->parmlu[3] = Factorization_Pivot_Tolerance;
399   lusol->parmlu[4] = Factorization_Pivot_Tolerance;
400   lusol->parmlu[5] = 3.0;
401   lusol->parmlu[6] = 0.3;
402   lusol->parmlu[7] = 0.6;
403 
404   /************************************************************************/
405   /* Allocate the workspace needed by LUSOL.                              */
406   /************************************************************************/
407 
408   lusol->elbowroom = PetscMax(lusol->elbowroom, info->fill);
409   nnz = PetscMax((int)(lusol->elbowroom*nz), 5*n);
410 
411   lusol->n = n;
412   lusol->nz = nz;
413   lusol->nnz = nnz;
414   lusol->luroom = 1.75;
415 
416   ierr = PetscMalloc(sizeof(int)*n,&lusol->ip);
417   ierr = PetscMalloc(sizeof(int)*n,&lusol->iq);
418   ierr = PetscMalloc(sizeof(int)*n,&lusol->lenc);
419   ierr = PetscMalloc(sizeof(int)*n,&lusol->lenr);
420   ierr = PetscMalloc(sizeof(int)*n,&lusol->locc);
421   ierr = PetscMalloc(sizeof(int)*n,&lusol->locr);
422   ierr = PetscMalloc(sizeof(int)*n,&lusol->iploc);
423   ierr = PetscMalloc(sizeof(int)*n,&lusol->iqloc);
424   ierr = PetscMalloc(sizeof(int)*n,&lusol->ipinv);
425   ierr = PetscMalloc(sizeof(int)*n,&lusol->iqinv);
426   ierr = PetscMalloc(sizeof(double)*n,&lusol->mnsw);
427   ierr = PetscMalloc(sizeof(double)*n,&lusol->mnsv);
428 
429   ierr = PetscMalloc3(nnz,double,&lusol->data,nnz,PetscInt,&lusol->indc,nnz,PetscInt,&lusol->indr);CHKERRQ(ierr);
430   lusol->CleanUpLUSOL = PETSC_TRUE;
431   F->ops->lufactornumeric  = MatLUFactorNumeric_LUSOL;
432   PetscFunctionReturn(0);
433 }
434 
435 EXTERN_C_BEGIN
436 #undef __FUNCT__
437 #define __FUNCT__ "MatFactorGetSolverPackage_seqaij_lusol"
438 PetscErrorCode MatFactorGetSolverPackage_seqaij_lusol(Mat A,const MatSolverPackage *type)
439 {
440   PetscFunctionBegin;
441   *type = MATSOLVERLUSOL;
442   PetscFunctionReturn(0);
443 }
444 EXTERN_C_END
445 
446 #undef __FUNCT__
447 #define __FUNCT__ "MatGetFactor_seqaij_lusol"
448 PetscErrorCode MatGetFactor_seqaij_lusol(Mat A,MatFactorType ftype,Mat *F)
449 {
450   Mat            B;
451   Mat_LUSOL      *lusol;
452   PetscErrorCode ierr;
453   int            m, n;
454 
455   PetscFunctionBegin;
456   ierr = MatGetSize(A, &m, &n);CHKERRQ(ierr);
457   ierr = MatCreate(((PetscObject)A)->comm,&B);CHKERRQ(ierr);
458   ierr = MatSetSizes(B,PETSC_DECIDE,PETSC_DECIDE,m,n);CHKERRQ(ierr);
459   ierr = MatSetType(B,((PetscObject)A)->type_name);CHKERRQ(ierr);
460   ierr = MatSeqAIJSetPreallocation(B,0,PETSC_NULL);CHKERRQ(ierr);
461 
462   ierr = PetscNewLog(B,Mat_LUSOL,&lusol);CHKERRQ(ierr);
463   B->spptr                 = lusol;
464 
465   B->ops->lufactorsymbolic = MatLUFactorSymbolic_LUSOL;
466   B->ops->destroy          = MatDestroy_LUSOL;
467   ierr = PetscObjectComposeFunctionDynamic((PetscObject)B,"MatFactorGetSolverPackage_C","MatFactorGetSolverPackage_seqaij_lusol",MatFactorGetSolverPackage_seqaij_lusol);CHKERRQ(ierr);
468   B->factortype            = MAT_FACTOR_LU;
469   PetscFunctionReturn(0);
470 }
471 
472 /*MC
473   MATSOLVERLUSOL - "lusol" - Provides direct solvers (LU) for sequential matrices
474                          via the external package LUSOL.
475 
476   If LUSOL is installed (see the manual for
477   instructions on how to declare the existence of external packages),
478 
479   Works with MATSEQAIJ matrices
480 
481    Level: beginner
482 
483 .seealso: PCLU, PCFactorSetMatSolverPackage(), MatSolverPackage
484 
485 M*/
486