1 /* -----------------------------------------------------------------
2 * Programmer(s): Daniel R. Reynolds @ SMU
3 * -----------------------------------------------------------------
4 * SUNDIALS Copyright Start
5 * Copyright (c) 2002-2020, 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 ManyVector implementation
15 * of the NVECTOR package.
16 * -----------------------------------------------------------------*/
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <sundials/sundials_math.h>
21 #if SUNDIALS_MPI_ENABLED
22 #include <nvector/nvector_mpimanyvector.h>
23 #else
24 #include <nvector/nvector_manyvector.h>
25 #endif
26
27 /* Macro to handle separate MPI-aware/unaware installations */
28 #if SUNDIALS_MPI_ENABLED
29 #define MVAPPEND(fun) fun##_MPIManyVector
30 #else
31 #define MVAPPEND(fun) fun##_ManyVector
32 #endif
33
34 #define ZERO RCONST(0.0)
35 #define ONE RCONST(1.0)
36
37 /* -----------------------------------------------------------------
38 ManyVector content accessor macros
39 -----------------------------------------------------------------*/
40 #if SUNDIALS_MPI_ENABLED
41 #define MANYVECTOR_CONTENT(v) ( (N_VectorContent_MPIManyVector)(v->content) )
42 #define MANYVECTOR_COMM(v) ( MANYVECTOR_CONTENT(v)->comm )
43 #else
44 #define MANYVECTOR_CONTENT(v) ( (N_VectorContent_ManyVector)(v->content) )
45 #endif
46 #define MANYVECTOR_NUM_SUBVECS(v) ( MANYVECTOR_CONTENT(v)->num_subvectors )
47 #define MANYVECTOR_GLOBLENGTH(v) ( MANYVECTOR_CONTENT(v)->global_length )
48 #define MANYVECTOR_SUBVECS(v) ( MANYVECTOR_CONTENT(v)->subvec_array )
49 #define MANYVECTOR_SUBVEC(v,i) ( MANYVECTOR_SUBVECS(v)[i] )
50 #define MANYVECTOR_OWN_DATA(v) ( MANYVECTOR_CONTENT(v)->own_data )
51
52 /* -----------------------------------------------------------------
53 Prototypes of utility routines
54 -----------------------------------------------------------------*/
55 static N_Vector ManyVectorClone(N_Vector w, booleantype cloneempty);
56 #if SUNDIALS_MPI_ENABLED
57 static int SubvectorMPIRank(N_Vector w);
58 #endif
59
60 /* -----------------------------------------------------------------
61 ManyVector API routines
62 -----------------------------------------------------------------*/
63
64 #if SUNDIALS_MPI_ENABLED
65
66 /* This function creates an MPIManyVector from a set of existing
67 N_Vector objects, along with a user-created MPI (inter/intra)communicator
68 that couples all subvectors together. */
N_VMake_MPIManyVector(MPI_Comm comm,sunindextype num_subvectors,N_Vector * vec_array)69 N_Vector N_VMake_MPIManyVector(MPI_Comm comm, sunindextype num_subvectors,
70 N_Vector *vec_array)
71 {
72 N_Vector v;
73 N_VectorContent_MPIManyVector content;
74 sunindextype i, local_length;
75 int rank, retval;
76
77 /* Check that input N_Vectors are non-NULL */
78 if (vec_array == NULL) return(NULL);
79 for (i=0; i<num_subvectors; i++)
80 if (vec_array[i] == NULL) return(NULL);
81
82 /* Create vector */
83 v = NULL;
84 v = N_VNewEmpty();
85 if (v == NULL) return(NULL);
86
87 /* Attach operations */
88
89 /* constructors, destructors, and utility operations */
90 v->ops->nvgetvectorid = N_VGetVectorID_MPIManyVector;
91 v->ops->nvcloneempty = N_VCloneEmpty_MPIManyVector;
92 v->ops->nvclone = N_VClone_MPIManyVector;
93 v->ops->nvdestroy = N_VDestroy_MPIManyVector;
94 v->ops->nvspace = N_VSpace_MPIManyVector;
95 v->ops->nvgetcommunicator = N_VGetCommunicator_MPIManyVector;
96 v->ops->nvgetlength = N_VGetLength_MPIManyVector;
97
98 /* standard vector operations */
99 v->ops->nvlinearsum = N_VLinearSum_MPIManyVector;
100 v->ops->nvconst = N_VConst_MPIManyVector;
101 v->ops->nvprod = N_VProd_MPIManyVector;
102 v->ops->nvdiv = N_VDiv_MPIManyVector;
103 v->ops->nvscale = N_VScale_MPIManyVector;
104 v->ops->nvabs = N_VAbs_MPIManyVector;
105 v->ops->nvinv = N_VInv_MPIManyVector;
106 v->ops->nvaddconst = N_VAddConst_MPIManyVector;
107 v->ops->nvdotprod = N_VDotProd_MPIManyVector;
108 v->ops->nvmaxnorm = N_VMaxNorm_MPIManyVector;
109 v->ops->nvwrmsnorm = N_VWrmsNorm_MPIManyVector;
110 v->ops->nvwrmsnormmask = N_VWrmsNormMask_MPIManyVector;
111 v->ops->nvmin = N_VMin_MPIManyVector;
112 v->ops->nvwl2norm = N_VWL2Norm_MPIManyVector;
113 v->ops->nvl1norm = N_VL1Norm_MPIManyVector;
114 v->ops->nvcompare = N_VCompare_MPIManyVector;
115 v->ops->nvinvtest = N_VInvTest_MPIManyVector;
116 v->ops->nvconstrmask = N_VConstrMask_MPIManyVector;
117 v->ops->nvminquotient = N_VMinQuotient_MPIManyVector;
118
119 /* fused vector operations */
120 v->ops->nvlinearcombination = N_VLinearCombination_MPIManyVector;
121 v->ops->nvscaleaddmulti = N_VScaleAddMulti_MPIManyVector;
122 v->ops->nvdotprodmulti = N_VDotProdMulti_MPIManyVector;
123
124 /* vector array operations */
125 v->ops->nvwrmsnormvectorarray = N_VWrmsNormVectorArray_MPIManyVector;
126 v->ops->nvwrmsnormmaskvectorarray = N_VWrmsNormMaskVectorArray_MPIManyVector;
127
128 /* local reduction operations */
129 v->ops->nvdotprodlocal = N_VDotProdLocal_MPIManyVector;
130 v->ops->nvmaxnormlocal = N_VMaxNormLocal_MPIManyVector;
131 v->ops->nvminlocal = N_VMinLocal_MPIManyVector;
132 v->ops->nvl1normlocal = N_VL1NormLocal_MPIManyVector;
133 v->ops->nvinvtestlocal = N_VInvTestLocal_MPIManyVector;
134 v->ops->nvconstrmasklocal = N_VConstrMaskLocal_MPIManyVector;
135 v->ops->nvminquotientlocal = N_VMinQuotientLocal_MPIManyVector;
136 v->ops->nvwsqrsumlocal = N_VWSqrSumLocal_MPIManyVector;
137 v->ops->nvwsqrsummasklocal = N_VWSqrSumMaskLocal_MPIManyVector;
138
139 /* Create content */
140 content = NULL;
141 content = (N_VectorContent_MPIManyVector) malloc(sizeof *content);
142 if (content == NULL) { N_VDestroy(v); return(NULL); }
143
144 /* Attach content */
145 v->content = content;
146
147 /* Attach content components */
148
149 /* set scalar content entries, and allocate/set subvector array */
150 content->comm = MPI_COMM_NULL;
151 content->num_subvectors = num_subvectors;
152 content->own_data = SUNFALSE;
153 content->subvec_array = NULL;
154 content->subvec_array = (N_Vector *) malloc(num_subvectors * sizeof(N_Vector));
155 if (content->subvec_array == NULL) { N_VDestroy(v); return(NULL); }
156 for (i=0; i<num_subvectors; i++)
157 content->subvec_array[i] = vec_array[i];
158
159 /* duplicate input communicator (if non-NULL) */
160 if (comm != MPI_COMM_NULL) {
161 retval = MPI_Comm_dup(comm, &(content->comm));
162 if (retval != MPI_SUCCESS) { N_VDestroy(v); return(NULL); }
163 }
164
165 /* Determine overall MPIManyVector length: sum contributions from all
166 subvectors where this rank is the root, then perform reduction */
167 local_length = 0;
168 for (i=0; i<num_subvectors; i++) {
169
170 /* determine rank of this task in subvector communicator
171 (serial vectors default to rank=0) */
172 rank = SubvectorMPIRank(vec_array[i]);
173 if (rank < 0) { N_VDestroy(v); return(NULL); }
174
175 /* accumulate contribution from root tasks */
176 if (vec_array[i]->ops->nvgetlength) {
177 if (rank == 0) local_length += N_VGetLength(vec_array[i]);
178 } else {
179 N_VDestroy(v);
180 return(NULL);
181 }
182 }
183 if (content->comm != MPI_COMM_NULL) {
184 retval = MPI_Allreduce(&local_length, &(content->global_length), 1,
185 MPI_SUNINDEXTYPE, MPI_SUM, content->comm);
186 if (retval != MPI_SUCCESS) { N_VDestroy(v); return(NULL); }
187 } else {
188 content->global_length = local_length;
189 }
190
191 return(v);
192 }
193 #endif
194
195
196 #if SUNDIALS_MPI_ENABLED
197 /* This function creates an MPIManyVector from a set of existing
198 N_Vector objects, under the requirement that all MPI-aware
199 sub-vectors use the same MPI communicator (this is verified
200 internally). If no sub-vector is MPI-aware, then this may be
201 used to describe data partitioning within a single node, and
202 a NULL communicator will be created. */
N_VNew_MPIManyVector(sunindextype num_subvectors,N_Vector * vec_array)203 N_Vector N_VNew_MPIManyVector(sunindextype num_subvectors,
204 N_Vector *vec_array)
205 {
206 sunindextype i;
207 booleantype nocommfound;
208 void* tmpcomm;
209 MPI_Comm comm, *vcomm;
210 int retval, comparison;
211 N_Vector v;
212
213 /* Check that all subvectors have identical MPI communicators (if present) */
214 nocommfound = SUNTRUE;
215 comm = MPI_COMM_NULL;
216 for (i=0; i<num_subvectors; i++) {
217
218 /* access MPI communicator for subvector i (vcomm);
219 if none is present then continue to next subvector */
220 tmpcomm = N_VGetCommunicator(vec_array[i]);
221 if (tmpcomm == NULL) continue;
222 vcomm = (MPI_Comm *) tmpcomm;
223
224 /* if this is the first communicator, create a copy */
225 if (nocommfound) {
226
227 /* set comm to duplicate this first subvector communicator */
228 retval = MPI_Comm_dup(*vcomm, &comm);
229 if (retval != MPI_SUCCESS) return(NULL);
230 nocommfound = SUNFALSE;
231
232 /* otherwise, verify that vcomm matches stored comm */
233 } else {
234
235 retval = MPI_Comm_compare(*vcomm, comm, &comparison);
236 if ((comparison != MPI_IDENT) && (comparison != MPI_CONGRUENT))
237 return(NULL);
238
239 }
240 }
241
242 /* Create vector using "Make" routine and shared communicator (if non-NULL) */
243 v = N_VMake_MPIManyVector(comm, num_subvectors, vec_array);
244 if (comm != MPI_COMM_NULL) MPI_Comm_free(&comm);
245 return(v);
246 }
247 #else
248 /* This function creates a ManyVector from a set of existing
249 N_Vector objects. ManyVector objects created with this constructor
250 may be used to describe data partitioning within a single node. */
N_VNew_ManyVector(sunindextype num_subvectors,N_Vector * vec_array)251 N_Vector N_VNew_ManyVector(sunindextype num_subvectors,
252 N_Vector *vec_array)
253 {
254 N_Vector v;
255 N_VectorContent_ManyVector content;
256 sunindextype i;
257
258 /* Check that input N_Vectors are non-NULL */
259 if (vec_array == NULL) return(NULL);
260 for (i=0; i<num_subvectors; i++)
261 if (vec_array[i] == NULL) return(NULL);
262
263 /* Create vector */
264 v = NULL;
265 v = N_VNewEmpty();
266 if (v == NULL) return(NULL);
267
268 /* Attach operations */
269
270 /* constructors, destructors, and utility operations */
271 v->ops->nvgetvectorid = N_VGetVectorID_ManyVector;
272 v->ops->nvcloneempty = N_VCloneEmpty_ManyVector;
273 v->ops->nvclone = N_VClone_ManyVector;
274 v->ops->nvdestroy = N_VDestroy_ManyVector;
275 v->ops->nvspace = N_VSpace_ManyVector;
276 v->ops->nvgetlength = N_VGetLength_ManyVector;
277
278 /* standard vector operations */
279 v->ops->nvlinearsum = N_VLinearSum_ManyVector;
280 v->ops->nvconst = N_VConst_ManyVector;
281 v->ops->nvprod = N_VProd_ManyVector;
282 v->ops->nvdiv = N_VDiv_ManyVector;
283 v->ops->nvscale = N_VScale_ManyVector;
284 v->ops->nvabs = N_VAbs_ManyVector;
285 v->ops->nvinv = N_VInv_ManyVector;
286 v->ops->nvaddconst = N_VAddConst_ManyVector;
287 v->ops->nvdotprod = N_VDotProdLocal_ManyVector;
288 v->ops->nvmaxnorm = N_VMaxNormLocal_ManyVector;
289 v->ops->nvwrmsnorm = N_VWrmsNorm_ManyVector;
290 v->ops->nvwrmsnormmask = N_VWrmsNormMask_ManyVector;
291 v->ops->nvmin = N_VMinLocal_ManyVector;
292 v->ops->nvwl2norm = N_VWL2Norm_ManyVector;
293 v->ops->nvl1norm = N_VL1NormLocal_ManyVector;
294 v->ops->nvcompare = N_VCompare_ManyVector;
295 v->ops->nvinvtest = N_VInvTestLocal_ManyVector;
296 v->ops->nvconstrmask = N_VConstrMaskLocal_ManyVector;
297 v->ops->nvminquotient = N_VMinQuotientLocal_ManyVector;
298
299 /* fused vector operations */
300 v->ops->nvlinearcombination = N_VLinearCombination_ManyVector;
301 v->ops->nvscaleaddmulti = N_VScaleAddMulti_ManyVector;
302 v->ops->nvdotprodmulti = N_VDotProdMulti_ManyVector;
303
304 /* vector array operations */
305 v->ops->nvwrmsnormvectorarray = N_VWrmsNormVectorArray_ManyVector;
306 v->ops->nvwrmsnormmaskvectorarray = N_VWrmsNormMaskVectorArray_ManyVector;
307
308 /* local reduction operations */
309 v->ops->nvdotprodlocal = N_VDotProdLocal_ManyVector;
310 v->ops->nvmaxnormlocal = N_VMaxNormLocal_ManyVector;
311 v->ops->nvminlocal = N_VMinLocal_ManyVector;
312 v->ops->nvl1normlocal = N_VL1NormLocal_ManyVector;
313 v->ops->nvinvtestlocal = N_VInvTestLocal_ManyVector;
314 v->ops->nvconstrmasklocal = N_VConstrMaskLocal_ManyVector;
315 v->ops->nvminquotientlocal = N_VMinQuotientLocal_ManyVector;
316 v->ops->nvwsqrsumlocal = N_VWSqrSumLocal_ManyVector;
317 v->ops->nvwsqrsummasklocal = N_VWSqrSumMaskLocal_ManyVector;
318
319 /* Create content */
320 content = NULL;
321 content = (N_VectorContent_ManyVector) malloc(sizeof *content);
322 if (content == NULL) { N_VDestroy(v); return(NULL); }
323
324 /* Attach content */
325 v->content = content;
326
327 /* Attach content components */
328
329 /* allocate and set subvector array */
330 content->num_subvectors = num_subvectors;
331 content->own_data = SUNFALSE;
332
333 content->subvec_array = NULL;
334 content->subvec_array = (N_Vector *) malloc(num_subvectors * sizeof(N_Vector));
335 if (content->subvec_array == NULL) { N_VDestroy(v); return(NULL); }
336
337 for (i=0; i<num_subvectors; i++)
338 content->subvec_array[i] = vec_array[i];
339
340 /* Determine overall ManyVector length: sum contributions from all subvectors */
341 content->global_length = 0;
342 for (i=0; i<num_subvectors; i++) {
343 if (vec_array[i]->ops->nvgetlength) {
344 content->global_length += N_VGetLength(vec_array[i]);
345 } else {
346 N_VDestroy(v);
347 return(NULL);
348 }
349 }
350
351 return(v);
352 }
353 #endif
354
355
356 /* This function returns the vec_num sub-N_Vector from the N_Vector
357 array. If vec_num is outside of applicable bounds, NULL is returned. */
MVAPPEND(N_VGetSubvector)358 N_Vector MVAPPEND(N_VGetSubvector)(N_Vector v, sunindextype vec_num)
359 {
360 if ( (vec_num < 0) || (vec_num > MANYVECTOR_NUM_SUBVECS(v)) )
361 return(NULL);
362 return(MANYVECTOR_SUBVEC(v,vec_num));
363 }
364
365
366 /* This function returns data pointer for the vec_num sub-N_Vector from
367 the N_Vector array. If vec_num is outside of applicable bounds, or if
368 the subvector does not support the N_VGetArrayPointer routine, then
369 NULL is returned. */
MVAPPEND(N_VGetSubvectorArrayPointer)370 realtype *MVAPPEND(N_VGetSubvectorArrayPointer)(N_Vector v, sunindextype vec_num)
371 {
372 if ( (vec_num < 0) || (vec_num > MANYVECTOR_NUM_SUBVECS(v)) )
373 return(NULL);
374 if ( MANYVECTOR_SUBVEC(v,vec_num)->ops->nvgetarraypointer == NULL )
375 return(NULL);
376 return(N_VGetArrayPointer(MANYVECTOR_SUBVEC(v,vec_num)));
377 }
378
379
380 /* This function sets the data pointer for the vec_num sub-N_Vector from
381 the N_Vector array. If vec_num is outside of applicable bounds, or if
382 the subvector does not support the N_VSetArrayPointer routine, then
383 -1 is returned; otherwise this routine returns 0. */
MVAPPEND(N_VSetSubvectorArrayPointer)384 int MVAPPEND(N_VSetSubvectorArrayPointer)(realtype *v_data, N_Vector v, sunindextype vec_num)
385 {
386 if ( (vec_num < 0) || (vec_num > MANYVECTOR_NUM_SUBVECS(v)) )
387 return(-1);
388 if ( MANYVECTOR_SUBVEC(v,vec_num)->ops->nvsetarraypointer == NULL )
389 return(-1);
390 N_VSetArrayPointer(v_data, MANYVECTOR_SUBVEC(v,vec_num));
391 return(0);
392 }
393
394
395 /* This function returns the overall number of sub-vectors.
396 It returns a locally stored integer, and is therefore a local call. */
MVAPPEND(N_VGetNumSubvectors)397 sunindextype MVAPPEND(N_VGetNumSubvectors)(N_Vector v)
398 {
399 return(MANYVECTOR_NUM_SUBVECS(v));
400 }
401
402
403 /* -----------------------------------------------------------------
404 ManyVector implementations of generic NVector routines
405 -----------------------------------------------------------------*/
406
407 /* Returns vector type ID. Used to identify vector implementation
408 from abstract N_Vector interface. */
MVAPPEND(N_VGetVectorID)409 N_Vector_ID MVAPPEND(N_VGetVectorID)(N_Vector v)
410 {
411 #if SUNDIALS_MPI_ENABLED
412 return(SUNDIALS_NVEC_MPIMANYVECTOR);
413 #else
414 return(SUNDIALS_NVEC_MANYVECTOR);
415 #endif
416 }
417
418
419 /* Clones a ManyVector, calling CloneEmpty on subvectors. */
MVAPPEND(N_VCloneEmpty)420 N_Vector MVAPPEND(N_VCloneEmpty)(N_Vector w)
421 {
422 return(ManyVectorClone(w, SUNTRUE));
423 }
424
425
426 /* Clones a ManyVector, calling Clone on subvectors. */
MVAPPEND(N_VClone)427 N_Vector MVAPPEND(N_VClone)(N_Vector w)
428 {
429 return(ManyVectorClone(w, SUNFALSE));
430 }
431
432
433 /* Destroys a ManyVector */
MVAPPEND(N_VDestroy)434 void MVAPPEND(N_VDestroy)(N_Vector v)
435 {
436 sunindextype i;
437
438 if (v == NULL) return;
439
440 /* free content */
441 if (v->content != NULL) {
442 /* if subvectors are owned by v, then Destroy those */
443 if ((MANYVECTOR_OWN_DATA(v) == SUNTRUE) && (MANYVECTOR_SUBVECS(v) != NULL)) {
444 for (i=0; i<MANYVECTOR_NUM_SUBVECS(v); i++) {
445 N_VDestroy(MANYVECTOR_SUBVEC(v,i));
446 MANYVECTOR_SUBVEC(v,i) = NULL;
447 }
448 }
449
450 /* free subvector array */
451 free(MANYVECTOR_SUBVECS(v));
452 MANYVECTOR_SUBVECS(v) = NULL;
453
454 #if SUNDIALS_MPI_ENABLED
455 /* free communicator */
456 if (MANYVECTOR_COMM(v) != MPI_COMM_NULL) MPI_Comm_free(&(MANYVECTOR_COMM(v)));
457 MANYVECTOR_COMM(v) = MPI_COMM_NULL;
458 #endif
459
460 /* free content structure */
461 free(v->content);
462 v->content = NULL;
463 }
464
465 /* free ops and vector */
466 if (v->ops != NULL) { free(v->ops); v->ops = NULL; }
467 free(v); v = NULL;
468
469 return;
470 }
471
472
473 /* Returns the space requirements for the ManyVector, by accumulating this
474 information from all subvectors. */
MVAPPEND(N_VSpace)475 void MVAPPEND(N_VSpace)(N_Vector v, sunindextype *lrw, sunindextype *liw)
476 {
477 sunindextype i, lrw1, liw1;
478 *lrw = 0;
479 *liw = 0;
480 for (i=0; i<MANYVECTOR_NUM_SUBVECS(v); i++) {
481 /* update space requirements for this subvector (if 'nvspace' is implemented) */
482 if ((MANYVECTOR_SUBVEC(v,i))->ops->nvspace != NULL) {
483 N_VSpace(MANYVECTOR_SUBVEC(v,i), &lrw1, &liw1);
484 *lrw += lrw1;
485 *liw += liw1;
486 }
487 }
488 return;
489 }
490
491
492 #if SUNDIALS_MPI_ENABLED
493 /* This function retrieves the MPI Communicator from an MPIManyVector object. */
N_VGetCommunicator_MPIManyVector(N_Vector v)494 void *N_VGetCommunicator_MPIManyVector(N_Vector v)
495 {
496 if (MANYVECTOR_COMM(v) == MPI_COMM_NULL)
497 return NULL;
498 else
499 return((void *) &MANYVECTOR_COMM(v));
500 }
501 #else
502 /* This function retrieves the MPI Communicator from a ManyVector object. */
N_VGetCommunicator_ManyVector(N_Vector v)503 void *N_VGetCommunicator_ManyVector(N_Vector v)
504 {
505 return NULL;
506 }
507 #endif
508
509
510 /* This function retrieves the global length of a ManyVector object. */
MVAPPEND(N_VGetLength)511 sunindextype MVAPPEND(N_VGetLength)(N_Vector v)
512 {
513 return(MANYVECTOR_GLOBLENGTH(v));
514 }
515
516
517 /* Performs the linear sum z = a*x + b*y by calling N_VLinearSum on all subvectors;
518 this routine does not check that x, y and z are ManyVectors, if they have the
519 same number of subvectors, or if these subvectors are compatible. */
MVAPPEND(N_VLinearSum)520 void MVAPPEND(N_VLinearSum)(realtype a, N_Vector x, realtype b, N_Vector y, N_Vector z)
521 {
522 sunindextype i;
523 for (i=0; i<MANYVECTOR_NUM_SUBVECS(x); i++)
524 N_VLinearSum(a, MANYVECTOR_SUBVEC(x,i), b, MANYVECTOR_SUBVEC(y,i),
525 MANYVECTOR_SUBVEC(z,i));
526 return;
527 }
528
529
530 /* Performs the operation z = c by calling N_VConst on all subvectors. */
MVAPPEND(N_VConst)531 void MVAPPEND(N_VConst)(realtype c, N_Vector z)
532 {
533 sunindextype i;
534 for (i=0; i<MANYVECTOR_NUM_SUBVECS(z); i++)
535 N_VConst(c, MANYVECTOR_SUBVEC(z,i));
536 return;
537 }
538
539
540 /* Performs the operation z_j = x_j*y_j by calling N_VProd on all subvectors;
541 this routine does not check that x, y and z are ManyVectors, if they have the
542 same number of subvectors, or if these subvectors are compatible. */
MVAPPEND(N_VProd)543 void MVAPPEND(N_VProd)(N_Vector x, N_Vector y, N_Vector z)
544 {
545 sunindextype i;
546 for (i=0; i<MANYVECTOR_NUM_SUBVECS(x); i++)
547 N_VProd(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(y,i),
548 MANYVECTOR_SUBVEC(z,i));
549 return;
550 }
551
552
553 /* Performs the operation z_j = x_j/y_j by calling N_VDiv on all subvectors;
554 this routine does not check that x, y and z are ManyVectors, if they have the
555 same number of subvectors, or if these subvectors are compatible. */
MVAPPEND(N_VDiv)556 void MVAPPEND(N_VDiv)(N_Vector x, N_Vector y, N_Vector z)
557 {
558 sunindextype i;
559 for (i=0; i<MANYVECTOR_NUM_SUBVECS(x); i++)
560 N_VDiv(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(y,i),
561 MANYVECTOR_SUBVEC(z,i));
562 return;
563 }
564
565
566 /* Performs the operation z_j = c*x_j by calling N_VScale on all subvectors;
567 this routine does not check that x and z are ManyVectors, if they have the
568 same number of subvectors, or if these subvectors are compatible. */
MVAPPEND(N_VScale)569 void MVAPPEND(N_VScale)(realtype c, N_Vector x, N_Vector z)
570 {
571 sunindextype i;
572 for (i=0; i<MANYVECTOR_NUM_SUBVECS(x); i++)
573 N_VScale(c, MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(z,i));
574 return;
575 }
576
577
578 /* Performs the operation z_j = |x_j| by calling N_VAbs on all subvectors;
579 this routine does not check that x and z are ManyVectors, if they have the
580 same number of subvectors, or if these subvectors are compatible. */
MVAPPEND(N_VAbs)581 void MVAPPEND(N_VAbs)(N_Vector x, N_Vector z)
582 {
583 sunindextype i;
584 for (i=0; i<MANYVECTOR_NUM_SUBVECS(x); i++)
585 N_VAbs(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(z,i));
586 return;
587 }
588
589
590 /* Performs the operation z_j = 1/x_j by calling N_VInv on all subvectors;
591 this routine does not check that x and z are ManyVectors, if they have the
592 same number of subvectors, or if these subvectors are compatible. */
MVAPPEND(N_VInv)593 void MVAPPEND(N_VInv)(N_Vector x, N_Vector z)
594 {
595 sunindextype i;
596 for (i=0; i<MANYVECTOR_NUM_SUBVECS(x); i++)
597 N_VInv(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(z,i));
598 return;
599 }
600
601
602 /* Performs the operation z_j = x_j + b by calling N_VAddConst on all subvectors;
603 this routine does not check that x and z are ManyVectors, if they have the
604 same number of subvectors, or if these subvectors are compatible. */
MVAPPEND(N_VAddConst)605 void MVAPPEND(N_VAddConst)(N_Vector x, realtype b, N_Vector z)
606 {
607 sunindextype i;
608 for (i=0; i<MANYVECTOR_NUM_SUBVECS(x); i++)
609 N_VAddConst(MANYVECTOR_SUBVEC(x,i), b, MANYVECTOR_SUBVEC(z,i));
610 return;
611 }
612
613
614 /* Performs the MPI task-local dot product of two ManyVectors by calling
615 N_VDotProdLocal on all subvectors; this routine does not check that x and
616 y are ManyVectors, if they have the same number of subvectors, or if these
617 subvectors are compatible.
618
619 If any subvector does not implement the N_VDotProdLocal routine (NULL
620 function pointer), then this routine will call N_VDotProd, but only
621 accumulate the sum if this is the root task for that subvector's
622 communicator (note: serial vectors are always root task). */
MVAPPEND(N_VDotProdLocal)623 realtype MVAPPEND(N_VDotProdLocal)(N_Vector x, N_Vector y)
624 {
625 sunindextype i;
626 realtype sum;
627 #if SUNDIALS_MPI_ENABLED
628 realtype contrib;
629 int rank;
630 #endif
631
632 /* initialize output*/
633 sum = ZERO;
634
635 for (i=0; i<MANYVECTOR_NUM_SUBVECS(x); i++) {
636
637 #if SUNDIALS_MPI_ENABLED
638
639 /* check for nvdotprodlocal in subvector */
640 if (MANYVECTOR_SUBVEC(x,i)->ops->nvdotprodlocal) {
641
642 sum += N_VDotProdLocal(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(y,i));
643
644 /* otherwise, call nvdotprod and root tasks accumulate to overall sum */
645 } else {
646
647 contrib = N_VDotProd(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(y,i));
648
649 /* get this task's rank in subvector communicator (note: serial
650 subvectors will result in rank==0) */
651 rank = SubvectorMPIRank(MANYVECTOR_SUBVEC(x,i));
652 if (rank < 0) return(ZERO);
653 if (rank == 0) sum += contrib;
654
655 }
656
657 #else
658
659 /* add subvector contribution */
660 sum += N_VDotProd(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(y,i));
661
662 #endif
663
664 }
665
666 return(sum);
667 }
668
669
670 #if SUNDIALS_MPI_ENABLED
671 /* Performs the dot product of two ManyVectors by calling N_VDotProdLocal and
672 combining the results. This routine does not check that x and y are
673 ManyVectors, if they have the same number of subvectors, or if these
674 subvectors are compatible. */
N_VDotProd_MPIManyVector(N_Vector x,N_Vector y)675 realtype N_VDotProd_MPIManyVector(N_Vector x, N_Vector y)
676 {
677 realtype lsum, gsum;
678 lsum = gsum = N_VDotProdLocal_MPIManyVector(x,y);
679 if (MANYVECTOR_COMM(x) != MPI_COMM_NULL)
680 MPI_Allreduce(&lsum, &gsum, 1, MPI_SUNREALTYPE, MPI_SUM, MANYVECTOR_COMM(x));
681 return(gsum);
682 }
683 #endif
684
685
686 /* Performs the MPI task-local maximum norm of a ManyVector by calling
687 N_VMaxNormLocal on all subvectors.
688
689 If any subvector does not implement the N_VMaxNormLocal routine (NULL
690 function pointer), then this routine will call N_VMaxNorm instead. */
MVAPPEND(N_VMaxNormLocal)691 realtype MVAPPEND(N_VMaxNormLocal)(N_Vector x)
692 {
693 sunindextype i;
694 realtype max, lmax;
695
696 /* initialize output*/
697 max = ZERO;
698
699 for (i=0; i<MANYVECTOR_NUM_SUBVECS(x); i++) {
700
701 /* check for nvmaxnormlocal in subvector */
702 if (MANYVECTOR_SUBVEC(x,i)->ops->nvmaxnormlocal) {
703
704 lmax = N_VMaxNormLocal(MANYVECTOR_SUBVEC(x,i));
705 max = (max > lmax) ? max : lmax;
706
707 /* otherwise, call nvmaxnorm and accumulate to overall max */
708 } else {
709
710 lmax = N_VMaxNorm(MANYVECTOR_SUBVEC(x,i));
711 max = (max > lmax) ? max : lmax;
712
713 }
714 }
715
716 return(max);
717 }
718
719
720 #if SUNDIALS_MPI_ENABLED
721 /* Performs the maximum norm of a ManyVector by calling N_VMaxNormLocal and
722 combining the results. */
N_VMaxNorm_MPIManyVector(N_Vector x)723 realtype N_VMaxNorm_MPIManyVector(N_Vector x)
724 {
725 realtype lmax, gmax;
726 lmax = gmax = N_VMaxNormLocal_MPIManyVector(x);
727 if (MANYVECTOR_COMM(x) != MPI_COMM_NULL)
728 MPI_Allreduce(&lmax, &gmax, 1, MPI_SUNREALTYPE, MPI_MAX, MANYVECTOR_COMM(x));
729 return(gmax);
730 }
731 #endif
732
733
734 /* Performs the MPI task-local weighted squared sum of a ManyVector by calling
735 N_VWSqrSumLocal on all subvectors; this routine does not check that x and
736 w are ManyVectors, if they have the same number of subvectors, or if these
737 subvectors are compatible.
738
739 If any subvector does not implement the N_VWSqrSumLocal routine (NULL
740 function pointer), then this routine will call N_VWrmsNorm and N_VGetLength
741 to unravel the squared sum of the subvector components. It will then only
742 accumulate this to the overall sum if this is the root task for that
743 subvector's communicator (note: serial vectors are always root task). */
MVAPPEND(N_VWSqrSumLocal)744 realtype MVAPPEND(N_VWSqrSumLocal)(N_Vector x, N_Vector w)
745 {
746 sunindextype i, N;
747 realtype sum, contrib;
748 #if SUNDIALS_MPI_ENABLED
749 int rank;
750 #endif
751
752 /* initialize output*/
753 sum = ZERO;
754
755 for (i=0; i<MANYVECTOR_NUM_SUBVECS(x); i++) {
756
757 #if SUNDIALS_MPI_ENABLED
758
759 /* check for nvwsqrsumlocal in subvector */
760 if (MANYVECTOR_SUBVEC(x,i)->ops->nvwsqrsumlocal) {
761
762 sum += N_VWSqrSumLocal(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(w,i));
763
764 /* otherwise, call nvwrmsnorm, and accumulate to overall sum on root task */
765 } else {
766
767 contrib = N_VWrmsNorm(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(w,i));
768
769 /* get this task's rank in subvector communicator (note: serial
770 subvectors will result in rank==0) */
771 rank = SubvectorMPIRank(MANYVECTOR_SUBVEC(x,i));
772 if (rank < 0) return(ZERO);
773 if (rank == 0) {
774 N = N_VGetLength(MANYVECTOR_SUBVEC(x,i));
775 sum += (contrib*contrib*N);
776 }
777 }
778
779 #else
780
781 /* accumulate subvector contribution to overall sum */
782 contrib = N_VWrmsNorm(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(w,i));
783 N = N_VGetLength(MANYVECTOR_SUBVEC(x,i));
784 sum += (contrib*contrib*N);
785
786 #endif
787
788 }
789
790 return(sum);
791 }
792
793
794 /* Performs the WRMS norm of a ManyVector by calling N_VWSqrSumLocal and
795 combining the results; this routine does not check that x and
796 w are ManyVectors, if they have the same number of subvectors, or if these
797 subvectors are compatible. */
MVAPPEND(N_VWrmsNorm)798 realtype MVAPPEND(N_VWrmsNorm)(N_Vector x, N_Vector w)
799 {
800 realtype gsum;
801 #if SUNDIALS_MPI_ENABLED
802 realtype lsum;
803 lsum = gsum = N_VWSqrSumLocal_MPIManyVector(x, w);
804 if (MANYVECTOR_COMM(x) != MPI_COMM_NULL)
805 MPI_Allreduce(&lsum, &gsum, 1, MPI_SUNREALTYPE, MPI_SUM, MANYVECTOR_COMM(x));
806 #else
807 gsum = N_VWSqrSumLocal_ManyVector(x, w);
808 #endif
809 return(SUNRsqrt(gsum/(MANYVECTOR_GLOBLENGTH(x))));
810 }
811
812
813 /* Performs the MPI task-local masked weighted squared sum of a ManyVector by
814 calling N_VWSqrSumMaskLocal on all subvectors; this routine does not check
815 that x, w and id are ManyVectors, if they have the same number of
816 subvectors, or if these subvectors are compatible.
817
818 If any subvector does not implement the N_VWSqrSumLocal routine (NULL
819 function pointer), then this routine will call N_VWrmsNormMask and
820 N_VGetLength to unravel the masked squared sum of the subvector components.
821 It will then only accumulate this to the overall sum if this is the root
822 task for that subvector's communicator (note: serial vectors are always
823 root task). */
MVAPPEND(N_VWSqrSumMaskLocal)824 realtype MVAPPEND(N_VWSqrSumMaskLocal)(N_Vector x, N_Vector w, N_Vector id)
825 {
826 sunindextype i, N;
827 realtype sum, contrib;
828 #if SUNDIALS_MPI_ENABLED
829 int rank;
830 #endif
831
832 /* initialize output*/
833 sum = ZERO;
834
835 for (i=0; i<MANYVECTOR_NUM_SUBVECS(x); i++) {
836
837 #if SUNDIALS_MPI_ENABLED
838
839 /* check for nvwsqrsummasklocal in subvector */
840 if (MANYVECTOR_SUBVEC(x,i)->ops->nvwsqrsummasklocal) {
841
842 sum += N_VWSqrSumMaskLocal(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(w,i),
843 MANYVECTOR_SUBVEC(id,i));
844
845 /* otherwise, call nvwrmsnormmask, and accumulate to overall sum on root task */
846 } else {
847
848 contrib = N_VWrmsNormMask(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(w,i),
849 MANYVECTOR_SUBVEC(id,i));
850
851 /* get this task's rank in subvector communicator (note: serial
852 subvectors will result in rank==0) */
853 rank = SubvectorMPIRank(MANYVECTOR_SUBVEC(x,i));
854 if (rank < 0) return(ZERO);
855 if (rank == 0) {
856 N = N_VGetLength(MANYVECTOR_SUBVEC(x,i));
857 sum += (contrib*contrib*N);
858 }
859 }
860
861 #else
862
863 /* accumulate subvector contribution to overall sum */
864 contrib = N_VWrmsNormMask(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(w,i),
865 MANYVECTOR_SUBVEC(id,i));
866 N = N_VGetLength(MANYVECTOR_SUBVEC(x,i));
867 sum += (contrib*contrib*N);
868
869 #endif
870
871 }
872
873 return(sum);
874 }
875
876
877 /* Performs the masked WRMS norm of a ManyVector by calling N_VWSqrSumMaskLocal
878 and combining the results; this routine does not check that x, w and id are
879 ManyVectors, if they have the same number of subvectors, or if these subvectors
880 are compatible. */
MVAPPEND(N_VWrmsNormMask)881 realtype MVAPPEND(N_VWrmsNormMask)(N_Vector x, N_Vector w, N_Vector id)
882 {
883 realtype gsum;
884 #if SUNDIALS_MPI_ENABLED
885 realtype lsum;
886 lsum = gsum = N_VWSqrSumMaskLocal_MPIManyVector(x, w, id);
887 if (MANYVECTOR_COMM(x) != MPI_COMM_NULL)
888 MPI_Allreduce(&lsum, &gsum, 1, MPI_SUNREALTYPE, MPI_SUM, MANYVECTOR_COMM(x));
889 #else
890 gsum = N_VWSqrSumMaskLocal_ManyVector(x, w, id);
891 #endif
892 return(SUNRsqrt(gsum/(MANYVECTOR_GLOBLENGTH(x))));
893 }
894
895
896 /* Computes the MPI task-local minimum entry of a ManyVector by calling
897 N_VMinLocal on all subvectors.
898
899 If any subvector does not implement the N_VMinLocal routine (NULL
900 function pointer), then this routine will call N_VMin instead. */
MVAPPEND(N_VMinLocal)901 realtype MVAPPEND(N_VMinLocal)(N_Vector x)
902 {
903 sunindextype i;
904 realtype min, lmin;
905
906 /* initialize output*/
907 min = BIG_REAL;
908
909 for (i=0; i<MANYVECTOR_NUM_SUBVECS(x); i++) {
910
911 /* check for nvminlocal in subvector */
912 if (MANYVECTOR_SUBVEC(x,i)->ops->nvminlocal) {
913
914 lmin = N_VMinLocal(MANYVECTOR_SUBVEC(x,i));
915 min = (min < lmin) ? min : lmin;
916
917 /* otherwise, call nvmin and accumulate to overall min */
918 } else {
919
920 lmin = N_VMin(MANYVECTOR_SUBVEC(x,i));
921 min = (min < lmin) ? min : lmin;
922
923 }
924 }
925
926 return(min);
927 }
928
929
930 #if SUNDIALS_MPI_ENABLED
931 /* Computes the minimum entry of a ManyVector by calling N_VMinLocal and
932 combining the results. */
N_VMin_MPIManyVector(N_Vector x)933 realtype N_VMin_MPIManyVector(N_Vector x)
934 {
935 realtype lmin, gmin;
936 lmin = gmin = N_VMinLocal_MPIManyVector(x);
937 if (MANYVECTOR_COMM(x) != MPI_COMM_NULL)
938 MPI_Allreduce(&lmin, &gmin, 1, MPI_SUNREALTYPE, MPI_MIN, MANYVECTOR_COMM(x));
939 return(gmin);
940 }
941 #endif
942
943
944 /* Performs the WL2 norm of a ManyVector by calling N_VSqrSumLocal and
945 'massaging' the result. This routine does not check that x and w are
946 ManyVectors, if they have the same number of subvectors, or if these
947 subvectors are compatible. */
MVAPPEND(N_VWL2Norm)948 realtype MVAPPEND(N_VWL2Norm)(N_Vector x, N_Vector w)
949 {
950 realtype gsum;
951 #if SUNDIALS_MPI_ENABLED
952 realtype lsum;
953 lsum = gsum = N_VWSqrSumLocal_MPIManyVector(x, w);
954 if (MANYVECTOR_COMM(x) != MPI_COMM_NULL)
955 MPI_Allreduce(&lsum, &gsum, 1, MPI_SUNREALTYPE, MPI_SUM, MANYVECTOR_COMM(x));
956 #else
957 gsum = N_VWSqrSumLocal_ManyVector(x, w);
958 #endif
959 return(SUNRsqrt(gsum));
960 }
961
962
963 /* Performs the MPI task-local L1 norm of a ManyVector by calling N_VL1NormLocal on
964 all subvectors. If any subvector does not implement the N_VL1NormLocal routine
965 (NULL function pointer), then this routine will call N_VL1Norm, but only
966 accumulate the sum if this is the root task for that subvector's
967 communicator (note: serial vectors are always root task). */
MVAPPEND(N_VL1NormLocal)968 realtype MVAPPEND(N_VL1NormLocal)(N_Vector x)
969 {
970 sunindextype i;
971 realtype sum;
972 #if SUNDIALS_MPI_ENABLED
973 realtype contrib;
974 int rank;
975 #endif
976
977 /* initialize output*/
978 sum = ZERO;
979
980 for (i=0; i<MANYVECTOR_NUM_SUBVECS(x); i++) {
981
982 #if SUNDIALS_MPI_ENABLED
983
984 /* check for nvl1normlocal in subvector */
985 if (MANYVECTOR_SUBVEC(x,i)->ops->nvl1normlocal) {
986
987 sum += N_VL1NormLocal(MANYVECTOR_SUBVEC(x,i));
988
989 /* otherwise, call nvl1norm and root tasks accumulate to overall sum */
990 } else {
991
992 contrib = N_VL1Norm(MANYVECTOR_SUBVEC(x,i));
993
994 /* get this task's rank in subvector communicator (note: serial
995 subvectors will result in rank==0) */
996 rank = SubvectorMPIRank(MANYVECTOR_SUBVEC(x,i));
997 if (rank < 0) return(ZERO);
998 if (rank == 0) sum += contrib;
999
1000 }
1001
1002 #else
1003
1004 /* accumulate subvector contribution to overall sum */
1005 sum += N_VL1Norm(MANYVECTOR_SUBVEC(x,i));
1006
1007 #endif
1008
1009 }
1010
1011 return(sum);
1012 }
1013
1014
1015 #if SUNDIALS_MPI_ENABLED
1016 /* Performs the L1 norm of a ManyVector by calling N_VL1NormLocal and
1017 combining the results. */
N_VL1Norm_MPIManyVector(N_Vector x)1018 realtype N_VL1Norm_MPIManyVector(N_Vector x)
1019 {
1020 realtype lsum, gsum;
1021 lsum = gsum = N_VL1NormLocal_MPIManyVector(x);
1022 if (MANYVECTOR_COMM(x) != MPI_COMM_NULL)
1023 MPI_Allreduce(&lsum, &gsum, 1, MPI_SUNREALTYPE, MPI_SUM, MANYVECTOR_COMM(x));
1024 return(gsum);
1025 }
1026 #endif
1027
1028
1029 /* Performs N_VCompare on all subvectors; this routine does not check that x and z are
1030 ManyVectors, if they have the same number of subvectors, or if these subvectors are
1031 compatible. */
MVAPPEND(N_VCompare)1032 void MVAPPEND(N_VCompare)(realtype c, N_Vector x, N_Vector z)
1033 {
1034 sunindextype i;
1035 for (i=0; i<MANYVECTOR_NUM_SUBVECS(x); i++)
1036 N_VCompare(c, MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(z,i));
1037 return;
1038 }
1039
1040
1041 /* Performs the MPI task-local InvTest for a ManyVector by calling N_VInvTestLocal
1042 on all subvectors and combining the results appropriately. This routine does
1043 not check that x and z are ManyVectors, if they have the same number of
1044 subvectors, or if these subvectors are compatible.
1045
1046 If any subvector does not implement the N_VInvTestLocal routine (NULL
1047 function pointer), then this routine will call N_VInvTest instead. */
MVAPPEND(N_VInvTestLocal)1048 booleantype MVAPPEND(N_VInvTestLocal)(N_Vector x, N_Vector z)
1049 {
1050 sunindextype i;
1051 booleantype val, subval;
1052
1053 /* initialize output*/
1054 val = SUNTRUE;
1055
1056 for (i=0; i<MANYVECTOR_NUM_SUBVECS(x); i++) {
1057
1058 /* check for nvinvtestlocal in subvector */
1059 if (MANYVECTOR_SUBVEC(x,i)->ops->nvinvtestlocal) {
1060
1061 subval = N_VInvTestLocal(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(z,i));
1062 val = (val && subval);
1063
1064 /* otherwise, call nvinvtest and accumulate to overall val */
1065 } else {
1066
1067 subval = N_VInvTest(MANYVECTOR_SUBVEC(x,i), MANYVECTOR_SUBVEC(z,i));
1068 val = (val && subval);
1069
1070 }
1071 }
1072
1073 return(val);
1074 }
1075
1076
1077 #if SUNDIALS_MPI_ENABLED
1078 /* Performs the InvTest for a ManyVector by calling N_VInvTestLocal and
1079 combining the results. This routine does not check that x and z
1080 are ManyVectors, if they have the same number of subvectors, or if these
1081 subvectors are compatible. */
N_VInvTest_MPIManyVector(N_Vector x,N_Vector z)1082 booleantype N_VInvTest_MPIManyVector(N_Vector x, N_Vector z)
1083 {
1084 realtype val, gval;
1085 val = gval = (N_VInvTestLocal_MPIManyVector(x, z)) ? ONE : ZERO;
1086 if (MANYVECTOR_COMM(x) != MPI_COMM_NULL)
1087 MPI_Allreduce(&val, &gval, 1, MPI_SUNREALTYPE, MPI_MIN, MANYVECTOR_COMM(x));
1088 return (gval != ZERO);
1089 }
1090 #endif
1091
1092
1093 /* Performs the MPI task-local ConstrMask for a ManyVector by calling N_VConstrMaskLocal
1094 on all subvectors and combining the results appropriately. This routine does not
1095 check that c, x and m are ManyVectors, if they have the same number of subvectors,
1096 or if these subvectors are compatible.
1097
1098 If any subvector does not implement the N_VConstrMaskLocal routine (NULL
1099 function pointer), then this routine will call N_VConstrMask instead. */
MVAPPEND(N_VConstrMaskLocal)1100 booleantype MVAPPEND(N_VConstrMaskLocal)(N_Vector c, N_Vector x, N_Vector m)
1101 {
1102 sunindextype i;
1103 booleantype val, subval;
1104
1105 /* initialize output*/
1106 val = SUNTRUE;
1107
1108 for (i=0; i<MANYVECTOR_NUM_SUBVECS(x); i++) {
1109
1110 /* check for nvconstrmasklocal in subvector */
1111 if (MANYVECTOR_SUBVEC(x,i)->ops->nvconstrmasklocal) {
1112
1113 subval = N_VConstrMaskLocal(MANYVECTOR_SUBVEC(c,i), MANYVECTOR_SUBVEC(x,i),
1114 MANYVECTOR_SUBVEC(m,i));
1115 val = (val && subval);
1116
1117 /* otherwise, call nvconstrmask and accumulate to overall val */
1118 } else {
1119
1120 subval = N_VConstrMask(MANYVECTOR_SUBVEC(c,i), MANYVECTOR_SUBVEC(x,i),
1121 MANYVECTOR_SUBVEC(m,i));
1122 val = (val && subval);
1123
1124 }
1125 }
1126
1127 return(val);
1128 }
1129
1130
1131 #if SUNDIALS_MPI_ENABLED
1132 /* Performs the ConstrMask for a ManyVector by calling N_VConstrMaskLocal and
1133 combining the results. This routine does not check that c, x and m
1134 are ManyVectors, if they have the same number of subvectors, or if these
1135 subvectors are compatible. */
N_VConstrMask_MPIManyVector(N_Vector c,N_Vector x,N_Vector m)1136 booleantype N_VConstrMask_MPIManyVector(N_Vector c, N_Vector x, N_Vector m)
1137 {
1138 realtype val, gval;
1139 val = gval = (N_VConstrMaskLocal_MPIManyVector(c, x, m)) ? ONE : ZERO;
1140 if (MANYVECTOR_COMM(x) != MPI_COMM_NULL)
1141 MPI_Allreduce(&val, &gval, 1, MPI_SUNREALTYPE, MPI_MIN, MANYVECTOR_COMM(x));
1142 return (gval != ZERO);
1143 }
1144 #endif
1145
1146
1147 /* Performs the MPI task-local MinQuotient for a ManyVector by calling N_VMinQuotientLocal
1148 on all subvectors and combining the results appropriately. This routine does not check
1149 that num and denom are ManyVectors, if they have the same number of subvectors, or if
1150 these subvectors are compatible.
1151
1152 If any subvector does not implement the N_VMinQuotientLocal routine (NULL
1153 function pointer), then this routine will call N_VMinQuotient instead. */
MVAPPEND(N_VMinQuotientLocal)1154 realtype MVAPPEND(N_VMinQuotientLocal)(N_Vector num, N_Vector denom)
1155 {
1156 sunindextype i;
1157 realtype min, lmin;
1158
1159 /* initialize output*/
1160 min = BIG_REAL;
1161
1162 for (i=0; i<MANYVECTOR_NUM_SUBVECS(num); i++) {
1163
1164 /* check for nvminquotientlocal in subvector */
1165 if (MANYVECTOR_SUBVEC(num,i)->ops->nvminquotientlocal) {
1166
1167 lmin = N_VMinQuotientLocal(MANYVECTOR_SUBVEC(num,i),
1168 MANYVECTOR_SUBVEC(denom,i));
1169 min = (min < lmin) ? min : lmin;
1170
1171 /* otherwise, call nvmin and accumulate to overall min */
1172 } else {
1173
1174 lmin = N_VMinQuotient(MANYVECTOR_SUBVEC(num,i),
1175 MANYVECTOR_SUBVEC(denom,i));
1176 min = (min < lmin) ? min : lmin;
1177
1178 }
1179 }
1180
1181 return(min);
1182 }
1183
1184
1185 #if SUNDIALS_MPI_ENABLED
1186 /* Performs the MinQuotient for a ManyVector by calling N_VMinQuotientLocal
1187 and combining the results. This routine does not check that num and
1188 denom are ManyVectors, if they have the same number of subvectors, or if
1189 these subvectors are compatible. */
N_VMinQuotient_MPIManyVector(N_Vector num,N_Vector denom)1190 realtype N_VMinQuotient_MPIManyVector(N_Vector num, N_Vector denom)
1191 {
1192 realtype lmin, gmin;
1193 lmin = gmin = N_VMinQuotientLocal_MPIManyVector(num, denom);
1194 if (MANYVECTOR_COMM(num) != MPI_COMM_NULL)
1195 MPI_Allreduce(&lmin, &gmin, 1, MPI_SUNREALTYPE, MPI_MIN, MANYVECTOR_COMM(num));
1196 return(gmin);
1197 }
1198 #endif
1199
1200
1201
1202 /* -----------------------------------------------------------------
1203 Fused vector operations
1204 ----------------------------------------------------------------- */
1205
1206 /* Performs the linear combination z = sum_j c[j]*X[j] by calling
1207 N_VLinearCombination on all subvectors; this routine does not check that z
1208 or the components of X are ManyVectors, if they have the same number of
1209 subvectors, or if these subvectors are compatible.
1210
1211 NOTE: implementation of this routine is more challenging, due to the
1212 array-of-arrays of N_Vectors that comprise X. This routine will be
1213 passed an array of ManyVectors, so to call the subvector-specific routines
1214 we must unravel the subvectors while retaining an array of outer vectors. */
MVAPPEND(N_VLinearCombination)1215 int MVAPPEND(N_VLinearCombination)(int nvec, realtype* c, N_Vector* X, N_Vector z)
1216 {
1217 sunindextype i, j;
1218 int retval;
1219 N_Vector *Xsub;
1220
1221 /* create array of nvec N_Vector pointers for reuse within loop */
1222 Xsub = NULL;
1223 Xsub = (N_Vector *) malloc( nvec * sizeof(N_Vector) );
1224 if (Xsub == NULL) return(1);
1225
1226 /* perform operation by calling N_VLinearCombination for each subvector */
1227 for (i=0; i<MANYVECTOR_NUM_SUBVECS(z); i++) {
1228
1229 /* for each subvector, create the array of subvectors of X */
1230 for (j=0; j<nvec; j++) Xsub[j] = MANYVECTOR_SUBVEC(X[j],i);
1231
1232 /* now call N_VLinearCombination for this array of subvectors */
1233 retval = N_VLinearCombination(nvec, c, Xsub, MANYVECTOR_SUBVEC(z,i));
1234
1235 /* fail gracefully */
1236 if (retval) {
1237 free(Xsub);
1238 return(retval);
1239 }
1240
1241 }
1242
1243 /* clean up and return */
1244 free(Xsub);
1245 return(0);
1246 }
1247
1248
1249 /* Performs the ScaleAddMulti operation by calling N_VScaleAddMulti on all
1250 subvectors; this routine does not check that x, or the components of X and Z are
1251 ManyVectors, if they have the same number of subvectors, or if these subvectors
1252 are compatible.
1253
1254 NOTE: this routine is more challenging, due to the array-of-arrays of
1255 N_Vectors that comprise Y and Z. This routine will be passed an array of
1256 ManyVectors, so to call the subvector-specific routines we must unravel
1257 the subvectors while retaining an array of outer vectors. */
MVAPPEND(N_VScaleAddMulti)1258 int MVAPPEND(N_VScaleAddMulti)(int nvec, realtype* a, N_Vector x, N_Vector* Y, N_Vector* Z)
1259 {
1260 sunindextype i, j;
1261 int retval;
1262 N_Vector *Ysub, *Zsub;
1263
1264 /* create arrays of nvec N_Vector pointers for reuse within loop */
1265 Ysub = Zsub = NULL;
1266 Ysub = (N_Vector *) malloc( nvec * sizeof(N_Vector) );
1267 Zsub = (N_Vector *) malloc( nvec * sizeof(N_Vector) );
1268 if ( (Ysub == NULL) || (Zsub == NULL) ) return(1);
1269
1270 /* perform operation by calling N_VScaleAddMulti for each subvector */
1271 for (i=0; i<MANYVECTOR_NUM_SUBVECS(x); i++) {
1272
1273 /* for each subvector, create the array of subvectors of Y and Z */
1274 for (j=0; j<nvec; j++) {
1275 Ysub[j] = MANYVECTOR_SUBVEC(Y[j],i);
1276 Zsub[j] = MANYVECTOR_SUBVEC(Z[j],i);
1277 }
1278
1279 /* now call N_VScaleAddMulti for this array of subvectors */
1280 retval = N_VScaleAddMulti(nvec, a, MANYVECTOR_SUBVEC(x,i), Ysub, Zsub);
1281
1282 /* fail gracefully */
1283 if (retval) {
1284 free(Ysub);
1285 free(Zsub);
1286 return(retval);
1287 }
1288
1289 }
1290
1291 /* clean up and return */
1292 free(Ysub);
1293 free(Zsub);
1294 return(0);
1295 }
1296
1297
1298 /* Performs the DotProdMulti operation by calling N_VDotProdLocal and combining results.
1299 This routine does not check that x, or the components of Y, are ManyVectors, if
1300 they have the same number of subvectors, or if these subvectors are compatible.
1301
1302 NOTE: if all subvectors implement the N_VDotProdLocal routine, then this routine
1303 will require only a single array-valued reduction operation (in contrast to calling
1304 N_VDotProdMulti on all subvectors, where we would require num_subvectors separate
1305 reductions). */
MVAPPEND(N_VDotProdMulti)1306 int MVAPPEND(N_VDotProdMulti)(int nvec, N_Vector x, N_Vector* Y, realtype* dotprods)
1307 {
1308 sunindextype i;
1309
1310 /* call N_VDotProdLocal for each <x,Y[i]> pair */
1311 for (i=0; i<nvec; i++) dotprods[i] = N_VDotProdLocal(x,Y[i]);
1312
1313 #if SUNDIALS_MPI_ENABLED
1314 /* accumulate totals and return */
1315 if (MANYVECTOR_COMM(x) != MPI_COMM_NULL)
1316 return(MPI_Allreduce(MPI_IN_PLACE, dotprods, nvec, MPI_SUNREALTYPE,
1317 MPI_SUM, MANYVECTOR_COMM(x)));
1318 #endif
1319 /* return with success */
1320 return(0);
1321 }
1322
1323
1324 /* -----------------------------------------------------------------
1325 Vector array operations
1326 ----------------------------------------------------------------- */
1327
1328 /* Performs the LinearSumVectorArray operation by calling N_VLinearSumVectorArray
1329 on all subvectors; this routine does not check that the components of X, Y or Z are
1330 ManyVectors, if they have the same number of subvectors, or if these subvectors
1331 are compatible.
1332
1333 NOTE: this routine is more challenging, due to the array-of-arrays of
1334 N_Vectors that comprise X, Y and Z. This routine will be passed arrays of
1335 ManyVectors, so to call the subvector-specific routines we must unravel
1336 the subvectors while retaining arrays of outer vectors. */
MVAPPEND(N_VLinearSumVectorArray)1337 int MVAPPEND(N_VLinearSumVectorArray)(int nvec, realtype a,
1338 N_Vector *X, realtype b,
1339 N_Vector *Y, N_Vector *Z)
1340 {
1341 sunindextype i, j;
1342 int retval;
1343 N_Vector *Xsub, *Ysub, *Zsub;
1344
1345 /* immediately return if nvec <= 0 */
1346 if (nvec <= 0) return(0);
1347
1348 /* create arrays of nvec N_Vector pointers for reuse within loop */
1349 Xsub = Ysub = Zsub = NULL;
1350 Xsub = (N_Vector *) malloc( nvec * sizeof(N_Vector) );
1351 Ysub = (N_Vector *) malloc( nvec * sizeof(N_Vector) );
1352 Zsub = (N_Vector *) malloc( nvec * sizeof(N_Vector) );
1353 if ( (Xsub == NULL) || (Ysub == NULL) || (Zsub == NULL) ) return(1);
1354
1355 /* perform operation by calling N_VLinearSumVectorArray for each subvector */
1356 for (i=0; i<MANYVECTOR_NUM_SUBVECS(X[0]); i++) {
1357
1358 /* for each subvector, create the array of subvectors of X, Y and Z */
1359 for (j=0; j<nvec; j++) {
1360 Xsub[j] = MANYVECTOR_SUBVEC(X[j],i);
1361 Ysub[j] = MANYVECTOR_SUBVEC(Y[j],i);
1362 Zsub[j] = MANYVECTOR_SUBVEC(Z[j],i);
1363 }
1364
1365 /* now call N_VLinearSumVectorArray for this array of subvectors */
1366 retval = N_VLinearSumVectorArray(nvec, a, Xsub, b, Ysub, Zsub);
1367
1368 /* fail gracefully */
1369 if (retval) {
1370 free(Xsub);
1371 free(Ysub);
1372 free(Zsub);
1373 return(retval);
1374 }
1375
1376 }
1377
1378 /* clean up and return */
1379 free(Xsub);
1380 free(Ysub);
1381 free(Zsub);
1382 return(0);
1383 }
1384
1385
1386 /* Performs the ScaleVectorArray operation by calling N_VScaleVectorArray
1387 on all subvectors; this routine does not check that the components of X or Z are
1388 ManyVectors, if they have the same number of subvectors, or if these subvectors
1389 are compatible.
1390
1391 NOTE: this routine is more challenging, due to the array-of-arrays of
1392 N_Vectors that comprise X and Z. This routine will be passed arrays of
1393 ManyVectors, so to call the subvector-specific routines we must unravel
1394 the subvectors while retaining arrays of outer vectors. */
MVAPPEND(N_VScaleVectorArray)1395 int MVAPPEND(N_VScaleVectorArray)(int nvec, realtype* c, N_Vector* X, N_Vector* Z)
1396 {
1397 sunindextype i, j;
1398 int retval;
1399 N_Vector *Xsub, *Zsub;
1400
1401 /* immediately return if nvec <= 0 */
1402 if (nvec <= 0) return(0);
1403
1404 /* create arrays of nvec N_Vector pointers for reuse within loop */
1405 Xsub = Zsub = NULL;
1406 Xsub = (N_Vector *) malloc( nvec * sizeof(N_Vector) );
1407 Zsub = (N_Vector *) malloc( nvec * sizeof(N_Vector) );
1408 if ( (Xsub == NULL) || (Zsub == NULL) ) return(1);
1409
1410 /* perform operation by calling N_VScaleVectorArray for each subvector */
1411 for (i=0; i<MANYVECTOR_NUM_SUBVECS(X[0]); i++) {
1412
1413 /* for each subvector, create the array of subvectors of X, Y and Z */
1414 for (j=0; j<nvec; j++) {
1415 Xsub[j] = MANYVECTOR_SUBVEC(X[j],i);
1416 Zsub[j] = MANYVECTOR_SUBVEC(Z[j],i);
1417 }
1418
1419 /* now call N_VScaleVectorArray for this array of subvectors */
1420 retval = N_VScaleVectorArray(nvec, c, Xsub, Zsub);
1421
1422 /* fail gracefully */
1423 if (retval) {
1424 free(Xsub);
1425 free(Zsub);
1426 return(retval);
1427 }
1428
1429 }
1430
1431 /* clean up and return */
1432 free(Xsub);
1433 free(Zsub);
1434 return(0);
1435 }
1436
1437
1438 /* Performs the ConstVectorArray operation by calling N_VConstVectorArray
1439 on all subvectors.
1440
1441 NOTE: this routine is more challenging, due to the array-of-arrays of
1442 N_Vectors that comprise Z. This routine will be passed an array of
1443 ManyVectors, so to call the subvector-specific routines we must unravel
1444 the subvectors while retaining an array of outer vectors. */
MVAPPEND(N_VConstVectorArray)1445 int MVAPPEND(N_VConstVectorArray)(int nvec, realtype c, N_Vector* Z)
1446 {
1447 sunindextype i, j;
1448 int retval;
1449 N_Vector *Zsub;
1450
1451 /* immediately return if nvec <= 0 */
1452 if (nvec <= 0) return(0);
1453
1454 /* create array of N_Vector pointers for reuse within loop */
1455 Zsub = NULL;
1456 Zsub = (N_Vector *) malloc( nvec * sizeof(N_Vector) );
1457 if (Zsub == NULL) return(1);
1458
1459 /* perform operation by calling N_VConstVectorArray for each subvector */
1460 for (i=0; i<MANYVECTOR_NUM_SUBVECS(Z[0]); i++) {
1461
1462 /* for each subvector, create the array of subvectors of X, Y and Z */
1463 for (j=0; j<nvec; j++)
1464 Zsub[j] = MANYVECTOR_SUBVEC(Z[j],i);
1465
1466 /* now call N_VConstVectorArray for this array of subvectors */
1467 retval = N_VConstVectorArray(nvec, c, Zsub);
1468
1469 /* fail gracefully */
1470 if (retval) {
1471 free(Zsub);
1472 return(retval);
1473 }
1474
1475 }
1476
1477 /* clean up and return */
1478 free(Zsub);
1479 return(0);
1480 }
1481
1482
1483 /* Performs the WrmsNormVectorArray operation by calling N_VWSqrSumLocal and combining
1484 results. This routine does not check that the components of X or W are ManyVectors, if
1485 they have the same number of subvectors, or if these subvectors are compatible.
1486
1487 NOTE: if all subvectors implement the N_VWSqrSumLocal routine, then this routine
1488 will require only a single array-valued reduction operation (in contrast to calling
1489 N_VWrmsNormVectorArray on all subvectors, where we would require num_subvectors
1490 separate reductions). */
MVAPPEND(N_VWrmsNormVectorArray)1491 int MVAPPEND(N_VWrmsNormVectorArray)(int nvec, N_Vector* X, N_Vector* W, realtype* nrm)
1492 {
1493 sunindextype i;
1494 int retval;
1495
1496 /* immediately return if nvec <= 0 */
1497 if (nvec <= 0) return(0);
1498
1499 /* call N_VWSqrSumLocal for each (X[i],W[i]) pair */
1500 for (i=0; i<nvec; i++) nrm[i] = N_VWSqrSumLocal(X[i], W[i]);
1501
1502 /* accumulate totals */
1503 retval = 0;
1504 #if SUNDIALS_MPI_ENABLED
1505 if (MANYVECTOR_COMM(X[0]) != MPI_COMM_NULL)
1506 retval = (MPI_Allreduce(MPI_IN_PLACE, nrm, nvec, MPI_SUNREALTYPE, MPI_SUM,
1507 MANYVECTOR_COMM(X[0])) == MPI_SUCCESS) ? 0 : -1;
1508 #endif
1509
1510 /* finish off WRMS norms and return */
1511 for (i=0; i<nvec; i++)
1512 nrm[i] = SUNRsqrt(nrm[i]/(MANYVECTOR_GLOBLENGTH(X[i])));
1513
1514 return(retval);
1515 }
1516
1517
1518 /* Performs the WrmsNormMaskVectorArray operation by calling N_VWSqrSumMaskLocal and
1519 combining results. This routine does not check that id or the components of X and
1520 W are ManyVectors, if they have the same number of subvectors, or if these
1521 subvectors are compatible.
1522
1523 NOTE: if all subvectors implement the N_VWSqrSumMaskLocal routine, then this
1524 routine will require only a single array-valued reduction operation (in contrast
1525 to calling N_VWrmsNormMaskVectorArray on all subvectors, where we would require
1526 num_subvectors separate reductions). */
MVAPPEND(N_VWrmsNormMaskVectorArray)1527 int MVAPPEND(N_VWrmsNormMaskVectorArray)(int nvec, N_Vector* X, N_Vector* W,
1528 N_Vector id, realtype* nrm)
1529 {
1530 sunindextype i;
1531 int retval;
1532
1533 /* immediately return if nvec <= 0 */
1534 if (nvec <= 0) return(0);
1535
1536 /* call N_VWSqrSumMaskLocal for each (X[i],W[i]) pair */
1537 for (i=0; i<nvec; i++) nrm[i] = N_VWSqrSumMaskLocal(X[i], W[i], id);
1538
1539 /* accumulate totals */
1540 retval = 0;
1541 #if SUNDIALS_MPI_ENABLED
1542 if (MANYVECTOR_COMM(X[0]) != MPI_COMM_NULL)
1543 retval = (MPI_Allreduce(MPI_IN_PLACE, nrm, nvec, MPI_SUNREALTYPE, MPI_SUM,
1544 MANYVECTOR_COMM(X[0])) == MPI_SUCCESS) ? 0 : -1;
1545 #endif
1546
1547 /* finish off WRMS norms and return */
1548 for (i=0; i<nvec; i++)
1549 nrm[i] = SUNRsqrt(nrm[i]/(MANYVECTOR_GLOBLENGTH(X[i])));
1550
1551 return(retval);
1552 }
1553
1554
1555 /* -----------------------------------------------------------------
1556 Enable / Disable fused and vector array operations
1557 ----------------------------------------------------------------- */
1558
MVAPPEND(N_VEnableFusedOps)1559 int MVAPPEND(N_VEnableFusedOps)(N_Vector v, booleantype tf)
1560 {
1561 /* check that vector is non-NULL */
1562 if (v == NULL) return(-1);
1563
1564 /* check that ops structure is non-NULL */
1565 if (v->ops == NULL) return(-1);
1566
1567 if (tf) {
1568 /* enable all fused vector operations */
1569 v->ops->nvlinearcombination = MVAPPEND(N_VLinearCombination);
1570 v->ops->nvscaleaddmulti = MVAPPEND(N_VScaleAddMulti);
1571 v->ops->nvdotprodmulti = MVAPPEND(N_VDotProdMulti);
1572 /* enable all vector array operations */
1573 v->ops->nvlinearsumvectorarray = MVAPPEND(N_VLinearSumVectorArray);
1574 v->ops->nvscalevectorarray = MVAPPEND(N_VScaleVectorArray);
1575 v->ops->nvconstvectorarray = MVAPPEND(N_VConstVectorArray);
1576 v->ops->nvwrmsnormvectorarray = MVAPPEND(N_VWrmsNormVectorArray);
1577 v->ops->nvwrmsnormmaskvectorarray = MVAPPEND(N_VWrmsNormMaskVectorArray);
1578 v->ops->nvscaleaddmultivectorarray = NULL;
1579 v->ops->nvlinearcombinationvectorarray = NULL;
1580 } else {
1581 /* disable all fused vector operations */
1582 v->ops->nvlinearcombination = NULL;
1583 v->ops->nvscaleaddmulti = NULL;
1584 v->ops->nvdotprodmulti = NULL;
1585 /* disable all vector array operations */
1586 v->ops->nvlinearsumvectorarray = NULL;
1587 v->ops->nvscalevectorarray = NULL;
1588 v->ops->nvconstvectorarray = NULL;
1589 v->ops->nvwrmsnormvectorarray = NULL;
1590 v->ops->nvwrmsnormmaskvectorarray = NULL;
1591 v->ops->nvscaleaddmultivectorarray = NULL;
1592 v->ops->nvlinearcombinationvectorarray = NULL;
1593 }
1594
1595 /* return success */
1596 return(0);
1597 }
1598
1599
MVAPPEND(N_VEnableLinearCombination)1600 int MVAPPEND(N_VEnableLinearCombination)(N_Vector v, booleantype tf)
1601 {
1602 /* check that vector is non-NULL */
1603 if (v == NULL) return(-1);
1604
1605 /* check that ops structure is non-NULL */
1606 if (v->ops == NULL) return(-1);
1607
1608 /* enable/disable operation */
1609 if (tf)
1610 v->ops->nvlinearcombination = MVAPPEND(N_VLinearCombination);
1611 else
1612 v->ops->nvlinearcombination = NULL;
1613
1614 /* return success */
1615 return(0);
1616 }
1617
MVAPPEND(N_VEnableScaleAddMulti)1618 int MVAPPEND(N_VEnableScaleAddMulti)(N_Vector v, booleantype tf)
1619 {
1620 /* check that vector is non-NULL */
1621 if (v == NULL) return(-1);
1622
1623 /* check that ops structure is non-NULL */
1624 if (v->ops == NULL) return(-1);
1625
1626 /* enable/disable operation */
1627 if (tf)
1628 v->ops->nvscaleaddmulti = MVAPPEND(N_VScaleAddMulti);
1629 else
1630 v->ops->nvscaleaddmulti = NULL;
1631
1632 /* return success */
1633 return(0);
1634 }
1635
MVAPPEND(N_VEnableDotProdMulti)1636 int MVAPPEND(N_VEnableDotProdMulti)(N_Vector v, booleantype tf)
1637 {
1638 /* check that vector is non-NULL */
1639 if (v == NULL) return(-1);
1640
1641 /* check that ops structure is non-NULL */
1642 if (v->ops == NULL) return(-1);
1643
1644 /* enable/disable operation */
1645 if (tf)
1646 v->ops->nvdotprodmulti = MVAPPEND(N_VDotProdMulti);
1647 else
1648 v->ops->nvdotprodmulti = NULL;
1649
1650 /* return success */
1651 return(0);
1652 }
1653
MVAPPEND(N_VEnableLinearSumVectorArray)1654 int MVAPPEND(N_VEnableLinearSumVectorArray)(N_Vector v, booleantype tf)
1655 {
1656 /* check that vector is non-NULL */
1657 if (v == NULL) return(-1);
1658
1659 /* check that ops structure is non-NULL */
1660 if (v->ops == NULL) return(-1);
1661
1662 /* enable/disable operation */
1663 if (tf)
1664 v->ops->nvlinearsumvectorarray = MVAPPEND(N_VLinearSumVectorArray);
1665 else
1666 v->ops->nvlinearsumvectorarray = NULL;
1667
1668 /* return success */
1669 return(0);
1670 }
1671
MVAPPEND(N_VEnableScaleVectorArray)1672 int MVAPPEND(N_VEnableScaleVectorArray)(N_Vector v, booleantype tf)
1673 {
1674 /* check that vector is non-NULL */
1675 if (v == NULL) return(-1);
1676
1677 /* check that ops structure is non-NULL */
1678 if (v->ops == NULL) return(-1);
1679
1680 /* enable/disable operation */
1681 if (tf)
1682 v->ops->nvscalevectorarray = MVAPPEND(N_VScaleVectorArray);
1683 else
1684 v->ops->nvscalevectorarray = NULL;
1685
1686 /* return success */
1687 return(0);
1688 }
1689
MVAPPEND(N_VEnableConstVectorArray)1690 int MVAPPEND(N_VEnableConstVectorArray)(N_Vector v, booleantype tf)
1691 {
1692 /* check that vector is non-NULL */
1693 if (v == NULL) return(-1);
1694
1695 /* check that ops structure is non-NULL */
1696 if (v->ops == NULL) return(-1);
1697
1698 /* enable/disable operation */
1699 if (tf)
1700 v->ops->nvconstvectorarray = MVAPPEND(N_VConstVectorArray);
1701 else
1702 v->ops->nvconstvectorarray = NULL;
1703
1704 /* return success */
1705 return(0);
1706 }
1707
MVAPPEND(N_VEnableWrmsNormVectorArray)1708 int MVAPPEND(N_VEnableWrmsNormVectorArray)(N_Vector v, booleantype tf)
1709 {
1710 /* check that vector is non-NULL */
1711 if (v == NULL) return(-1);
1712
1713 /* check that ops structure is non-NULL */
1714 if (v->ops == NULL) return(-1);
1715
1716 /* enable/disable operation */
1717 if (tf)
1718 v->ops->nvwrmsnormvectorarray = MVAPPEND(N_VWrmsNormVectorArray);
1719 else
1720 v->ops->nvwrmsnormvectorarray = NULL;
1721
1722 /* return success */
1723 return(0);
1724 }
1725
MVAPPEND(N_VEnableWrmsNormMaskVectorArray)1726 int MVAPPEND(N_VEnableWrmsNormMaskVectorArray)(N_Vector v, booleantype tf)
1727 {
1728 /* check that vector is non-NULL */
1729 if (v == NULL) return(-1);
1730
1731 /* check that ops structure is non-NULL */
1732 if (v->ops == NULL) return(-1);
1733
1734 /* enable/disable operation */
1735 if (tf)
1736 v->ops->nvwrmsnormmaskvectorarray = MVAPPEND(N_VWrmsNormMaskVectorArray);
1737 else
1738 v->ops->nvwrmsnormmaskvectorarray = NULL;
1739
1740 /* return success */
1741 return(0);
1742 }
1743
1744
1745 /* -----------------------------------------------------------------
1746 Implementation of utility routines
1747 -----------------------------------------------------------------*/
1748
1749 /* This function performs a generic clone operation on an input N_Vector.
1750 Based on the 'cloneempty' flag it will either call "nvclone" or
1751 "nvcloneempty" when creating subvectors in the cloned vector. */
ManyVectorClone(N_Vector w,booleantype cloneempty)1752 static N_Vector ManyVectorClone(N_Vector w, booleantype cloneempty)
1753 {
1754 N_Vector v;
1755 MVAPPEND(N_VectorContent) content;
1756 sunindextype i;
1757
1758 if (w == NULL) return(NULL);
1759
1760 /* Create vector */
1761 v = NULL;
1762 v = N_VNewEmpty();
1763 if (v == NULL) return(NULL);
1764
1765 /* Attach operations */
1766 if (N_VCopyOps(w, v)) { N_VDestroy(v); return(NULL); }
1767
1768 /* Create content */
1769 content = NULL;
1770 content = (MVAPPEND(N_VectorContent)) malloc(sizeof *content);
1771 if (content == NULL) { N_VDestroy(v); return(NULL); }
1772
1773 /* Attach content and ops to new vector, and return */
1774 v->content = content;
1775
1776 /* Attach content components */
1777
1778 /* Set scalar components */
1779 #if SUNDIALS_MPI_ENABLED
1780 content->comm = MPI_COMM_NULL;
1781 #endif
1782 content->num_subvectors = MANYVECTOR_NUM_SUBVECS(w);
1783 content->global_length = MANYVECTOR_GLOBLENGTH(w);
1784 content->own_data = SUNTRUE;
1785
1786 /* Allocate the subvector array */
1787 content->subvec_array = NULL;
1788 content->subvec_array = (N_Vector *) malloc(content->num_subvectors * sizeof(N_Vector));
1789 if (content->subvec_array == NULL) { N_VDestroy(v); return(NULL); }
1790
1791 /* Initialize the subvector array to NULL */
1792 for (i=0; i<content->num_subvectors; i++)
1793 content->subvec_array[i] = NULL;
1794
1795 /* Duplicate the input communicator (if applicable) */
1796 #if SUNDIALS_MPI_ENABLED
1797 if (MANYVECTOR_COMM(w) != MPI_COMM_NULL) {
1798 if (MPI_Comm_dup(MANYVECTOR_COMM(w), &(content->comm)) != MPI_SUCCESS)
1799 { N_VDestroy(v); return(NULL); }
1800 }
1801 #endif
1802
1803 /* Clone vectors into the subvector array */
1804 for (i=0; i<content->num_subvectors; i++) {
1805 if (cloneempty) {
1806 content->subvec_array[i] = N_VCloneEmpty(MANYVECTOR_SUBVEC(w,i));
1807 } else {
1808 content->subvec_array[i] = N_VClone(MANYVECTOR_SUBVEC(w,i));
1809 }
1810 if (content->subvec_array[i] == NULL) {
1811 N_VDestroy(v);
1812 return(NULL);
1813 }
1814 }
1815
1816 return(v);
1817 }
1818
1819
1820 #if SUNDIALS_MPI_ENABLED
1821 /* This function returns the rank of this task in the MPI communicator
1822 associated with the input N_Vector. If the input N_Vector is MPI-unaware, it
1823 returns 0. If an error occurs in the call to MPI_Comm_Rank, it returns -1. */
SubvectorMPIRank(N_Vector x)1824 static int SubvectorMPIRank(N_Vector x)
1825 {
1826 void* tmpcomm;
1827 MPI_Comm *comm;
1828 int rank, retval;
1829 tmpcomm = N_VGetCommunicator(x);
1830 if (tmpcomm == NULL) return(0);
1831 comm = (MPI_Comm *) tmpcomm;
1832 if ((*comm) == MPI_COMM_NULL) return(0);
1833 retval = MPI_Comm_rank(*comm, &rank);
1834 if (retval != MPI_SUCCESS) return(-1);
1835 return(rank);
1836 }
1837 #endif
1838