Actual source code: gcreate.c
1: #include <petsc/private/matimpl.h>
3: #include <../src/mat/impls/aij/seq/aij.h>
4: #include <../src/mat/impls/aij/mpi/mpiaij.h>
6: PetscErrorCode MatSetBlockSizes_Default(Mat mat, PetscInt rbs, PetscInt cbs)
7: {
8: PetscFunctionBegin;
9: if (!mat->preallocated) PetscFunctionReturn(PETSC_SUCCESS);
10: PetscCheck(mat->rmap->bs <= 0 || mat->rmap->bs == rbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot change row block size %" PetscInt_FMT " to %" PetscInt_FMT, mat->rmap->bs, rbs);
11: PetscCheck(mat->cmap->bs <= 0 || mat->cmap->bs == cbs, PetscObjectComm((PetscObject)mat), PETSC_ERR_SUP, "Cannot change column block size %" PetscInt_FMT " to %" PetscInt_FMT, mat->cmap->bs, cbs);
12: PetscFunctionReturn(PETSC_SUCCESS);
13: }
15: PetscErrorCode MatShift_Basic(Mat Y, PetscScalar a)
16: {
17: PetscInt i, start, end, oldValA = 0, oldValB = 0;
18: PetscScalar alpha = a;
19: PetscBool prevoption;
20: PetscBool isSeqAIJDerived, isMPIAIJDerived; // all classes sharing SEQAIJHEADER or MPIAIJHEADER
21: Mat A = NULL, B = NULL;
23: PetscFunctionBegin;
24: PetscCall(MatGetOption(Y, MAT_NO_OFF_PROC_ENTRIES, &prevoption));
25: PetscCall(MatSetOption(Y, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE));
26: PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)Y, &isSeqAIJDerived, MATSEQAIJ, MATSEQBAIJ, MATSEQSBAIJ, ""));
27: PetscCall(PetscObjectBaseTypeCompareAny((PetscObject)Y, &isMPIAIJDerived, MATMPIAIJ, MATMPIBAIJ, MATMPISBAIJ, ""));
29: if (isSeqAIJDerived) A = Y;
30: else if (isMPIAIJDerived) {
31: Mat_MPIAIJ *mpiaij = (Mat_MPIAIJ *)Y->data;
32: A = mpiaij->A;
33: B = mpiaij->B;
34: }
36: if (A) {
37: oldValA = ((Mat_SeqAIJ *)A->data)->nonew;
38: ((Mat_SeqAIJ *)A->data)->nonew = 0; // so that new nonzero locations are allowed
39: }
40: if (B) {
41: oldValB = ((Mat_SeqAIJ *)B->data)->nonew;
42: ((Mat_SeqAIJ *)B->data)->nonew = 0;
43: }
45: PetscCall(MatGetOwnershipRange(Y, &start, &end));
46: for (i = start; i < end; i++) {
47: if (i < Y->cmap->N) PetscCall(MatSetValues(Y, 1, &i, 1, &i, &alpha, ADD_VALUES));
48: }
49: PetscCall(MatAssemblyBegin(Y, MAT_FINAL_ASSEMBLY));
50: PetscCall(MatAssemblyEnd(Y, MAT_FINAL_ASSEMBLY));
51: PetscCall(MatSetOption(Y, MAT_NO_OFF_PROC_ENTRIES, prevoption));
52: if (A) ((Mat_SeqAIJ *)A->data)->nonew = oldValA;
53: if (B) ((Mat_SeqAIJ *)B->data)->nonew = oldValB;
54: PetscFunctionReturn(PETSC_SUCCESS);
55: }
57: /*@
58: MatCreate - Creates a matrix where the type is determined
59: from either a call to `MatSetType()` or from the options database
60: with a call to `MatSetFromOptions()`.
62: Collective
64: Input Parameter:
65: . comm - MPI communicator
67: Output Parameter:
68: . A - the matrix
70: Options Database Keys:
71: + -mat_type seqaij - `MATSEQAIJ` type, uses `MatCreateSeqAIJ()`
72: . -mat_type mpiaij - `MATMPIAIJ` type, uses `MatCreateAIJ()`
73: . -mat_type seqdense - `MATSEQDENSE`, uses `MatCreateSeqDense()`
74: . -mat_type mpidense - `MATMPIDENSE` type, uses `MatCreateDense()`
75: . -mat_type seqbaij - `MATSEQBAIJ` type, uses `MatCreateSeqBAIJ()`
76: - -mat_type mpibaij - `MATMPIBAIJ` type, uses `MatCreateBAIJ()`
78: See the manpages for particular formats (e.g., `MATSEQAIJ`)
79: for additional format-specific options.
81: Level: beginner
83: Notes:
84: The default matrix type is `MATAIJ`, using the routines `MatCreateSeqAIJ()` or
85: `MatCreateAIJ()` if you do not set a type in the options database. If you never call
86: `MatSetType()` or `MatSetFromOptions()` it will generate an error when you try to use the
87: matrix.
89: .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MatCreateAIJ()`,
90: `MatCreateSeqDense()`, `MatCreateDense()`,
91: `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`,
92: `MatCreateSeqSBAIJ()`, `MatCreateSBAIJ()`,
93: `MatConvert()`
94: @*/
95: PetscErrorCode MatCreate(MPI_Comm comm, Mat *A)
96: {
97: Mat B;
99: PetscFunctionBegin;
100: PetscAssertPointer(A, 2);
101: PetscCall(MatInitializePackage());
103: PetscCall(PetscHeaderCreate(B, MAT_CLASSID, "Mat", "Matrix", "Mat", comm, MatDestroy, MatView));
104: PetscCall(PetscLayoutCreate(comm, &B->rmap));
105: PetscCall(PetscLayoutCreate(comm, &B->cmap));
106: PetscCall(PetscStrallocpy(VECSTANDARD, &B->defaultvectype));
107: PetscCall(PetscStrallocpy(PETSCRANDER48, &B->defaultrandtype));
109: B->symmetric = PETSC_BOOL3_UNKNOWN;
110: B->hermitian = PETSC_BOOL3_UNKNOWN;
111: B->structurally_symmetric = PETSC_BOOL3_UNKNOWN;
112: B->spd = PETSC_BOOL3_UNKNOWN;
113: B->symmetry_eternal = PETSC_FALSE;
114: B->structural_symmetry_eternal = PETSC_FALSE;
116: B->congruentlayouts = PETSC_DECIDE;
117: B->preallocated = PETSC_FALSE;
118: #if PetscDefined(HAVE_DEVICE)
119: B->boundtocpu = PETSC_TRUE;
120: #endif
121: *A = B;
122: PetscFunctionReturn(PETSC_SUCCESS);
123: }
125: /*@
126: MatCreateFromOptions - Creates a matrix whose type is set from the options database
128: Collective
130: Input Parameters:
131: + comm - MPI communicator
132: . prefix - [optional] prefix for the options database
133: . bs - the blocksize (commonly 1)
134: . m - the local number of rows (or `PETSC_DECIDE`)
135: . n - the local number of columns (or `PETSC_DECIDE` or `PETSC_DETERMINE`)
136: . M - the global number of rows (or `PETSC_DETERMINE`)
137: - N - the global number of columns (or `PETSC_DETERMINE`)
139: Output Parameter:
140: . A - the matrix
142: Options Database Key:
143: . -mat_type - see `MatType`, for example `aij`, `aijcusparse`, `baij`, `sbaij`, `dense`, defaults to `aij`
145: Level: beginner
147: .seealso: [](ch_matrices), `Mat`, `MatCreateSeqAIJ()`, `MatCreateAIJ()`,
148: `MatCreateSeqDense()`, `MatCreateDense()`,
149: `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`,
150: `MatCreateSeqSBAIJ()`, `MatCreateSBAIJ()`,
151: `MatConvert()`, `MatCreate()`
152: @*/
153: PetscErrorCode MatCreateFromOptions(MPI_Comm comm, const char *prefix, PetscInt bs, PetscInt m, PetscInt n, PetscInt M, PetscInt N, Mat *A)
154: {
155: PetscFunctionBegin;
156: PetscAssertPointer(A, 8);
157: PetscCall(MatCreate(comm, A));
158: if (prefix) PetscCall(MatSetOptionsPrefix(*A, prefix));
159: PetscCall(MatSetBlockSize(*A, bs));
160: PetscCall(MatSetSizes(*A, m, n, M, N));
161: PetscCall(MatSetFromOptions(*A));
162: PetscFunctionReturn(PETSC_SUCCESS);
163: }
165: /*@
166: MatSetErrorIfFailure - Causes `Mat` to generate an immediate error, for example a zero pivot, is detected.
168: Logically Collective
170: Input Parameters:
171: + mat - matrix obtained from `MatCreate()`
172: - flg - `PETSC_TRUE` indicates you want the error generated
174: Level: advanced
176: Note:
177: If this flag is not set then the matrix operation will note the error and continue. The error may cause a later `PC` or `KSP` error
178: or result in a `KSPConvergedReason` indicating the method did not converge.
180: .seealso: [](ch_matrices), `Mat`, `PCSetErrorIfFailure()`, `KSPConvergedReason`, `SNESConvergedReason`
181: @*/
182: PetscErrorCode MatSetErrorIfFailure(Mat mat, PetscBool flg)
183: {
184: PetscFunctionBegin;
187: mat->erroriffailure = flg;
188: PetscFunctionReturn(PETSC_SUCCESS);
189: }
191: /*@
192: MatSetSizes - Sets the local and global sizes, and checks to determine compatibility
194: Collective
196: Input Parameters:
197: + A - the matrix
198: . m - number of local rows (or `PETSC_DECIDE`)
199: . n - number of local columns (or `PETSC_DECIDE`)
200: . M - number of global rows (or `PETSC_DETERMINE`)
201: - N - number of global columns (or `PETSC_DETERMINE`)
203: Level: beginner
205: Notes:
206: `m` (`n`) and `M` (`N`) cannot be both `PETSC_DECIDE`
207: If one processor calls this with `M` (`N`) of `PETSC_DECIDE` then all processors must, otherwise the program will hang.
209: If `PETSC_DECIDE` is not used for the arguments 'm' and 'n', then the
210: user must ensure that they are chosen to be compatible with the
211: vectors. To do this, one first considers the matrix-vector product
212: 'y = A x'. The `m` that is used in the above routine must match the
213: local size of 'y'. Likewise, the `n` used must match the local size of 'x'.
215: If `m` and `n` are not `PETSC_DECIDE`, then the values determine the `PetscLayout` of the matrix and the ranges returned by
216: `MatGetOwnershipRange()`, `MatGetOwnershipRanges()`, `MatGetOwnershipRangeColumn()`, and `MatGetOwnershipRangesColumn()`.
218: You cannot change the sizes once they have been set.
220: The sizes must be set before `MatSetUp()` or MatXXXSetPreallocation() is called.
222: .seealso: [](ch_matrices), `Mat`, `MatGetSize()`, `PetscSplitOwnership()`, `MatGetOwnershipRange()`, `MatGetOwnershipRanges()`,
223: `MatGetOwnershipRangeColumn()`, `MatGetOwnershipRangesColumn()`, `PetscLayout`, `VecSetSizes()`
224: @*/
225: PetscErrorCode MatSetSizes(Mat A, PetscInt m, PetscInt n, PetscInt M, PetscInt N)
226: {
227: PetscFunctionBegin;
231: PetscCheck(M <= 0 || m <= M, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Local row size %" PetscInt_FMT " cannot be larger than global row size %" PetscInt_FMT, m, M);
232: PetscCheck(N <= 0 || n <= N, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Local column size %" PetscInt_FMT " cannot be larger than global column size %" PetscInt_FMT, n, N);
233: PetscCheck((A->rmap->n < 0 || A->rmap->N < 0) || (A->rmap->n == m && (M <= 0 || A->rmap->N == M)), PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot change/reset row sizes to %" PetscInt_FMT " local %" PetscInt_FMT " global after previously setting them to %" PetscInt_FMT " local %" PetscInt_FMT " global", m, M,
234: A->rmap->n, A->rmap->N);
235: PetscCheck((A->cmap->n < 0 || A->cmap->N < 0) || (A->cmap->n == n && (N <= 0 || A->cmap->N == N)), PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot change/reset column sizes to %" PetscInt_FMT " local %" PetscInt_FMT " global after previously setting them to %" PetscInt_FMT " local %" PetscInt_FMT " global", n, N,
236: A->cmap->n, A->cmap->N);
237: A->rmap->n = m;
238: A->cmap->n = n;
239: A->rmap->N = M > -1 ? M : A->rmap->N;
240: A->cmap->N = N > -1 ? N : A->cmap->N;
241: PetscFunctionReturn(PETSC_SUCCESS);
242: }
244: /*@
245: MatSetFromOptions - Creates a matrix where the type is determined
246: from the options database.
248: Collective
250: Input Parameter:
251: . B - the matrix
253: Options Database Keys:
254: + -mat_block_size size - set the block size used to store the matrix; see `MatSetBlockSize()`
255: . -mat_type type - set the matrix type; see `MatType` and `MatSetType()`
256: . -mat_vec_type vtype - set the `VecType` used by `MatCreateVecs()`; see `MatSetVecType()`
257: . -mat_is_symmetric tol - check symmetry during `MatAssemblyEnd()` with an optional tolerance; see `MatIsSymmetric()`
258: . -mat_null_space_test (true|false) - test the attached null space during `MatAssemblyEnd()`; see `MatNullSpaceTest()`
259: . -mat_error_if_failure (true|false) - generate an error if matrix factorization fails; see `MatSetErrorIfFailure()`
260: . -mat_spd (true|false) - set the `MAT_SPD` property with `MatSetOption()`
261: . -mat_new_nonzero_location_err (true|false) - generate an error if insertion creates a new nonzero location; see `MAT_NEW_NONZERO_LOCATION_ERR` in `MatSetOption()`
262: . -mat_new_nonzero_allocation_err (true|false) - generate an error if insertion requires additional nonzero allocation; see `MAT_NEW_NONZERO_ALLOCATION_ERR` in `MatSetOption()`
263: . -mat_ignore_zero_entries (true|false) - ignore eligible zero entries during insertion; see `MAT_IGNORE_ZERO_ENTRIES` in `MatSetOption()`
264: . -mat_form_explicit_transpose (true|false) - hint to form an explicit transpose for operations such as `MatMultTranspose()`
265: - -mat_bind_below size - bind the matrix to the CPU if its number of local rows is less than size; see `MatBindToCPU()`
267: Level: beginner
269: Notes:
270: Generates a parallel MPI matrix if the communicator has more than one processor. The default
271: matrix type is `MATAIJ`, using the routines `MatCreateSeqAIJ()` and `MatCreateAIJ()` if you
272: do not select a type in the options database.
274: See the manpages for particular formats (e.g., `MATSEQAIJ`)
275: for additional format-specific options.
277: .seealso: [](ch_matrices), `Mat`, `MatType`, `MatCreateSeqAIJ()`, `MatCreateAIJ()`,
278: `MatCreateSeqDense()`, `MatCreateDense()`,
279: `MatCreateSeqBAIJ()`, `MatCreateBAIJ()`,
280: `MatCreateSeqSBAIJ()`, `MatCreateSBAIJ()`,
281: `MatConvert()`
282: @*/
283: PetscErrorCode MatSetFromOptions(Mat B)
284: {
285: const char *deft = MATAIJ;
286: char type[256];
287: PetscBool flg, set;
288: PetscInt bind_below = 0, newbs = -1;
290: PetscFunctionBegin;
293: PetscObjectOptionsBegin((PetscObject)B);
295: PetscCall(PetscOptionsInt("-mat_block_size", "Set the blocksize used to store the matrix", "MatSetBlockSize", newbs, &newbs, &flg));
296: if (flg) {
297: PetscCall(PetscLayoutSetBlockSize(B->rmap, newbs));
298: PetscCall(PetscLayoutSetBlockSize(B->cmap, newbs));
299: }
301: PetscCall(PetscOptionsFList("-mat_type", "Matrix type", "MatSetType", MatList, deft, type, sizeof(type), &flg));
302: if (flg) PetscCall(MatSetType(B, type));
303: else if (!((PetscObject)B)->type_name) PetscCall(MatSetType(B, deft));
304: PetscCall(PetscOptionsFList("-mat_vec_type", "Vec type used by MatCreateVecs()", "MatSetVecType", VecList, B->defaultvectype, type, sizeof(type), &flg));
305: if (flg) PetscCall(MatSetVecType(B, type));
307: if (newbs > 0) PetscTryTypeMethod(B, setblocksizes, newbs, newbs);
309: PetscCall(PetscOptionsName("-mat_is_symmetric", "Checks if mat is symmetric on MatAssemblyEnd()", "MatIsSymmetric", &B->checksymmetryonassembly));
310: PetscCall(PetscOptionsReal("-mat_is_symmetric", "Checks if mat is symmetric on MatAssemblyEnd()", "MatIsSymmetric", B->checksymmetrytol, &B->checksymmetrytol, NULL));
311: PetscCall(PetscOptionsBool("-mat_null_space_test", "Checks if provided null space is correct in MatAssemblyEnd()", "MatNullSpaceTest", B->checknullspaceonassembly, &B->checknullspaceonassembly, NULL));
312: PetscCall(PetscOptionsBool("-mat_error_if_failure", "Generate an error if an error occurs when factoring the matrix", "MatSetErrorIfFailure", B->erroriffailure, &B->erroriffailure, NULL));
314: PetscTryTypeMethod(B, setfromoptions, PetscOptionsObject);
316: flg = PETSC_FALSE;
317: PetscCall(PetscOptionsBool("-mat_spd", "Set whether the matrix is symmetric positive definite", "MatSetOption", flg, &flg, &set));
318: if (set) PetscCall(MatSetOption(B, MAT_SPD, flg));
320: flg = PETSC_FALSE;
321: PetscCall(PetscOptionsBool("-mat_new_nonzero_location_err", "Generate an error if new nonzeros are created in the matrix nonzero structure (useful to test preallocation)", "MatSetOption", flg, &flg, &set));
322: if (set) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_LOCATION_ERR, flg));
323: flg = PETSC_FALSE;
324: PetscCall(PetscOptionsBool("-mat_new_nonzero_allocation_err", "Generate an error if new nonzeros are allocated in the matrix nonzero structure (useful to test preallocation)", "MatSetOption", flg, &flg, &set));
325: if (set) PetscCall(MatSetOption(B, MAT_NEW_NONZERO_ALLOCATION_ERR, flg));
326: flg = PETSC_FALSE;
327: PetscCall(PetscOptionsBool("-mat_ignore_zero_entries", "For AIJ/SELL/IS matrices this will stop zero values from creating a zero location in the matrix", "MatSetOption", flg, &flg, &set));
328: if (set) PetscCall(MatSetOption(B, MAT_IGNORE_ZERO_ENTRIES, flg));
330: flg = PETSC_FALSE;
331: PetscCall(PetscOptionsBool("-mat_form_explicit_transpose", "Hint to form an explicit transpose for operations like MatMultTranspose", "MatSetOption", flg, &flg, &set));
332: if (set) PetscCall(MatSetOption(B, MAT_FORM_EXPLICIT_TRANSPOSE, flg));
334: /* Bind to CPU if below a user-specified size threshold.
335: * This perhaps belongs in the options for the GPU Mat types, but MatBindToCPU() does nothing when called on non-GPU types,
336: * and putting it here makes is more maintainable than duplicating this for all. */
337: PetscCall(PetscOptionsInt("-mat_bind_below", "Set the size threshold (in local rows) below which the Mat is bound to the CPU", "MatBindToCPU", bind_below, &bind_below, &flg));
338: if (flg && B->rmap->n < bind_below) PetscCall(MatBindToCPU(B, PETSC_TRUE));
340: /* process any options handlers added with PetscObjectAddOptionsHandler() */
341: PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)B, PetscOptionsObject));
342: PetscOptionsEnd();
343: PetscFunctionReturn(PETSC_SUCCESS);
344: }
346: /*@
347: MatXAIJSetPreallocation - set preallocation for serial and parallel `MATAIJ`, `MATBAIJ`, and `MATSBAIJ` matrices and their unassembled versions.
349: Collective
351: Input Parameters:
352: + A - matrix being preallocated
353: . bs - block size
354: . dnnz - number of nonzero column blocks per block row of diagonal part of parallel matrix
355: . onnz - number of nonzero column blocks per block row of off-diagonal part of parallel matrix
356: . dnnzu - number of nonzero column blocks per block row of upper-triangular part of diagonal part of parallel matrix
357: - onnzu - number of nonzero column blocks per block row of upper-triangular part of off-diagonal part of parallel matrix
359: Level: beginner
361: .seealso: [](ch_matrices), `Mat`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatSeqBAIJSetPreallocation()`, `MatMPIBAIJSetPreallocation()`,
362: `MatSeqSBAIJSetPreallocation()`, `MatMPISBAIJSetPreallocation()`,
363: `PetscSplitOwnership()`
364: @*/
365: PetscErrorCode MatXAIJSetPreallocation(Mat A, PetscInt bs, const PetscInt dnnz[], const PetscInt onnz[], const PetscInt dnnzu[], const PetscInt onnzu[])
366: {
367: PetscInt cbs;
368: PetscBool aij, is, hyp;
370: PetscFunctionBegin;
371: if (bs != PETSC_DECIDE) { /* don't mess with an already set block size */
372: PetscCall(MatSetBlockSize(A, bs));
373: }
374: PetscCall(PetscLayoutSetUp(A->rmap));
375: PetscCall(PetscLayoutSetUp(A->cmap));
376: PetscCall(MatGetBlockSizes(A, &bs, &cbs));
377: /* these routines assumes bs == cbs, this should be checked somehow */
378: PetscCall(MatSeqBAIJSetPreallocation(A, bs, 0, dnnz));
379: PetscCall(MatMPIBAIJSetPreallocation(A, bs, 0, dnnz, 0, onnz));
380: PetscCall(MatSeqSBAIJSetPreallocation(A, bs, 0, dnnzu));
381: PetscCall(MatMPISBAIJSetPreallocation(A, bs, 0, dnnzu, 0, onnzu));
382: /*
383: In general, we have to do extra work to preallocate for scalar (AIJ) or unassembled (IS) matrices so we check whether it will do any
384: good before going on with it.
385: */
386: PetscCall(PetscObjectHasFunction((PetscObject)A, "MatMPIAIJSetPreallocation_C", &aij));
387: PetscCall(PetscObjectHasFunction((PetscObject)A, "MatISSetPreallocation_C", &is));
388: PetscCall(PetscObjectHasFunction((PetscObject)A, "MatHYPRESetPreallocation_C", &hyp));
389: if (!aij && !is && !hyp) PetscCall(PetscObjectHasFunction((PetscObject)A, "MatSeqAIJSetPreallocation_C", &aij));
390: if (aij || is || hyp) {
391: if (bs == cbs && bs == 1) {
392: PetscCall(MatSeqAIJSetPreallocation(A, 0, dnnz));
393: PetscCall(MatMPIAIJSetPreallocation(A, 0, dnnz, 0, onnz));
394: PetscCall(MatISSetPreallocation(A, 0, dnnz, 0, onnz));
395: #if PetscDefined(HAVE_HYPRE)
396: PetscCall(MatHYPRESetPreallocation(A, 0, dnnz, 0, onnz));
397: #endif
398: } else { /* Convert block-row precallocation to scalar-row */
399: PetscInt i, m, *sdnnz, *sonnz;
400: PetscCall(MatGetLocalSize(A, &m, NULL));
401: PetscCall(PetscMalloc2((!!dnnz) * m, &sdnnz, (!!onnz) * m, &sonnz));
402: for (i = 0; i < m; i++) {
403: if (dnnz) sdnnz[i] = dnnz[i / bs] * cbs;
404: if (onnz) sonnz[i] = onnz[i / bs] * cbs;
405: }
406: PetscCall(MatSeqAIJSetPreallocation(A, 0, dnnz ? sdnnz : NULL));
407: PetscCall(MatMPIAIJSetPreallocation(A, 0, dnnz ? sdnnz : NULL, 0, onnz ? sonnz : NULL));
408: PetscCall(MatISSetPreallocation(A, 0, dnnz ? sdnnz : NULL, 0, onnz ? sonnz : NULL));
409: #if PetscDefined(HAVE_HYPRE)
410: PetscCall(MatHYPRESetPreallocation(A, 0, dnnz ? sdnnz : NULL, 0, onnz ? sonnz : NULL));
411: #endif
412: PetscCall(PetscFree2(sdnnz, sonnz));
413: }
414: }
415: PetscFunctionReturn(PETSC_SUCCESS);
416: }
418: /*@
419: MatHeaderMerge - Merges some information from the header of `C` to `A`; the `C` object is then destroyed
421: Collective, No Fortran Support
423: Input Parameters:
424: + A - a `Mat` being merged into
425: - C - the `Mat` providing the merge information
427: Level: developer
429: Notes:
430: `A` and `C` must be of the same type.
431: The object list and query function list in `A` are retained, as well as the object name, and prefix.
432: The object state of `A` is increased by 1.
434: Developer Note:
435: This is somewhat different from `MatHeaderReplace()`, it would be nice to merge the code
437: .seealso: `Mat`, `MatHeaderReplace()`
438: @*/
439: PetscErrorCode MatHeaderMerge(Mat A, Mat *C)
440: {
441: PetscInt refct;
442: PetscOps Abops;
443: struct _MatOps Aops;
444: char *mtype, *mname, *mprefix;
445: Mat_Product *product;
446: Mat_Redundant *redundant;
447: PetscObjectState state;
448: PetscObjectList olist;
449: PetscFunctionList qlist;
451: PetscFunctionBegin;
454: if (A == *C) PetscFunctionReturn(PETSC_SUCCESS);
455: PetscCheckSameTypeAndComm(A, 1, *C, 2);
456: /* save the parts of A we need */
457: Abops = ((PetscObject)A)->bops[0];
458: Aops = A->ops[0];
459: refct = ((PetscObject)A)->refct;
460: mtype = ((PetscObject)A)->type_name;
461: mname = ((PetscObject)A)->name;
462: state = ((PetscObject)A)->state;
463: mprefix = ((PetscObject)A)->prefix;
464: product = A->product;
465: redundant = A->redundant;
466: qlist = ((PetscObject)A)->qlist;
467: olist = ((PetscObject)A)->olist;
469: /* zero these so the destroy below does not free them */
470: ((PetscObject)A)->type_name = NULL;
471: ((PetscObject)A)->name = NULL;
472: ((PetscObject)A)->qlist = NULL;
473: ((PetscObject)A)->olist = NULL;
475: /*
476: free all the interior data structures from mat
477: cannot use PetscUseTypeMethod(A,destroy); because compiler
478: thinks it may print NULL type_name and name
479: */
480: PetscTryTypeMethod(A, destroy);
482: PetscCall(PetscFree(A->defaultvectype));
483: PetscCall(PetscFree(A->defaultrandtype));
484: PetscCall(PetscLayoutDestroy(&A->rmap));
485: PetscCall(PetscLayoutDestroy(&A->cmap));
486: PetscCall(PetscComposedQuantitiesDestroy((PetscObject)A));
488: /* copy C over to A */
489: PetscCall(PetscFree(A->factorprefix));
490: PetscCall(PetscMemcpy(A, *C, sizeof(struct _p_Mat)));
492: /* return the parts of A we saved */
493: ((PetscObject)A)->bops[0] = Abops;
494: A->ops[0] = Aops;
495: ((PetscObject)A)->refct = refct;
496: ((PetscObject)A)->type_name = mtype;
497: ((PetscObject)A)->name = mname;
498: ((PetscObject)A)->prefix = mprefix;
499: ((PetscObject)A)->state = state + 1;
500: A->product = product;
501: A->redundant = redundant;
503: /* Append the saved lists */
504: PetscCall(PetscFunctionListDuplicate(qlist, &((PetscObject)A)->qlist));
505: PetscCall(PetscObjectListDuplicate(olist, &((PetscObject)A)->olist));
506: PetscCall(PetscFunctionListDestroy(&qlist));
507: PetscCall(PetscObjectListDestroy(&olist));
509: /* since these two are copied into A we do not want them destroyed in C */
510: ((PetscObject)*C)->qlist = NULL;
511: ((PetscObject)*C)->olist = NULL;
512: PetscCall(PetscHeaderDestroy(C));
513: PetscFunctionReturn(PETSC_SUCCESS);
514: }
516: /*@
517: MatHeaderReplace - Replaces the internal data of matrix `A` by the internal data of matrix `C` while deleting the outer wrapper of `C`
519: Input Parameters:
520: + A - a `Mat` whose internal data is to be replaced
521: - C - the `Mat` providing new internal data for `A`
523: Level: advanced
525: Example Usage\:
526: .vb
527: Mat C;
528: MatCreateSeqAIJWithArrays(..., &C);
529: MatHeaderReplace(A, &C);
530: // C has been destroyed and A contains the matrix entries of C
531: .ve
533: Note:
534: This can be used inside a function provided to `SNESSetJacobian()`, `TSSetRHSJacobian()`, or `TSSetIJacobian()` in cases where the user code
535: computes an entirely new sparse matrix (generally with a different matrix nonzero structure/pattern) for each Newton update.
536: It is usually better to reuse the matrix nonzero structure of `A` instead of constructing an entirely new one.
538: Developer Note:
539: This is somewhat different from `MatHeaderMerge()` it would be nice to merge the code
541: .seealso: `Mat`, `MatHeaderMerge()`
542: @*/
543: PetscErrorCode MatHeaderReplace(Mat A, Mat *C)
544: {
545: PetscInt refct;
546: PetscObjectState state;
547: struct _p_Mat buffer;
548: MatStencilInfo stencil;
550: PetscFunctionBegin;
553: if (A == *C) PetscFunctionReturn(PETSC_SUCCESS);
554: PetscCheckSameComm(A, 1, *C, 2);
555: PetscCheck(((PetscObject)*C)->refct == 1, PetscObjectComm((PetscObject)C), PETSC_ERR_ARG_WRONGSTATE, "Object C has refct %" PetscInt_FMT " > 1, would leave hanging reference", ((PetscObject)*C)->refct);
557: /* swap C and A */
558: refct = ((PetscObject)A)->refct;
559: state = ((PetscObject)A)->state;
560: stencil = A->stencil;
561: PetscCall(PetscMemcpy(&buffer, A, sizeof(struct _p_Mat)));
562: PetscCall(PetscMemcpy(A, *C, sizeof(struct _p_Mat)));
563: PetscCall(PetscMemcpy(*C, &buffer, sizeof(struct _p_Mat)));
564: ((PetscObject)A)->refct = refct;
565: ((PetscObject)A)->state = state + 1;
566: A->stencil = stencil;
568: ((PetscObject)*C)->refct = 1;
569: PetscCall(MatDestroy(C));
570: PetscFunctionReturn(PETSC_SUCCESS);
571: }
573: /*@
574: MatBindToCPU - marks a matrix to temporarily stay on the CPU and perform computations on the CPU
576: Logically Collective
578: Input Parameters:
579: + A - the matrix
580: - flg - bind to the CPU if value of `PETSC_TRUE`
582: Level: intermediate
584: Note:
585: `MATAIJKOKKOS` has yet to implement CPU binding. If Kokkos is configured without GPU support,
586: we deem a `MATAIJKOKKOS` matrix as bound to the CPU. Different from `MATAIJVIENNACL` with a CPU
587: backend, `MATAIJKOKKOS` always use its own operation implementations (in contrast to CPU-bound
588: `MATAIJVIENNACL`, which uses `MATAIJ`'s CPU operations).
590: .seealso: [](ch_matrices), `Mat`, `MatBoundToCPU()`
591: @*/
592: PetscErrorCode MatBindToCPU(Mat A, PetscBool flg)
593: {
594: PetscFunctionBegin;
597: #if PetscDefined(HAVE_DEVICE)
598: if (A->boundtocpu == flg) PetscFunctionReturn(PETSC_SUCCESS);
599: A->boundtocpu = flg;
600: PetscTryTypeMethod(A, bindtocpu, flg);
601: #endif
602: PetscFunctionReturn(PETSC_SUCCESS);
603: }
605: /*@
606: MatBoundToCPU - query if a matrix is bound to the CPU
608: Input Parameter:
609: . A - the matrix
611: Output Parameter:
612: . flg - the logical flag
614: Level: intermediate
616: .seealso: [](ch_matrices), `Mat`, `MatBindToCPU()`
617: @*/
618: PetscErrorCode MatBoundToCPU(Mat A, PetscBool *flg)
619: {
620: PetscFunctionBegin;
622: PetscAssertPointer(flg, 2);
623: #if PetscDefined(HAVE_DEVICE)
624: *flg = A->boundtocpu;
625: #else
626: *flg = PETSC_TRUE;
627: #endif
628: PetscFunctionReturn(PETSC_SUCCESS);
629: }
631: PetscErrorCode MatSetValuesCOO_Basic(Mat A, const PetscScalar coo_v[], InsertMode imode)
632: {
633: IS is_coo_i, is_coo_j;
634: const PetscInt *coo_i, *coo_j;
635: PetscInt n, n_i, n_j;
636: PetscScalar zero = 0.;
638: PetscFunctionBegin;
639: PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_coo_i", (PetscObject *)&is_coo_i));
640: PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_coo_j", (PetscObject *)&is_coo_j));
641: PetscCheck(is_coo_i, PetscObjectComm((PetscObject)A), PETSC_ERR_COR, "Missing coo_i IS");
642: PetscCheck(is_coo_j, PetscObjectComm((PetscObject)A), PETSC_ERR_COR, "Missing coo_j IS");
643: PetscCall(ISGetLocalSize(is_coo_i, &n_i));
644: PetscCall(ISGetLocalSize(is_coo_j, &n_j));
645: PetscCheck(n_i == n_j, PETSC_COMM_SELF, PETSC_ERR_COR, "Wrong local size %" PetscInt_FMT " != %" PetscInt_FMT, n_i, n_j);
646: PetscCall(ISGetIndices(is_coo_i, &coo_i));
647: PetscCall(ISGetIndices(is_coo_j, &coo_j));
648: if (imode != ADD_VALUES) PetscCall(MatZeroEntries(A));
649: for (n = 0; n < n_i; n++) PetscCall(MatSetValue(A, coo_i[n], coo_j[n], coo_v ? coo_v[n] : zero, ADD_VALUES));
650: PetscCall(ISRestoreIndices(is_coo_i, &coo_i));
651: PetscCall(ISRestoreIndices(is_coo_j, &coo_j));
652: PetscFunctionReturn(PETSC_SUCCESS);
653: }
655: PetscErrorCode MatSetPreallocationCOO_Basic(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
656: {
657: Mat preallocator;
658: IS is_coo_i, is_coo_j;
659: PetscInt ncoo_i;
660: PetscScalar zero = 0.0;
662: PetscFunctionBegin;
663: PetscCall(PetscIntCast(ncoo, &ncoo_i));
664: PetscCall(PetscLayoutSetUp(A->rmap));
665: PetscCall(PetscLayoutSetUp(A->cmap));
666: PetscCall(MatCreate(PetscObjectComm((PetscObject)A), &preallocator));
667: PetscCall(MatSetType(preallocator, MATPREALLOCATOR));
668: PetscCall(MatSetSizes(preallocator, A->rmap->n, A->cmap->n, A->rmap->N, A->cmap->N));
669: PetscCall(MatSetLayouts(preallocator, A->rmap, A->cmap));
670: PetscCall(MatSetUp(preallocator));
671: for (PetscCount n = 0; n < ncoo; n++) PetscCall(MatSetValue(preallocator, coo_i[n], coo_j[n], zero, INSERT_VALUES));
672: PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY));
673: PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY));
674: PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, A));
675: PetscCall(MatDestroy(&preallocator));
676: PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncoo_i, coo_i, PETSC_COPY_VALUES, &is_coo_i));
677: PetscCall(ISCreateGeneral(PETSC_COMM_SELF, ncoo_i, coo_j, PETSC_COPY_VALUES, &is_coo_j));
678: PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc_coo_i", (PetscObject)is_coo_i));
679: PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc_coo_j", (PetscObject)is_coo_j));
680: PetscCall(ISDestroy(&is_coo_i));
681: PetscCall(ISDestroy(&is_coo_j));
682: PetscFunctionReturn(PETSC_SUCCESS);
683: }
685: /*@
686: MatSetPreallocationCOO - set preallocation for matrices using a coordinate format of the entries with global indices
688: Collective
690: Input Parameters:
691: + A - matrix being preallocated
692: . ncoo - number of entries
693: . coo_i - row indices
694: - coo_j - column indices
696: Level: beginner
698: Notes:
699: The indices within `coo_i` and `coo_j` may be modified within this function. The caller should not rely on them
700: having any specific value after this function returns. The arrays can be freed or reused immediately
701: after this function returns.
703: Entries can be repeated, see `MatSetValuesCOO()`. Entries with negative row or column indices are allowed
704: but will be ignored. The corresponding entries in `MatSetValuesCOO()` will be ignored too. Remote entries
705: are allowed and will be properly added or inserted to the matrix, unless the matrix option `MAT_IGNORE_OFF_PROC_ENTRIES`
706: is set, in which case remote entries are ignored, or `MAT_NO_OFF_PROC_ENTRIES` is set, in which case an error will be generated.
708: If you just want to create a sequential AIJ matrix (`MATSEQAIJ`), and your matrix entries in COO format are unique, you can also use
709: `MatCreateSeqAIJFromTriple()`. But that is not recommended for iterative applications.
711: .seealso: [](ch_matrices), `Mat`, `MatSetValuesCOO()`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatSeqBAIJSetPreallocation()`,
712: `MatMPIBAIJSetPreallocation()`, `MatSeqSBAIJSetPreallocation()`, `MatMPISBAIJSetPreallocation()`, `MatSetPreallocationCOOLocal()`,
713: `DMSetMatrixPreallocateSkip()`, `MatCreateSeqAIJFromTriple()`
714: @*/
715: PetscErrorCode MatSetPreallocationCOO(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
716: {
717: PetscErrorCode (*f)(Mat, PetscCount, PetscInt[], PetscInt[]) = NULL;
719: PetscFunctionBegin;
722: if (ncoo) PetscAssertPointer(coo_i, 3);
723: if (ncoo) PetscAssertPointer(coo_j, 4);
724: PetscCall(PetscLayoutSetUp(A->rmap));
725: PetscCall(PetscLayoutSetUp(A->cmap));
726: PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatSetPreallocationCOO_C", &f));
728: PetscCall(PetscLogEventBegin(MAT_PreallCOO, A, 0, 0, 0));
729: if (f) PetscCall((*f)(A, ncoo, coo_i, coo_j));
730: else PetscCall(MatSetPreallocationCOO_Basic(A, ncoo, coo_i, coo_j)); /* allow fallback, very slow */
731: PetscCall(PetscLogEventEnd(MAT_PreallCOO, A, 0, 0, 0));
732: A->preallocated = PETSC_TRUE;
733: A->nonzerostate++;
734: PetscFunctionReturn(PETSC_SUCCESS);
735: }
737: /*@
738: MatSetPreallocationCOOLocal - set preallocation for matrices using a coordinate format of the entries with local indices
740: Collective
742: Input Parameters:
743: + A - matrix being preallocated
744: . ncoo - number of entries
745: . coo_i - row indices (local numbering; may be modified)
746: - coo_j - column indices (local numbering; may be modified)
748: Level: beginner
750: Notes:
751: The local indices are translated using the local to global mapping, thus `MatSetLocalToGlobalMapping()` must have been
752: called prior to this function. For matrices created with `DMCreateMatrix()` the local to global mapping is often already provided.
754: The indices `coo_i` and `coo_j` may be modified within this function. They might be translated to corresponding global
755: indices, but the caller should not rely on them having any specific value after this function returns. The arrays
756: can be freed or reused immediately after this function returns.
758: Entries can be repeated, see `MatSetValuesCOO()`. Entries with negative row or column indices are allowed
759: but will be ignored. The corresponding entries in `MatSetValuesCOO()` will be ignored too. Remote entries
760: are allowed and will be properly added or inserted to the matrix.
762: .seealso: [](ch_matrices), `Mat`, `MatSetValuesCOO()`, `MatSeqAIJSetPreallocation()`, `MatMPIAIJSetPreallocation()`, `MatSeqBAIJSetPreallocation()`,
763: `MatMPIBAIJSetPreallocation()`, `MatSeqSBAIJSetPreallocation()`, `MatMPISBAIJSetPreallocation()`, `MatSetPreallocationCOO()`,
764: `DMSetMatrixPreallocateSkip()`
765: @*/
766: PetscErrorCode MatSetPreallocationCOOLocal(Mat A, PetscCount ncoo, PetscInt coo_i[], PetscInt coo_j[])
767: {
768: PetscErrorCode (*f)(Mat, PetscCount, PetscInt[], PetscInt[]) = NULL;
770: PetscFunctionBegin;
773: if (ncoo) PetscAssertPointer(coo_i, 3);
774: if (ncoo) PetscAssertPointer(coo_j, 4);
775: PetscCall(PetscLayoutSetUp(A->rmap));
776: PetscCall(PetscLayoutSetUp(A->cmap));
778: PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatSetPreallocationCOOLocal_C", &f));
779: if (f) {
780: PetscCall((*f)(A, ncoo, coo_i, coo_j));
781: A->nonzerostate++;
782: } else {
783: PetscInt ncoo_i;
784: ISLocalToGlobalMapping ltog_row, ltog_col;
786: PetscCall(MatGetLocalToGlobalMapping(A, <og_row, <og_col));
787: if (ltog_row) {
788: PetscCall(PetscIntCast(ncoo, &ncoo_i));
789: PetscCall(ISLocalToGlobalMappingApply(ltog_row, ncoo_i, coo_i, coo_i));
790: }
791: if (ltog_col) {
792: PetscCall(PetscIntCast(ncoo, &ncoo_i));
793: PetscCall(ISLocalToGlobalMappingApply(ltog_col, ncoo_i, coo_j, coo_j));
794: }
795: PetscCall(MatSetPreallocationCOO(A, ncoo, coo_i, coo_j));
796: }
797: A->preallocated = PETSC_TRUE;
798: PetscFunctionReturn(PETSC_SUCCESS);
799: }
801: /*@
802: MatSetValuesCOO - set values at once in a matrix preallocated using `MatSetPreallocationCOO()`
804: Collective
806: Input Parameters:
807: + A - matrix being preallocated
808: . coo_v - the matrix values (can be `NULL`)
809: - imode - the insert mode
811: Level: beginner
813: Notes:
814: The values must follow the order of the indices prescribed with `MatSetPreallocationCOO()` or `MatSetPreallocationCOOLocal()`.
816: When repeated entries are specified in the COO indices the `coo_v` values are first properly summed, regardless of the value of imode.
817: The imode flag indicates if coo_v must be added to the current values of the matrix (`ADD_VALUES`) or overwritten (`INSERT_VALUES`).
819: `MatAssemblyBegin()` and `MatAssemblyEnd()` do not need to be called after this routine. It automatically handles the assembly process.
821: If the `MAT_STRUCTURE_ONLY` option is set to true, the values are ignored and only the assembly process is performed.
823: `MatSetValues()` and other operations may modify existing entries of the matrix between calls to this routine. If they change
824: the nonzero pattern built by `MatSetPreallocationCOO()`, for example by inserting a new nonzero, this routine generates an error
825: for `MATAIJ` and its device subtypes; call `MatSetPreallocationCOO()` again before calling `MatSetValuesCOO()`.
827: .seealso: [](ch_matrices), `Mat`, `MatSetPreallocationCOO()`, `MatSetPreallocationCOOLocal()`, `InsertMode`, `INSERT_VALUES`, `ADD_VALUES`
828: @*/
829: PetscErrorCode MatSetValuesCOO(Mat A, const PetscScalar coo_v[], InsertMode imode)
830: {
831: PetscErrorCode (*f)(Mat, const PetscScalar[], InsertMode) = NULL;
832: PetscBool oldFlg;
834: PetscFunctionBegin;
837: MatCheckPreallocated(A, 1);
839: PetscCall(PetscObjectQueryFunction((PetscObject)A, "MatSetValuesCOO_C", &f));
840: PetscCall(PetscLogEventBegin(MAT_SetVCOO, A, 0, 0, 0));
841: if (f) {
842: if (!A->structure_only) PetscCall((*f)(A, coo_v, imode)); // all known COO implementations do not use MatStash. They do their own off-proc communication
843: PetscCall(MatGetOption(A, MAT_NO_OFF_PROC_ENTRIES, &oldFlg));
844: PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, PETSC_TRUE)); // set A->nooffprocentries to avoid costly MatStash scatter in MatAssembly
845: } else if (!A->structure_only) PetscCall(MatSetValuesCOO_Basic(A, coo_v, imode)); // fall back to MatSetValues, which might use MatStash
846: PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
847: PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
848: if (f) PetscCall(MatSetOption(A, MAT_NO_OFF_PROC_ENTRIES, oldFlg));
849: PetscCall(PetscLogEventEnd(MAT_SetVCOO, A, 0, 0, 0));
850: PetscFunctionReturn(PETSC_SUCCESS);
851: }
853: /*@
854: MatSetBindingPropagates - Sets whether the state of being bound to the CPU for a GPU matrix type propagates to child and some other associated objects
856: Input Parameters:
857: + A - the matrix
858: - flg - flag indicating whether the boundtocpu flag should be propagated
860: Level: developer
862: Notes:
863: If the value of flg is set to true, the following will occur
864: + `MatCreateSubMatrices()` and `MatCreateRedundantMatrix()` - bind created matrices to CPU if the input matrix is bound to the CPU.
865: - `MatCreateVecs()` - bind created vectors to CPU if the input matrix is bound to the CPU.
867: The bindingpropagates flag itself is also propagated by the above routines.
869: Developer Notes:
870: If the fine-scale `DMDA` has the `-dm_bind_below` option set to true, then `DMCreateInterpolationScale()` calls `MatSetBindingPropagates()`
871: on the restriction/interpolation operator to set the bindingpropagates flag to true.
873: .seealso: [](ch_matrices), `Mat`, `VecSetBindingPropagates()`, `MatGetBindingPropagates()`
874: @*/
875: PetscErrorCode MatSetBindingPropagates(Mat A, PetscBool flg)
876: {
877: PetscFunctionBegin;
879: #if PetscDefined(HAVE_VIENNACL) || PetscDefined(HAVE_CUDA) || PetscDefined(HAVE_HIP)
880: A->bindingpropagates = flg;
881: #endif
882: PetscFunctionReturn(PETSC_SUCCESS);
883: }
885: /*@
886: MatGetBindingPropagates - Gets whether the state of being bound to the CPU for a GPU matrix type propagates to child and some other associated objects
888: Input Parameter:
889: . A - the matrix
891: Output Parameter:
892: . flg - flag indicating whether the boundtocpu flag will be propagated
894: Level: developer
896: .seealso: [](ch_matrices), `Mat`, `MatSetBindingPropagates()`
897: @*/
898: PetscErrorCode MatGetBindingPropagates(Mat A, PetscBool *flg)
899: {
900: PetscFunctionBegin;
902: PetscAssertPointer(flg, 2);
903: #if PetscDefined(HAVE_VIENNACL) || PetscDefined(HAVE_CUDA) || PetscDefined(HAVE_HIP)
904: *flg = A->bindingpropagates;
905: #else
906: *flg = PETSC_FALSE;
907: #endif
908: PetscFunctionReturn(PETSC_SUCCESS);
909: }