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