1 /*
2  * -----------------------------------------------------------------
3  * Programmer(s): Daniel R. Reynolds @ SMU
4  *                David J. Gardner @ LLNL
5  * -----------------------------------------------------------------
6  * SUNDIALS Copyright Start
7  * Copyright (c) 2002-2020, 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