1 /* -----------------------------------------------------------------------------
2  * Programmer(s): Cody J. Balos @ LLNL
3  * -----------------------------------------------------------------------------
4  * SUNDIALS Copyright Start
5  * Copyright (c) 2002-2021, Lawrence Livermore National Security
6  * and Southern Methodist University.
7  * All rights reserved.
8  *
9  * See the top-level LICENSE and NOTICE files for details.
10  *
11  * SPDX-License-Identifier: BSD-3-Clause
12  * SUNDIALS Copyright End
13  * -----------------------------------------------------------------------------
14  * This is the implementation file for the SuperLU-DIST implementation of the
15  * SUNLINSOL package.
16  * ---------------------------------------------------------------------------*/
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 
21 #include <sunmatrix/sunmatrix_slunrloc.h>
22 #include <sunlinsol/sunlinsol_superludist.h>
23 #include <sundials/sundials_math.h>
24 #include <superlu_ddefs.h>
25 
26 #define ZERO      RCONST(0.0)
27 #define ONE       RCONST(1.0)
28 #define TWO       RCONST(2.0)
29 
30 /*
31  * -----------------------------------------------------------------
32  * SuperLUDIST solver structure accessibility macros:
33  * -----------------------------------------------------------------
34  */
35 
36 #define SLUDIST_CONTENT(S)    ( (SUNLinearSolverContent_SuperLUDIST)(S->content) )
37 #define SLU_FIRSTFACTORIZE(S) ( SLUDIST_CONTENT(S)->first_factorize )
38 #define SLU_BERR(S)           ( SLUDIST_CONTENT(S)->berr )
39 #define SLU_GRID(S)           ( SLUDIST_CONTENT(S)->grid )
40 #define SLU_LASTFLAG(S)       ( SLUDIST_CONTENT(S)->last_flag )
41 #define SLU_LU(S)             ( SLUDIST_CONTENT(S)->lu )
42 #define SLU_OPTIONS(S)        ( SLUDIST_CONTENT(S)->options )
43 #define SLU_SCALEPERM(S)      ( SLUDIST_CONTENT(S)->scaleperm )
44 #define SLU_SOLVESTRUCT(S)    ( SLUDIST_CONTENT(S)->solve )
45 #define SLU_STAT(S)           ( SLUDIST_CONTENT(S)->stat )
46 #define SLU_SIZE(S)           ( SLUDIST_CONTENT(S)->N )
47 
48 /*
49  * ----------------------------------------------------------------------------
50  *  Implementations of exported functions.
51  * ----------------------------------------------------------------------------
52  */
53 
SUNLinSol_SuperLUDIST(N_Vector y,SUNMatrix A,gridinfo_t * grid,xLUstruct_t * lu,xScalePermstruct_t * scaleperm,xSOLVEstruct_t * solve,SuperLUStat_t * stat,superlu_dist_options_t * options)54 SUNLinearSolver SUNLinSol_SuperLUDIST(N_Vector y, SUNMatrix A, gridinfo_t *grid,
55                                       xLUstruct_t *lu, xScalePermstruct_t *scaleperm,
56                                       xSOLVEstruct_t *solve, SuperLUStat_t *stat,
57                                       superlu_dist_options_t *options)
58 {
59   SUNLinearSolver S;
60   SUNLinearSolverContent_SuperLUDIST content;
61   SuperMatrix *Asuper;
62   NRformat_loc *Astore;
63 
64   /* Check that required arguments are not NULL */
65   if (y == NULL || A == NULL || grid == NULL || lu == NULL ||
66       scaleperm == NULL || solve == NULL || stat == NULL || options == NULL)
67     return(NULL);
68 
69   /* Check compatibility with supplied SUNMatrix and N_Vector */
70   if (SUNMatGetID(A) != SUNMATRIX_SLUNRLOC) return(NULL);
71 
72   Asuper = SUNMatrix_SLUNRloc_SuperMatrix(A);
73   Astore = (NRformat_loc *) Asuper->Store;
74 
75   /* Check that the matrix is square */
76   if (Asuper->nrow != Asuper->ncol) return(NULL);
77 
78   /* Create an empty linear solver */
79   S = NULL;
80   S = SUNLinSolNewEmpty();
81   if (S == NULL) return(NULL);
82 
83   /* Attach operations */
84   S->ops->gettype    = SUNLinSolGetType_SuperLUDIST;
85   S->ops->getid      = SUNLinSolGetID_SuperLUDIST;
86   S->ops->initialize = SUNLinSolInitialize_SuperLUDIST;
87   S->ops->setup      = SUNLinSolSetup_SuperLUDIST;
88   S->ops->solve      = SUNLinSolSolve_SuperLUDIST;
89   S->ops->lastflag   = SUNLinSolLastFlag_SuperLUDIST;
90   S->ops->space      = SUNLinSolSpace_SuperLUDIST;
91   S->ops->free       = SUNLinSolFree_SuperLUDIST;
92 
93   /* Create content */
94   content = NULL;
95   content = (SUNLinearSolverContent_SuperLUDIST) malloc(sizeof *content);
96   if (content == NULL) { SUNLinSolFree(S); return(NULL); }
97 
98   /* Attach content */
99   S->content = content;
100 
101   /* Fill content */
102   content->grid      = grid;
103   content->lu        = lu;
104   content->N         = Astore->m_loc;
105   content->options   = options;
106   content->scaleperm = scaleperm;
107   content->solve     = solve;
108   content->stat      = stat;
109   content->berr      = ZERO;
110   content->last_flag = 0;
111 
112   return(S);
113 }
114 
115 /*
116  * -----------------------------------------------------------------
117  * Implementation of accessor functions.
118  * -----------------------------------------------------------------
119  */
120 
SUNLinSol_SuperLUDIST_GetBerr(SUNLinearSolver LS)121 realtype SUNLinSol_SuperLUDIST_GetBerr(SUNLinearSolver LS)
122 {
123   return(SLU_BERR(LS));
124 }
125 
SUNLinSol_SuperLUDIST_GetGridinfo(SUNLinearSolver LS)126 gridinfo_t* SUNLinSol_SuperLUDIST_GetGridinfo(SUNLinearSolver LS)
127 {
128   return(SLU_GRID(LS));
129 }
130 
SUNLinSol_SuperLUDIST_GetLUstruct(SUNLinearSolver LS)131 xLUstruct_t* SUNLinSol_SuperLUDIST_GetLUstruct(SUNLinearSolver LS)
132 {
133   return(SLU_LU(LS));
134 }
135 
SUNLinSol_SuperLUDIST_GetSuperLUOptions(SUNLinearSolver LS)136 superlu_dist_options_t* SUNLinSol_SuperLUDIST_GetSuperLUOptions(SUNLinearSolver LS)
137 {
138   return(SLU_OPTIONS(LS));
139 }
140 
SUNLinSol_SuperLUDIST_GetScalePermstruct(SUNLinearSolver LS)141 xScalePermstruct_t* SUNLinSol_SuperLUDIST_GetScalePermstruct(SUNLinearSolver LS)
142 {
143   return(SLU_SCALEPERM(LS));
144 }
145 
SUNLinSol_SuperLUDIST_GetSOLVEstruct(SUNLinearSolver LS)146 xSOLVEstruct_t* SUNLinSol_SuperLUDIST_GetSOLVEstruct(SUNLinearSolver LS)
147 {
148   return(SLU_SOLVESTRUCT(LS));
149 }
150 
SUNLinSol_SuperLUDIST_GetSuperLUStat(SUNLinearSolver LS)151 SuperLUStat_t* SUNLinSol_SuperLUDIST_GetSuperLUStat(SUNLinearSolver LS)
152 {
153   return(SLU_STAT(LS));
154 }
155 
156 /*
157  * -----------------------------------------------------------------
158  * Implementation of linear solver operations
159  * -----------------------------------------------------------------
160  */
161 
SUNLinSolGetType_SuperLUDIST(SUNLinearSolver S)162 SUNLinearSolver_Type SUNLinSolGetType_SuperLUDIST(SUNLinearSolver S)
163 {
164   return(SUNLINEARSOLVER_DIRECT);
165 }
166 
SUNLinSolGetID_SuperLUDIST(SUNLinearSolver S)167 SUNLinearSolver_ID SUNLinSolGetID_SuperLUDIST(SUNLinearSolver S)
168 {
169   return(SUNLINEARSOLVER_SUPERLUDIST);
170 }
171 
SUNLinSolInitialize_SuperLUDIST(SUNLinearSolver S)172 int SUNLinSolInitialize_SuperLUDIST(SUNLinearSolver S)
173 {
174   SLU_FIRSTFACTORIZE(S) = SUNTRUE;
175 
176   SLU_LASTFLAG(S) = SUNLS_SUCCESS;
177   return(SLU_LASTFLAG(S));
178 }
179 
SUNLinSolSetup_SuperLUDIST(SUNLinearSolver S,SUNMatrix A)180 int SUNLinSolSetup_SuperLUDIST(SUNLinearSolver S, SUNMatrix A)
181 {
182   if (SLU_FIRSTFACTORIZE(S)) {
183     /* Force factorization on next solve. */
184     SLU_OPTIONS(S)->Fact = DOFACT;
185 
186     /* if the solve struct was already initialized, we need to
187        finalize the last solve to avoid leaking memory */
188     if (SLU_OPTIONS(S)->SolveInitialized == YES) {
189       xDestroy_LU(SLU_SIZE(S), SLU_GRID(S), SLU_LU(S));
190       dSolveFinalize(SLU_OPTIONS(S), SLU_SOLVESTRUCT(S));
191     }
192   } else {
193     /* Force factorization on next solve, but reuse column permutation */
194     SLU_OPTIONS(S)->Fact = SamePattern;
195   }
196 
197   SLU_LASTFLAG(S) = SUNLS_SUCCESS;
198   return(SLU_LASTFLAG(S));
199 }
200 
SUNLinSolSolve_SuperLUDIST(SUNLinearSolver S,SUNMatrix A,N_Vector x,N_Vector b,realtype tol)201 int SUNLinSolSolve_SuperLUDIST(SUNLinearSolver S, SUNMatrix A,
202                                N_Vector x, N_Vector b, realtype tol)
203 {
204   int retval;
205   realtype *xdata;
206   SuperMatrix *Asuper;
207   NRformat_loc *Astore;
208 
209   if ((S == NULL) || (A == NULL) || (x == NULL) || (b == NULL))
210     return(SUNLS_MEM_NULL);
211 
212   Asuper = SUNMatrix_SLUNRloc_SuperMatrix(A);
213   Astore = (NRformat_loc *) Asuper->Store;
214 
215   /* Copy b into x, and use xdata with SuperLU-DIST because
216      SuperLU reuses b to store the solution vector. */
217   N_VScale(ONE, b, x);
218   xdata = N_VGetArrayPointer(x);
219   if (xdata == NULL) {
220     SLU_LASTFLAG(S) = SUNLS_MEM_FAIL;
221     return(SLU_LASTFLAG(S));
222   }
223 
224   /* Call SuperLU-DIST to solve the linear system */
225   pdgssvx(SLU_OPTIONS(S), Asuper, SLU_SCALEPERM(S), xdata, Astore->m_loc, 1,
226           SLU_GRID(S), SLU_LU(S), SLU_SOLVESTRUCT(S), &SLU_BERR(S), SLU_STAT(S),
227           &retval);
228 
229   if (retval != 0) {
230     /* retval should never be < 0, and if it is > than ncol it means a memory
231        allocation error occured. If 0 < retval <= ncol, then U is singular and
232        the solve couldn't be completed. */
233     if (retval < 0 || retval > Asuper->ncol)
234       SLU_LASTFLAG(S) = SUNLS_PACKAGE_FAIL_UNREC;
235     else
236       SLU_LASTFLAG(S) = SUNLS_PACKAGE_FAIL_REC;
237     return(SLU_LASTFLAG(S));
238   }
239 
240   /* Tell SuperLU-DIST that A is already factored so do not factorize */
241   SLU_OPTIONS(S)->Fact = FACTORED;
242 
243   SLU_LASTFLAG(S) = SUNLS_SUCCESS;
244   return(SLU_LASTFLAG(S));
245 }
246 
SUNLinSolLastFlag_SuperLUDIST(SUNLinearSolver S)247 sunindextype SUNLinSolLastFlag_SuperLUDIST(SUNLinearSolver S)
248 {
249   if (S == NULL) return(-1);
250   return(SLU_LASTFLAG(S));
251 }
252 
SUNLinSolFree_SuperLUDIST(SUNLinearSolver S)253 int SUNLinSolFree_SuperLUDIST(SUNLinearSolver S)
254 {
255   /* return with success if already freed */
256   if (S == NULL) return(SUNLS_SUCCESS);
257 
258   /* Call SuperLU DIST destroy/finalize routines,
259      but don't free the sturctures themselves - that is the user's job */
260   xDestroy_LU(SLU_SIZE(S), SLU_GRID(S), SLU_LU(S));
261   dSolveFinalize(SLU_OPTIONS(S), SLU_SOLVESTRUCT(S));
262 
263   /* free content structure */
264   if (S->content) {
265     free(S->content);
266     S->content = NULL;
267   }
268 
269   /* free ops structure */
270   if (S->ops) {
271     free(S->ops);
272     S->ops = NULL;
273   }
274 
275   /* free the actual SUNLinSol */
276   free(S);
277   S = NULL;
278 
279   return(SUNLS_SUCCESS);
280 }
281 
SUNLinSolSpace_SuperLUDIST(SUNLinearSolver S,long int * leniwLS,long int * lenrwLS)282 int SUNLinSolSpace_SuperLUDIST(SUNLinearSolver S, long int *leniwLS,
283                                long int *lenrwLS)
284 {
285   /* since the SuperLU_DIST structures are opaque objects, we
286      omit those from these results */
287 
288   *leniwLS = 2; /* last_flag, N */
289   *lenrwLS = 1; /* berr */
290 
291   return(SUNLS_SUCCESS);
292 }
293