1 /*
2 * -----------------------------------------------------------------
3 * Programmer(s): Daniel R. Reynolds @ SMU
4 * David J. Gardner @ LLNL
5 * -----------------------------------------------------------------
6 * SUNDIALS Copyright Start
7 * Copyright (c) 2002-2021, Lawrence Livermore National Security
8 * and Southern Methodist University.
9 * All rights reserved.
10 *
11 * See the top-level LICENSE and NOTICE files for details.
12 *
13 * SPDX-License-Identifier: BSD-3-Clause
14 * SUNDIALS Copyright End
15 * -----------------------------------------------------------------
16 * These test functions are designed to check a SUNLinSol module
17 * implementation.
18 * -----------------------------------------------------------------
19 */
20
21 #include <sundials/sundials_linearsolver.h>
22 #include <sundials/sundials_types.h>
23 #include <sundials/sundials_math.h>
24
25 #include <math.h> /* include isnan */
26 #include <stdio.h>
27 #include <stdlib.h>
28
29 #include "test_sunlinsol.h"
30
31 #if defined( SUNDIALS_HAVE_POSIX_TIMERS) && defined(_POSIX_TIMERS)
32 #include <time.h>
33 #include <unistd.h>
34 #endif
35
36 /* private functions */
37 static double get_time();
38
39 int print_time = 0;
40
41 #define PRINT_TIME(format, time) if(print_time) printf(format, time)
42
43 /* ----------------------------------------------------------------------
44 * SUNLinSolGetType Test
45 * --------------------------------------------------------------------*/
Test_SUNLinSolGetType(SUNLinearSolver S,SUNLinearSolver_Type suntype,int myid)46 int Test_SUNLinSolGetType(SUNLinearSolver S, SUNLinearSolver_Type suntype, int myid)
47 {
48 double start_time, stop_time;
49 SUNLinearSolver_Type mysuntype;
50
51 start_time = get_time();
52 mysuntype = SUNLinSolGetType(S);
53 sync_device();
54 stop_time = get_time();
55
56 if (suntype != mysuntype) {
57 printf(">>> FAILED test -- SUNLinSolGetType, Proc %d \n", myid);
58 PRINT_TIME(" SUNLinSolGetType Time: %22.15e \n \n", stop_time - start_time);
59 return(1);
60 } else if (myid == 0) {
61 printf(" PASSED test -- SUNLinSolGetType \n");
62 PRINT_TIME(" SUNLinSolGetType Time: %22.15e \n \n", stop_time - start_time);
63 }
64
65 return(0);
66 }
67
68 /* ----------------------------------------------------------------------
69 * SUNLinSolGetID Test
70 * --------------------------------------------------------------------*/
Test_SUNLinSolGetID(SUNLinearSolver S,SUNLinearSolver_ID sunid,int myid)71 int Test_SUNLinSolGetID(SUNLinearSolver S, SUNLinearSolver_ID sunid, int myid)
72 {
73 double start_time, stop_time;
74 SUNLinearSolver_ID mysunid;
75
76 start_time = get_time();
77 mysunid = SUNLinSolGetID(S);
78 sync_device();
79 stop_time = get_time();
80
81 if (sunid != mysunid) {
82 printf(">>> FAILED test -- SUNLinSolGetID, Proc %d \n", myid);
83 PRINT_TIME(" SUNLinSolGetID Time: %22.15e \n \n", stop_time - start_time);
84 return(1);
85 } else if (myid == 0) {
86 printf(" PASSED test -- SUNLinSolGetID \n");
87 PRINT_TIME(" SUNLinSolGetID Time: %22.15e \n \n", stop_time - start_time);
88 }
89
90 return (0);
91 }
92
93 /* ----------------------------------------------------------------------
94 * Test_SUNLinSolLastFlag Test
95 * --------------------------------------------------------------------*/
Test_SUNLinSolLastFlag(SUNLinearSolver S,int myid)96 int Test_SUNLinSolLastFlag(SUNLinearSolver S, int myid)
97 {
98 double start_time, stop_time;
99 sunindextype lastflag;
100
101 /* the only way for this test to fail is if S is NULL */
102 if (S == NULL) {
103 printf(">>> FAILED test -- SUNLinSolLastFlag, Proc %d \n", myid);
104 return(1);
105 }
106
107 start_time = get_time();
108 lastflag = SUNLinSolLastFlag(S);
109 sync_device();
110 stop_time = get_time();
111
112 if (myid == 0) {
113 printf(" PASSED test -- SUNLinSolLastFlag (%ld) \n", (long int) lastflag);
114 PRINT_TIME(" SUNLinSolLastFlag Time: %22.15e \n \n", stop_time - start_time);
115 }
116
117 return(0);
118 }
119
120
121 /* ----------------------------------------------------------------------
122 * Test_SUNLinSolSpace Test
123 * --------------------------------------------------------------------*/
Test_SUNLinSolSpace(SUNLinearSolver S,int myid)124 int Test_SUNLinSolSpace(SUNLinearSolver S, int myid)
125 {
126 int failure;
127 double start_time, stop_time;
128 long int lenrw, leniw;
129
130 /* call SUNLinSolSpace (failure based on output flag) */
131 start_time = get_time();
132 failure = SUNLinSolSpace(S, &lenrw, &leniw);
133 sync_device();
134 stop_time = get_time();
135
136 if (failure) {
137 printf(">>> FAILED test -- SUNLinSolSpace, Proc %d \n", myid);
138 PRINT_TIME(" SUNLinSolSpace Time: %22.15e \n \n", stop_time - start_time);
139 return(1);
140 } else if (myid == 0) {
141 printf(" PASSED test -- SUNLinSolSpace, lenrw = %li, leniw = %li\n", lenrw, leniw);
142 PRINT_TIME(" SUNLinSolSpace Time: %22.15e \n \n", stop_time - start_time);
143 }
144
145 return(0);
146 }
147
148
149 /* ----------------------------------------------------------------------
150 * SUNLinSolNumIters Test
151 * --------------------------------------------------------------------*/
Test_SUNLinSolNumIters(SUNLinearSolver S,int myid)152 int Test_SUNLinSolNumIters(SUNLinearSolver S, int myid)
153 {
154 int numiters;
155 double start_time, stop_time;
156
157 /* the only way to fail this test is if the function is NULL,
158 which will cause a seg-fault */
159 start_time = get_time();
160 numiters = SUNLinSolNumIters(S);
161 sync_device();
162 stop_time = get_time();
163
164 if (myid == 0) {
165 printf(" PASSED test -- SUNLinSolNumIters (%d) \n", numiters);
166 PRINT_TIME(" SUNLinSolNumIters Time: %22.15e \n \n", stop_time - start_time);
167 }
168
169 return(0);
170 }
171
172
173 /* ----------------------------------------------------------------------
174 * SUNLinSolResNorm Test
175 * --------------------------------------------------------------------*/
Test_SUNLinSolResNorm(SUNLinearSolver S,int myid)176 int Test_SUNLinSolResNorm(SUNLinearSolver S, int myid)
177 {
178 double start_time, stop_time, resnorm;
179
180 /* this test can fail if the function is NULL, which will cause a seg-fault */
181 start_time = get_time();
182 resnorm = (double) SUNLinSolResNorm(S);
183 sync_device();
184 stop_time = get_time();
185
186 /* this test can also fail if the return value is negative */
187 if (resnorm < ZERO){
188 printf(">>> FAILED test -- SUNLinSolResNorm returned %g on Proc %d \n",
189 resnorm, myid);
190 return(1);
191 }
192 else if (myid == 0) {
193 printf(" PASSED test -- SUNLinSolResNorm\n");
194 PRINT_TIME(" SUNLinSolResNorm Time: %22.15e \n \n", stop_time - start_time);
195 }
196
197 return(0);
198 }
199
200
201 /* ----------------------------------------------------------------------
202 * SUNLinSolResid Test
203 * --------------------------------------------------------------------*/
Test_SUNLinSolResid(SUNLinearSolver S,int myid)204 int Test_SUNLinSolResid(SUNLinearSolver S, int myid)
205 {
206 double start_time, stop_time;
207 N_Vector resid;
208
209 /* this test can fail if the function returns NULL */
210 start_time = get_time();
211 resid = SUNLinSolResid(S);
212 sync_device();
213 stop_time = get_time();
214
215 /* this test can also fail if the return value is NULL */
216 if (resid == NULL){
217 printf(">>> FAILED test -- SUNLinSolResid returned NULL N_Vector on Proc %d \n",
218 myid);
219 return(1);
220 }
221 else if (myid == 0) {
222 printf(" PASSED test -- SUNLinSolResid\n");
223 PRINT_TIME(" SUNLinSolResid Time: %22.15e \n \n", stop_time - start_time);
224 }
225
226 return(0);
227 }
228
229
230 /* ----------------------------------------------------------------------
231 * SUNLinSolSetATimes Test
232 * --------------------------------------------------------------------*/
Test_SUNLinSolSetATimes(SUNLinearSolver S,void * ATdata,ATimesFn ATimes,int myid)233 int Test_SUNLinSolSetATimes(SUNLinearSolver S, void *ATdata,
234 ATimesFn ATimes, int myid)
235 {
236 int failure;
237 double start_time, stop_time;
238
239 /* try calling SetATimes routine: should pass/fail based on expected input */
240 start_time = get_time();
241 failure = SUNLinSolSetATimes(S, ATdata, ATimes);
242 sync_device();
243 stop_time = get_time();
244
245 if (failure) {
246 printf(">>> FAILED test -- SUNLinSolSetATimes returned %d on Proc %d \n",
247 failure, myid);
248 return(1);
249 }
250 else if (myid == 0) {
251 printf(" PASSED test -- SUNLinSolSetATimes \n");
252 PRINT_TIME(" SUNLinSolSetATimes Time: %22.15e \n \n", stop_time - start_time);
253 }
254
255 return(0);
256 }
257
258
259 /* ----------------------------------------------------------------------
260 * SUNLinSolSetPreconditioner
261 * --------------------------------------------------------------------*/
Test_SUNLinSolSetPreconditioner(SUNLinearSolver S,void * Pdata,PSetupFn PSetup,PSolveFn PSolve,int myid)262 int Test_SUNLinSolSetPreconditioner(SUNLinearSolver S, void *Pdata,
263 PSetupFn PSetup, PSolveFn PSolve, int myid)
264 {
265 int failure;
266 double start_time, stop_time;
267
268 /* try calling SetPreconditioner routine: should pass/fail based on expected input */
269 start_time = get_time();
270 failure = SUNLinSolSetPreconditioner(S, Pdata, PSetup, PSolve);
271 sync_device();
272 stop_time = get_time();
273
274 if (failure) {
275 printf(">>> FAILED test -- SUNLinSolSetPreconditioner returned %d on Proc %d \n",
276 failure, myid);
277 return(1);
278 }
279 else if (myid == 0) {
280 printf(" PASSED test -- SUNLinSolSetPreconditioner \n");
281 PRINT_TIME(" SUNLinSolSetPreconditioner Time: %22.15e \n \n", stop_time - start_time);
282 }
283
284 return(0);
285 }
286
287
288 /* ----------------------------------------------------------------------
289 * SUNLinSolSetScalingVectors
290 * --------------------------------------------------------------------*/
Test_SUNLinSolSetScalingVectors(SUNLinearSolver S,N_Vector s1,N_Vector s2,int myid)291 int Test_SUNLinSolSetScalingVectors(SUNLinearSolver S, N_Vector s1,
292 N_Vector s2, int myid)
293 {
294 int failure;
295 double start_time, stop_time;
296
297 /* try calling SetScalingVectors routine: should pass/fail based on expected input */
298 start_time = get_time();
299 failure = SUNLinSolSetScalingVectors(S, s1, s2);
300 sync_device();
301 stop_time = get_time();
302
303 if (failure) {
304 printf(">>> FAILED test -- SUNLinSolSetScalingVectors returned %d on Proc %d \n",
305 failure, myid);
306 return(1);
307 }
308 else if (myid == 0) {
309 printf(" PASSED test -- SUNLinSolSetScalingVectors \n");
310 PRINT_TIME(" SUNLinSolSetScalingVectors Time: %22.15e \n \n", stop_time - start_time);
311 }
312
313 return(0);
314 }
315
316
317 /* ----------------------------------------------------------------------
318 * SUNLinSolInitialize Test
319 * --------------------------------------------------------------------*/
Test_SUNLinSolInitialize(SUNLinearSolver S,int myid)320 int Test_SUNLinSolInitialize(SUNLinearSolver S, int myid)
321 {
322 int failure;
323 double start_time, stop_time;
324
325 start_time = get_time();
326 failure = SUNLinSolInitialize(S);
327 sync_device();
328 stop_time = get_time();
329
330 if (failure) {
331 printf(">>> FAILED test -- SUNLinSolInitialize check, Proc %d \n", myid);
332 PRINT_TIME(" SUNLinSolInitialize Time: %22.15e \n \n", stop_time - start_time);
333 return(1);
334 }
335 else if (myid == 0) {
336 printf(" PASSED test -- SUNLinSolInitialize \n");
337 PRINT_TIME(" SUNLinSolInitialize Time: %22.15e \n \n", stop_time - start_time);
338 }
339
340 return(0);
341 }
342
343
344 /* ----------------------------------------------------------------------
345 * SUNLinSolSetup Test
346 *
347 * This test must follow Test_SUNLinSolInitialize
348 * --------------------------------------------------------------------*/
Test_SUNLinSolSetup(SUNLinearSolver S,SUNMatrix A,int myid)349 int Test_SUNLinSolSetup(SUNLinearSolver S, SUNMatrix A, int myid)
350 {
351 int failure;
352 double start_time, stop_time;
353
354 start_time = get_time();
355 failure = SUNLinSolSetup(S, A);
356 sync_device();
357 stop_time = get_time();
358
359 if (failure) {
360 printf(">>> FAILED test -- SUNLinSolSetup check, Proc %d \n", myid);
361 PRINT_TIME(" SUNLinSolSetup Time: %22.15e \n \n", stop_time - start_time);
362 return(1);
363 }
364 else if (myid == 0) {
365 printf(" PASSED test -- SUNLinSolSetup \n");
366 PRINT_TIME(" SUNLinSolSetup Time: %22.15e \n \n", stop_time - start_time);
367 }
368
369 return(0);
370 }
371
372
373 /* ----------------------------------------------------------------------
374 * SUNLinSolSolve Test
375 *
376 * This test must follow Test_SUNLinSolSetup. Also, x must be the
377 * solution to the linear system A*x = b (for the original A matrix);
378 * while the 'A' that is supplied to this function should have been
379 * 'setup' by the Test_SUNLinSolSetup() function prior to this call.
380 * --------------------------------------------------------------------*/
Test_SUNLinSolSolve(SUNLinearSolver S,SUNMatrix A,N_Vector x,N_Vector b,realtype tol,int myid)381 int Test_SUNLinSolSolve(SUNLinearSolver S, SUNMatrix A, N_Vector x,
382 N_Vector b, realtype tol, int myid)
383 {
384 int failure;
385 double start_time, stop_time;
386 N_Vector y;
387
388 /* clone to create solution vector */
389 y = N_VClone(x);
390 N_VConst(ZERO, y);
391
392 sync_device();
393
394 /* perform solve */
395 start_time = get_time();
396 failure = SUNLinSolSolve(S, A, y, b, tol);
397 sync_device();
398 stop_time = get_time();
399 if (failure) {
400 printf(">>> FAILED test -- SUNLinSolSolve returned %d on Proc %d \n",
401 failure, myid);
402 }
403 if (failure < 0) {
404 N_VDestroy(y);
405 return(1);
406 }
407
408 /* Check solution, and copy y into x for return */
409 failure = check_vector(x, y, 10.0*tol);
410 N_VScale(ONE, y, x);
411 if (failure) {
412 printf(">>> FAILED test -- SUNLinSolSolve check, Proc %d \n", myid);
413 PRINT_TIME(" SUNLinSolSolve Time: %22.15e \n \n", stop_time - start_time);
414 N_VDestroy(y);
415 return(1);
416 }
417 else if (myid == 0) {
418 printf(" PASSED test -- SUNLinSolSolve \n");
419 PRINT_TIME(" SUNLinSolSolve Time: %22.15e \n \n", stop_time - start_time);
420 }
421
422 N_VDestroy(y);
423 return(0);
424 }
425
426
427 /* ======================================================================
428 * Private functions
429 * ====================================================================*/
430
431 #if defined( SUNDIALS_HAVE_POSIX_TIMERS) && defined(_POSIX_TIMERS)
432 time_t base_time_tv_sec = 0; /* Base time; makes time values returned
433 by get_time easier to read when
434 printed since they will be zero
435 based.
436 */
437 #endif
438
SetTiming(int onoff)439 void SetTiming(int onoff)
440 {
441 print_time = onoff;
442
443 #if defined( SUNDIALS_HAVE_POSIX_TIMERS) && defined(_POSIX_TIMERS)
444 struct timespec spec;
445 clock_gettime( CLOCK_MONOTONIC_RAW, &spec );
446 base_time_tv_sec = spec.tv_sec;
447 #endif
448 }
449
450 /* ----------------------------------------------------------------------
451 * Timer
452 * --------------------------------------------------------------------*/
get_time()453 static double get_time()
454 {
455 #if defined( SUNDIALS_HAVE_POSIX_TIMERS) && defined(_POSIX_TIMERS)
456 struct timespec spec;
457 clock_gettime( CLOCK_MONOTONIC_RAW, &spec );
458 double time = (double)(spec.tv_sec - base_time_tv_sec) + ((double)(spec.tv_nsec) / 1E9);
459 #else
460 double time = 0;
461 #endif
462 return time;
463 }
464