17072be85SIrina Sokolova /* 27072be85SIrina Sokolova Defines basic operations for the MATSEQBAIJMKL matrix class. 37072be85SIrina Sokolova Uses sparse BLAS operations from the Intel Math Kernel Library (MKL) 47072be85SIrina Sokolova wherever possible. If used MKL verion is older than 11.3 PETSc default 57072be85SIrina Sokolova code for sparse matrix operations is used. 67072be85SIrina Sokolova */ 77072be85SIrina Sokolova 87072be85SIrina Sokolova #include <../src/mat/impls/baij/seq/baij.h> 97072be85SIrina Sokolova #include <../src/mat/impls/baij/seq/baijmkl/baijmkl.h> 107072be85SIrina Sokolova 117072be85SIrina Sokolova 127072be85SIrina Sokolova /* MKL include files. */ 137072be85SIrina Sokolova #include <mkl_spblas.h> /* Sparse BLAS */ 147072be85SIrina Sokolova 157072be85SIrina Sokolova #ifdef PETSC_HAVE_MKL_SPARSE_OPTIMIZE 167072be85SIrina Sokolova typedef struct { 177072be85SIrina Sokolova PetscBool sparse_optimized; /* If PETSC_TRUE, then mkl_sparse_optimize() has been called. */ 187072be85SIrina Sokolova sparse_matrix_t bsrA; /* "Handle" used by SpMV2 inspector-executor routines. */ 197072be85SIrina Sokolova struct matrix_descr descr; 207072be85SIrina Sokolova #ifndef PETSC_MKL_SUPPORTS_BAIJ_ZERO_BASED 217072be85SIrina Sokolova PetscInt *ai1; 227072be85SIrina Sokolova PetscInt *aj1; 237072be85SIrina Sokolova #endif 247072be85SIrina Sokolova } Mat_SeqBAIJMKL; 257072be85SIrina Sokolova 264d6dccb5SIrina Sokolova PetscErrorCode MatAssemblyEnd_SeqBAIJMKL(Mat A, MatAssemblyType mode); 277072be85SIrina Sokolova extern PetscErrorCode MatAssemblyEnd_SeqBAIJ(Mat,MatAssemblyType); 287072be85SIrina Sokolova 297072be85SIrina Sokolova PETSC_INTERN PetscErrorCode MatConvert_SeqBAIJMKL_SeqBAIJ(Mat A,MatType type,MatReuse reuse,Mat *newmat) 307072be85SIrina Sokolova { 317072be85SIrina Sokolova /* This routine is only called to convert a MATBAIJMKL to its base PETSc type, */ 327072be85SIrina Sokolova /* so we will ignore 'MatType type'. */ 337072be85SIrina Sokolova PetscErrorCode ierr; 347072be85SIrina Sokolova Mat B = *newmat; 357072be85SIrina Sokolova Mat_SeqBAIJMKL *baijmkl = (Mat_SeqBAIJMKL*)A->spptr; 367072be85SIrina Sokolova 377072be85SIrina Sokolova PetscFunctionBegin; 387072be85SIrina Sokolova if (reuse == MAT_INITIAL_MATRIX) { 397072be85SIrina Sokolova ierr = MatDuplicate(A,MAT_COPY_VALUES,&B);CHKERRQ(ierr); 407072be85SIrina Sokolova } 417072be85SIrina Sokolova 427072be85SIrina Sokolova /* Reset the original function pointers. */ 437072be85SIrina Sokolova B->ops->duplicate = MatDuplicate_SeqBAIJ; 447072be85SIrina Sokolova B->ops->assemblyend = MatAssemblyEnd_SeqBAIJ; 457072be85SIrina Sokolova B->ops->destroy = MatDestroy_SeqBAIJ; 467072be85SIrina Sokolova B->ops->multtranspose = MatMultTranspose_SeqBAIJ; 477072be85SIrina Sokolova B->ops->multtransposeadd = MatMultTransposeAdd_SeqBAIJ; 487072be85SIrina Sokolova B->ops->scale = MatScale_SeqBAIJ; 497072be85SIrina Sokolova B->ops->diagonalscale = MatDiagonalScale_SeqBAIJ; 507072be85SIrina Sokolova B->ops->axpy = MatAXPY_SeqBAIJ; 517072be85SIrina Sokolova 527072be85SIrina Sokolova switch (A->rmap->bs) { 537072be85SIrina Sokolova case 1: 547072be85SIrina Sokolova B->ops->mult = MatMult_SeqBAIJ_1; 557072be85SIrina Sokolova B->ops->multadd = MatMultAdd_SeqBAIJ_1; 567072be85SIrina Sokolova break; 577072be85SIrina Sokolova case 2: 587072be85SIrina Sokolova B->ops->mult = MatMult_SeqBAIJ_2; 597072be85SIrina Sokolova B->ops->multadd = MatMultAdd_SeqBAIJ_2; 607072be85SIrina Sokolova break; 617072be85SIrina Sokolova case 3: 627072be85SIrina Sokolova B->ops->mult = MatMult_SeqBAIJ_3; 637072be85SIrina Sokolova B->ops->multadd = MatMultAdd_SeqBAIJ_3; 647072be85SIrina Sokolova break; 657072be85SIrina Sokolova case 4: 667072be85SIrina Sokolova B->ops->mult = MatMult_SeqBAIJ_4; 677072be85SIrina Sokolova B->ops->multadd = MatMultAdd_SeqBAIJ_4; 687072be85SIrina Sokolova break; 697072be85SIrina Sokolova case 5: 707072be85SIrina Sokolova B->ops->mult = MatMult_SeqBAIJ_5; 717072be85SIrina Sokolova B->ops->multadd = MatMultAdd_SeqBAIJ_5; 727072be85SIrina Sokolova break; 737072be85SIrina Sokolova case 6: 747072be85SIrina Sokolova B->ops->mult = MatMult_SeqBAIJ_6; 757072be85SIrina Sokolova B->ops->multadd = MatMultAdd_SeqBAIJ_6; 767072be85SIrina Sokolova break; 777072be85SIrina Sokolova case 7: 787072be85SIrina Sokolova B->ops->mult = MatMult_SeqBAIJ_7; 797072be85SIrina Sokolova B->ops->multadd = MatMultAdd_SeqBAIJ_7; 807072be85SIrina Sokolova break; 817072be85SIrina Sokolova case 11: 827072be85SIrina Sokolova B->ops->mult = MatMult_SeqBAIJ_11; 837072be85SIrina Sokolova B->ops->multadd = MatMultAdd_SeqBAIJ_11; 847072be85SIrina Sokolova break; 857072be85SIrina Sokolova case 15: 867072be85SIrina Sokolova B->ops->mult = MatMult_SeqBAIJ_15_ver1; 877072be85SIrina Sokolova B->ops->multadd = MatMultAdd_SeqBAIJ_N; 887072be85SIrina Sokolova break; 897072be85SIrina Sokolova default: 907072be85SIrina Sokolova B->ops->mult = MatMult_SeqBAIJ_N; 917072be85SIrina Sokolova B->ops->multadd = MatMultAdd_SeqBAIJ_N; 927072be85SIrina Sokolova break; 937072be85SIrina Sokolova } 947072be85SIrina Sokolova ierr = PetscObjectComposeFunction((PetscObject)B,"MatConvert_seqbaijmkl_seqbaij_C",NULL);CHKERRQ(ierr); 957072be85SIrina Sokolova 967072be85SIrina Sokolova /* Free everything in the Mat_SeqBAIJMKL data structure. Currently, this 977072be85SIrina Sokolova * simply involves destroying the MKL sparse matrix handle and then freeing 987072be85SIrina Sokolova * the spptr pointer. */ 997072be85SIrina Sokolova if (reuse == MAT_INITIAL_MATRIX) baijmkl = (Mat_SeqBAIJMKL*)B->spptr; 1007072be85SIrina Sokolova 1017072be85SIrina Sokolova if (baijmkl->sparse_optimized) { 1027072be85SIrina Sokolova sparse_status_t stat; 1037072be85SIrina Sokolova stat = mkl_sparse_destroy(baijmkl->bsrA); 1047072be85SIrina Sokolova if (stat != SPARSE_STATUS_SUCCESS) { 1057072be85SIrina Sokolova PetscFunctionReturn(PETSC_ERR_LIB); 1067072be85SIrina Sokolova } 1077072be85SIrina Sokolova } 1087072be85SIrina Sokolova #ifndef PETSC_MKL_SUPPORTS_BAIJ_ZERO_BASED 1097072be85SIrina Sokolova ierr = PetscFree(baijmkl->ai1);CHKERRQ(ierr); 1107072be85SIrina Sokolova ierr = PetscFree(baijmkl->aj1);CHKERRQ(ierr); 1117072be85SIrina Sokolova #endif 1127072be85SIrina Sokolova ierr = PetscFree(B->spptr);CHKERRQ(ierr); 1137072be85SIrina Sokolova 1147072be85SIrina Sokolova /* Change the type of B to MATSEQBAIJ. */ 1157072be85SIrina Sokolova ierr = PetscObjectChangeTypeName((PetscObject)B, MATSEQBAIJ);CHKERRQ(ierr); 1167072be85SIrina Sokolova 1177072be85SIrina Sokolova *newmat = B; 1187072be85SIrina Sokolova PetscFunctionReturn(0); 1197072be85SIrina Sokolova } 1207072be85SIrina Sokolova 1217072be85SIrina Sokolova PetscErrorCode MatDestroy_SeqBAIJMKL(Mat A) 1227072be85SIrina Sokolova { 1237072be85SIrina Sokolova PetscErrorCode ierr; 1247072be85SIrina Sokolova Mat_SeqBAIJMKL *baijmkl = (Mat_SeqBAIJMKL*) A->spptr; 1257072be85SIrina Sokolova 1267072be85SIrina Sokolova PetscFunctionBegin; 1277072be85SIrina Sokolova if (baijmkl) { 1287072be85SIrina Sokolova /* Clean up everything in the Mat_SeqBAIJMKL data structure, then free A->spptr. */ 1297072be85SIrina Sokolova if (baijmkl->sparse_optimized) { 1307072be85SIrina Sokolova sparse_status_t stat = SPARSE_STATUS_SUCCESS; 1317072be85SIrina Sokolova stat = mkl_sparse_destroy(baijmkl->bsrA); 1327072be85SIrina Sokolova if (stat != SPARSE_STATUS_SUCCESS) { 1337072be85SIrina Sokolova PetscFunctionReturn(PETSC_ERR_LIB); 1347072be85SIrina Sokolova } 1357072be85SIrina Sokolova } 1367072be85SIrina Sokolova #ifndef PETSC_MKL_SUPPORTS_BAIJ_ZERO_BASED 1377072be85SIrina Sokolova ierr = PetscFree(baijmkl->ai1);CHKERRQ(ierr); 1387072be85SIrina Sokolova ierr = PetscFree(baijmkl->aj1);CHKERRQ(ierr); 1397072be85SIrina Sokolova #endif 1407072be85SIrina Sokolova ierr = PetscFree(A->spptr);CHKERRQ(ierr); 1417072be85SIrina Sokolova } 1427072be85SIrina Sokolova 1437072be85SIrina Sokolova /* Change the type of A back to SEQBAIJ and use MatDestroy_SeqBAIJ() 1447072be85SIrina Sokolova * to destroy everything that remains. */ 1457072be85SIrina Sokolova ierr = PetscObjectChangeTypeName((PetscObject)A, MATSEQBAIJ);CHKERRQ(ierr); 1467072be85SIrina Sokolova ierr = MatDestroy_SeqBAIJ(A);CHKERRQ(ierr); 1477072be85SIrina Sokolova PetscFunctionReturn(0); 1487072be85SIrina Sokolova } 1497072be85SIrina Sokolova 1507072be85SIrina Sokolova PETSC_INTERN PetscErrorCode MatSeqBAIJMKL_create_mkl_handle(Mat A) 1517072be85SIrina Sokolova { 1527072be85SIrina Sokolova PetscErrorCode ierr; 1537072be85SIrina Sokolova Mat_SeqBAIJ *a = (Mat_SeqBAIJ*)A->data; 1547072be85SIrina Sokolova Mat_SeqBAIJMKL *baijmkl = (Mat_SeqBAIJMKL*)A->spptr; 1557072be85SIrina Sokolova PetscInt mbs, nbs, nz, bs, i; 1567072be85SIrina Sokolova MatScalar *aa; 1577072be85SIrina Sokolova PetscInt *aj,*ai; 1587072be85SIrina Sokolova sparse_status_t stat; 1597072be85SIrina Sokolova 1607072be85SIrina Sokolova PetscFunctionBegin; 1617072be85SIrina Sokolova if (baijmkl->sparse_optimized) { 1627072be85SIrina Sokolova /* Matrix has been previously assembled and optimized. Must destroy old 1637072be85SIrina Sokolova * matrix handle before running the optimization step again. */ 1644d6dccb5SIrina Sokolova #ifndef PETSC_MKL_SUPPORTS_BAIJ_ZERO_BASED 1654d6dccb5SIrina Sokolova ierr = PetscFree(baijmkl->ai1);CHKERRQ(ierr); 1664d6dccb5SIrina Sokolova ierr = PetscFree(baijmkl->aj1);CHKERRQ(ierr); 1674d6dccb5SIrina Sokolova #endif 168017c2882SIrina Sokolova stat = mkl_sparse_destroy(baijmkl->bsrA);CHKERRMKL(stat); 1697072be85SIrina Sokolova } 1707072be85SIrina Sokolova baijmkl->sparse_optimized = PETSC_FALSE; 1717072be85SIrina Sokolova 1727072be85SIrina Sokolova /* Now perform the SpMV2 setup and matrix optimization. */ 1737072be85SIrina Sokolova baijmkl->descr.type = SPARSE_MATRIX_TYPE_GENERAL; 1747072be85SIrina Sokolova baijmkl->descr.mode = SPARSE_FILL_MODE_LOWER; 1757072be85SIrina Sokolova baijmkl->descr.diag = SPARSE_DIAG_NON_UNIT; 1767072be85SIrina Sokolova mbs = a->mbs; 1777072be85SIrina Sokolova nbs = a->nbs; 1787072be85SIrina Sokolova nz = a->nz; 1797072be85SIrina Sokolova bs = A->rmap->bs; 1807072be85SIrina Sokolova aa = a->a; 1817072be85SIrina Sokolova 182*80095d54SIrina Sokolova if ((nz!=0) & !(A->structure_only)) { 1837072be85SIrina Sokolova /* Create a new, optimized sparse matrix handle only if the matrix has nonzero entries. 1847072be85SIrina Sokolova * The MKL sparse-inspector executor routines don't like being passed an empty matrix. */ 1857072be85SIrina Sokolova #ifdef PETSC_MKL_SUPPORTS_BAIJ_ZERO_BASED 1867072be85SIrina Sokolova aj = a->j; 1877072be85SIrina Sokolova ai = a->i; 188017c2882SIrina Sokolova stat = mkl_sparse_x_create_bsr(&(baijmkl->bsrA),SPARSE_INDEX_BASE_ZERO,SPARSE_LAYOUT_COLUMN_MAJOR,mbs,nbs,bs,ai,ai+1,aj,aa);CHKERRMKL(stat); 1897072be85SIrina Sokolova #else 1907072be85SIrina Sokolova ierr = PetscMalloc1(mbs+1,&ai);CHKERRQ(ierr); 1917072be85SIrina Sokolova ierr = PetscMalloc1(nz,&aj);CHKERRQ(ierr); 1927072be85SIrina Sokolova for (i=0;i<mbs+1;i++) 1937072be85SIrina Sokolova ai[i] = a->i[i]+1; 1947072be85SIrina Sokolova for (i=0;i<nz;i++) 1957072be85SIrina Sokolova aj[i] = a->j[i]+1; 1967072be85SIrina Sokolova aa = a->a; 197017c2882SIrina Sokolova stat = mkl_sparse_x_create_bsr(&baijmkl->bsrA,SPARSE_INDEX_BASE_ONE,SPARSE_LAYOUT_COLUMN_MAJOR,mbs,nbs,bs,ai,ai+1,aj,aa);CHKERRMKL(stat); 1987072be85SIrina Sokolova baijmkl->ai1 = ai; 1997072be85SIrina Sokolova baijmkl->aj1 = aj; 2007072be85SIrina Sokolova #endif 201017c2882SIrina Sokolova stat = mkl_sparse_set_mv_hint(baijmkl->bsrA,SPARSE_OPERATION_NON_TRANSPOSE,baijmkl->descr,1000);CHKERRMKL(stat); 202017c2882SIrina Sokolova stat = mkl_sparse_set_memory_hint(baijmkl->bsrA,SPARSE_MEMORY_AGGRESSIVE);CHKERRMKL(stat); 203017c2882SIrina Sokolova stat = mkl_sparse_optimize(baijmkl->bsrA);CHKERRMKL(stat); 2047072be85SIrina Sokolova baijmkl->sparse_optimized = PETSC_TRUE; 2057072be85SIrina Sokolova } 2067072be85SIrina Sokolova PetscFunctionReturn(0); 2077072be85SIrina Sokolova } 2087072be85SIrina Sokolova 2097072be85SIrina Sokolova PetscErrorCode MatDuplicate_SeqBAIJMKL(Mat A, MatDuplicateOption op, Mat *M) 2107072be85SIrina Sokolova { 2117072be85SIrina Sokolova PetscErrorCode ierr; 2127072be85SIrina Sokolova Mat_SeqBAIJMKL *baijmkl; 2137072be85SIrina Sokolova Mat_SeqBAIJMKL *baijmkl_dest; 2147072be85SIrina Sokolova 2157072be85SIrina Sokolova PetscFunctionBegin; 2167072be85SIrina Sokolova ierr = MatDuplicate_SeqBAIJ(A,op,M);CHKERRQ(ierr); 2177072be85SIrina Sokolova baijmkl = (Mat_SeqBAIJMKL*) A->spptr; 21871bc03e0SIrina Sokolova ierr = PetscNewLog((*M),&baijmkl_dest);CHKERRQ(ierr); 21971bc03e0SIrina Sokolova (*M)->spptr = (void*)baijmkl_dest; 2207072be85SIrina Sokolova ierr = PetscMemcpy(baijmkl_dest,baijmkl,sizeof(Mat_SeqBAIJMKL));CHKERRQ(ierr); 2217072be85SIrina Sokolova baijmkl_dest->sparse_optimized = PETSC_FALSE; 2227072be85SIrina Sokolova ierr = MatSeqBAIJMKL_create_mkl_handle(A);CHKERRQ(ierr); 2237072be85SIrina Sokolova PetscFunctionReturn(0); 2247072be85SIrina Sokolova } 2257072be85SIrina Sokolova 2267072be85SIrina Sokolova PetscErrorCode MatMult_SeqBAIJMKL_SpMV2(Mat A,Vec xx,Vec yy) 2277072be85SIrina Sokolova { 2287072be85SIrina Sokolova Mat_SeqBAIJ *a = (Mat_SeqBAIJ*)A->data; 2297072be85SIrina Sokolova Mat_SeqBAIJMKL *baijmkl=(Mat_SeqBAIJMKL*)A->spptr; 2307072be85SIrina Sokolova const PetscScalar *x; 2317072be85SIrina Sokolova PetscScalar *y; 2327072be85SIrina Sokolova PetscErrorCode ierr; 2337072be85SIrina Sokolova sparse_status_t stat = SPARSE_STATUS_SUCCESS; 2347072be85SIrina Sokolova 2357072be85SIrina Sokolova PetscFunctionBegin; 2367072be85SIrina Sokolova /* If there are no nonzero entries, zero yy and return immediately. */ 2377072be85SIrina Sokolova if(!a->nz) { 2387072be85SIrina Sokolova PetscInt i; 2397072be85SIrina Sokolova PetscInt m=a->mbs*A->rmap->bs; 2407072be85SIrina Sokolova ierr = VecGetArray(yy,&y);CHKERRQ(ierr); 2417072be85SIrina Sokolova for (i=0; i<m; i++) { 2427072be85SIrina Sokolova y[i] = 0.0; 2437072be85SIrina Sokolova } 2447072be85SIrina Sokolova ierr = VecRestoreArray(yy,&y);CHKERRQ(ierr); 2457072be85SIrina Sokolova PetscFunctionReturn(0); 2467072be85SIrina Sokolova } 2477072be85SIrina Sokolova 2487072be85SIrina Sokolova ierr = VecGetArrayRead(xx,&x);CHKERRQ(ierr); 2497072be85SIrina Sokolova ierr = VecGetArray(yy,&y);CHKERRQ(ierr); 2507072be85SIrina Sokolova 2517072be85SIrina Sokolova /* In some cases, we get to this point without mkl_sparse_optimize() having been called, so we check and then call 2527072be85SIrina Sokolova * it if needed. Eventually, when everything in PETSc is properly updating the matrix state, we should probably 2537072be85SIrina Sokolova * take a "lazy" approach to creation/updating of the MKL matrix handle and plan to always do it here (when needed). */ 2547072be85SIrina Sokolova if (!baijmkl->sparse_optimized) { 255017c2882SIrina Sokolova ierr = MatSeqBAIJMKL_create_mkl_handle(A);CHKERRQ(ierr); 2567072be85SIrina Sokolova } 2577072be85SIrina Sokolova 2587072be85SIrina Sokolova /* Call MKL SpMV2 executor routine to do the MatMult. */ 259017c2882SIrina Sokolova stat = mkl_sparse_x_mv(SPARSE_OPERATION_NON_TRANSPOSE,1.0,baijmkl->bsrA,baijmkl->descr,x,0.0,y);CHKERRMKL(stat); 2607072be85SIrina Sokolova 2617072be85SIrina Sokolova ierr = PetscLogFlops(2.0*a->nz - a->nonzerorowcnt);CHKERRQ(ierr); 2627072be85SIrina Sokolova ierr = VecRestoreArrayRead(xx,&x);CHKERRQ(ierr); 2637072be85SIrina Sokolova ierr = VecRestoreArray(yy,&y);CHKERRQ(ierr); 2647072be85SIrina Sokolova PetscFunctionReturn(0); 2657072be85SIrina Sokolova } 2667072be85SIrina Sokolova 2677072be85SIrina Sokolova PetscErrorCode MatMultTranspose_SeqBAIJMKL_SpMV2(Mat A,Vec xx,Vec yy) 2687072be85SIrina Sokolova { 2697072be85SIrina Sokolova Mat_SeqBAIJ *a = (Mat_SeqBAIJ*)A->data; 2707072be85SIrina Sokolova Mat_SeqBAIJMKL *baijmkl = (Mat_SeqBAIJMKL*)A->spptr; 2717072be85SIrina Sokolova const PetscScalar *x; 2727072be85SIrina Sokolova PetscScalar *y; 2737072be85SIrina Sokolova PetscErrorCode ierr; 2747072be85SIrina Sokolova sparse_status_t stat; 2757072be85SIrina Sokolova 2767072be85SIrina Sokolova PetscFunctionBegin; 2777072be85SIrina Sokolova /* If there are no nonzero entries, zero yy and return immediately. */ 2787072be85SIrina Sokolova if(!a->nz) { 2797072be85SIrina Sokolova PetscInt i; 2807072be85SIrina Sokolova PetscInt n=a->nbs; 2817072be85SIrina Sokolova ierr = VecGetArray(yy,&y);CHKERRQ(ierr); 2827072be85SIrina Sokolova for (i=0; i<n; i++) { 2837072be85SIrina Sokolova y[i] = 0.0; 2847072be85SIrina Sokolova } 2857072be85SIrina Sokolova ierr = VecRestoreArray(yy,&y);CHKERRQ(ierr); 2867072be85SIrina Sokolova PetscFunctionReturn(0); 2877072be85SIrina Sokolova } 2887072be85SIrina Sokolova 2897072be85SIrina Sokolova ierr = VecGetArrayRead(xx,&x);CHKERRQ(ierr); 2907072be85SIrina Sokolova ierr = VecGetArray(yy,&y);CHKERRQ(ierr); 2917072be85SIrina Sokolova 2927072be85SIrina Sokolova /* In some cases, we get to this point without mkl_sparse_optimize() having been called, so we check and then call 2937072be85SIrina Sokolova * it if needed. Eventually, when everything in PETSc is properly updating the matrix state, we should probably 2947072be85SIrina Sokolova * take a "lazy" approach to creation/updating of the MKL matrix handle and plan to always do it here (when needed). */ 2957072be85SIrina Sokolova if (!baijmkl->sparse_optimized) { 296017c2882SIrina Sokolova ierr = MatSeqBAIJMKL_create_mkl_handle(A);CHKERRQ(ierr); 2977072be85SIrina Sokolova } 2987072be85SIrina Sokolova 2997072be85SIrina Sokolova /* Call MKL SpMV2 executor routine to do the MatMultTranspose. */ 300017c2882SIrina Sokolova stat = mkl_sparse_x_mv(SPARSE_OPERATION_TRANSPOSE,1.0,baijmkl->bsrA,baijmkl->descr,x,0.0,y);CHKERRMKL(stat); 3017072be85SIrina Sokolova 3027072be85SIrina Sokolova ierr = PetscLogFlops(2.0*a->nz - a->nonzerorowcnt);CHKERRQ(ierr); 3037072be85SIrina Sokolova ierr = VecRestoreArrayRead(xx,&x);CHKERRQ(ierr); 3047072be85SIrina Sokolova ierr = VecRestoreArray(yy,&y);CHKERRQ(ierr); 3057072be85SIrina Sokolova PetscFunctionReturn(0); 3067072be85SIrina Sokolova } 3077072be85SIrina Sokolova 3087072be85SIrina Sokolova PetscErrorCode MatMultAdd_SeqBAIJMKL_SpMV2(Mat A,Vec xx,Vec yy,Vec zz) 3097072be85SIrina Sokolova { 3107072be85SIrina Sokolova Mat_SeqBAIJ *a = (Mat_SeqBAIJ*)A->data; 3117072be85SIrina Sokolova Mat_SeqBAIJMKL *baijmkl = (Mat_SeqBAIJMKL*)A->spptr; 3127072be85SIrina Sokolova const PetscScalar *x; 3137072be85SIrina Sokolova PetscScalar *y,*z; 3147072be85SIrina Sokolova PetscErrorCode ierr; 3157072be85SIrina Sokolova PetscInt m=a->mbs*A->rmap->bs; 3167072be85SIrina Sokolova PetscInt i; 3177072be85SIrina Sokolova 3187072be85SIrina Sokolova sparse_status_t stat = SPARSE_STATUS_SUCCESS; 3197072be85SIrina Sokolova 3207072be85SIrina Sokolova PetscFunctionBegin; 3217072be85SIrina Sokolova /* If there are no nonzero entries, set zz = yy and return immediately. */ 3227072be85SIrina Sokolova if(!a->nz) { 3237072be85SIrina Sokolova PetscInt i; 3247072be85SIrina Sokolova ierr = VecGetArrayPair(yy,zz,&y,&z);CHKERRQ(ierr); 3257072be85SIrina Sokolova for (i=0; i<m; i++) { 3267072be85SIrina Sokolova z[i] = y[i]; 3277072be85SIrina Sokolova } 3287072be85SIrina Sokolova ierr = VecRestoreArrayPair(yy,zz,&y,&z);CHKERRQ(ierr); 3297072be85SIrina Sokolova PetscFunctionReturn(0); 3307072be85SIrina Sokolova } 3317072be85SIrina Sokolova 3327072be85SIrina Sokolova ierr = VecGetArrayRead(xx,&x);CHKERRQ(ierr); 3337072be85SIrina Sokolova ierr = VecGetArrayPair(yy,zz,&y,&z);CHKERRQ(ierr); 3347072be85SIrina Sokolova 3357072be85SIrina Sokolova /* In some cases, we get to this point without mkl_sparse_optimize() having been called, so we check and then call 3367072be85SIrina Sokolova * it if needed. Eventually, when everything in PETSc is properly updating the matrix state, we should probably 3377072be85SIrina Sokolova * take a "lazy" approach to creation/updating of the MKL matrix handle and plan to always do it here (when needed). */ 3387072be85SIrina Sokolova if (!baijmkl->sparse_optimized) { 339017c2882SIrina Sokolova ierr = MatSeqBAIJMKL_create_mkl_handle(A);CHKERRQ(ierr); 3407072be85SIrina Sokolova } 3417072be85SIrina Sokolova 3427072be85SIrina Sokolova /* Call MKL sparse BLAS routine to do the MatMult. */ 3437072be85SIrina Sokolova if (zz == yy) { 3447072be85SIrina Sokolova /* If zz and yy are the same vector, we can use mkl_sparse_x_mv, which calculates y = alpha*A*x + beta*y, 3457072be85SIrina Sokolova * with alpha and beta both set to 1.0. */ 346017c2882SIrina Sokolova stat = mkl_sparse_x_mv(SPARSE_OPERATION_NON_TRANSPOSE,1.0,baijmkl->bsrA,baijmkl->descr,x,1.0,z);CHKERRMKL(stat); 3477072be85SIrina Sokolova } else { 3487072be85SIrina Sokolova /* zz and yy are different vectors, so we call mkl_sparse_x_mv with alpha=1.0 and beta=0.0, and then 3497072be85SIrina Sokolova * we add the contents of vector yy to the result; MKL sparse BLAS does not have a MatMultAdd equivalent. */ 350017c2882SIrina Sokolova stat = mkl_sparse_x_mv(SPARSE_OPERATION_NON_TRANSPOSE,1.0,baijmkl->bsrA,baijmkl->descr,x,0.0,z);CHKERRMKL(stat); 3517072be85SIrina Sokolova for (i=0; i<m; i++) { 3527072be85SIrina Sokolova z[i] += y[i]; 3537072be85SIrina Sokolova } 3547072be85SIrina Sokolova } 3557072be85SIrina Sokolova 3567072be85SIrina Sokolova ierr = PetscLogFlops(2.0*a->nz);CHKERRQ(ierr); 3577072be85SIrina Sokolova ierr = VecRestoreArrayRead(xx,&x);CHKERRQ(ierr); 3587072be85SIrina Sokolova ierr = VecRestoreArrayPair(yy,zz,&y,&z);CHKERRQ(ierr); 3597072be85SIrina Sokolova PetscFunctionReturn(0); 3607072be85SIrina Sokolova } 3617072be85SIrina Sokolova 3627072be85SIrina Sokolova PetscErrorCode MatMultTransposeAdd_SeqBAIJMKL_SpMV2(Mat A,Vec xx,Vec yy,Vec zz) 3637072be85SIrina Sokolova { 3647072be85SIrina Sokolova Mat_SeqBAIJ *a = (Mat_SeqBAIJ*)A->data; 3657072be85SIrina Sokolova Mat_SeqBAIJMKL *baijmkl = (Mat_SeqBAIJMKL*)A->spptr; 3667072be85SIrina Sokolova const PetscScalar *x; 3677072be85SIrina Sokolova PetscScalar *y,*z; 3687072be85SIrina Sokolova PetscErrorCode ierr; 3697072be85SIrina Sokolova PetscInt n=a->nbs*A->rmap->bs; 3707072be85SIrina Sokolova PetscInt i; 3717072be85SIrina Sokolova /* Variables not in MatMultTransposeAdd_SeqBAIJ. */ 3727072be85SIrina Sokolova sparse_status_t stat = SPARSE_STATUS_SUCCESS; 3737072be85SIrina Sokolova 3747072be85SIrina Sokolova PetscFunctionBegin; 3757072be85SIrina Sokolova /* If there are no nonzero entries, set zz = yy and return immediately. */ 3767072be85SIrina Sokolova if(!a->nz) { 3777072be85SIrina Sokolova PetscInt i; 3787072be85SIrina Sokolova ierr = VecGetArrayPair(yy,zz,&y,&z);CHKERRQ(ierr); 3797072be85SIrina Sokolova for (i=0; i<n; i++) { 3807072be85SIrina Sokolova z[i] = y[i]; 3817072be85SIrina Sokolova } 3827072be85SIrina Sokolova ierr = VecRestoreArrayPair(yy,zz,&y,&z);CHKERRQ(ierr); 3837072be85SIrina Sokolova PetscFunctionReturn(0); 3847072be85SIrina Sokolova } 3857072be85SIrina Sokolova 3867072be85SIrina Sokolova ierr = VecGetArrayRead(xx,&x);CHKERRQ(ierr); 3877072be85SIrina Sokolova ierr = VecGetArrayPair(yy,zz,&y,&z);CHKERRQ(ierr); 3887072be85SIrina Sokolova 3897072be85SIrina Sokolova /* In some cases, we get to this point without mkl_sparse_optimize() having been called, so we check and then call 3907072be85SIrina Sokolova * it if needed. Eventually, when everything in PETSc is properly updating the matrix state, we should probably 3917072be85SIrina Sokolova * take a "lazy" approach to creation/updating of the MKL matrix handle and plan to always do it here (when needed). */ 3927072be85SIrina Sokolova if (!baijmkl->sparse_optimized) { 393017c2882SIrina Sokolova ierr = MatSeqBAIJMKL_create_mkl_handle(A);CHKERRQ(ierr); 3947072be85SIrina Sokolova } 3957072be85SIrina Sokolova 3967072be85SIrina Sokolova /* Call MKL sparse BLAS routine to do the MatMult. */ 3977072be85SIrina Sokolova if (zz == yy) { 3987072be85SIrina Sokolova /* If zz and yy are the same vector, we can use mkl_sparse_x_mv, which calculates y = alpha*A*x + beta*y, 3997072be85SIrina Sokolova * with alpha and beta both set to 1.0. */ 400017c2882SIrina Sokolova stat = mkl_sparse_x_mv(SPARSE_OPERATION_TRANSPOSE,1.0,baijmkl->bsrA,baijmkl->descr,x,1.0,z);CHKERRMKL(stat); 4017072be85SIrina Sokolova } else { 4027072be85SIrina Sokolova /* zz and yy are different vectors, so we call mkl_sparse_x_mv with alpha=1.0 and beta=0.0, and then 4037072be85SIrina Sokolova * we add the contents of vector yy to the result; MKL sparse BLAS does not have a MatMultAdd equivalent. */ 404017c2882SIrina Sokolova stat = mkl_sparse_x_mv(SPARSE_OPERATION_TRANSPOSE,1.0,baijmkl->bsrA,baijmkl->descr,x,0.0,z);CHKERRMKL(stat); 4057072be85SIrina Sokolova for (i=0; i<n; i++) { 4067072be85SIrina Sokolova z[i] += y[i]; 4077072be85SIrina Sokolova } 4087072be85SIrina Sokolova } 4097072be85SIrina Sokolova 4107072be85SIrina Sokolova ierr = PetscLogFlops(2.0*a->nz);CHKERRQ(ierr); 4117072be85SIrina Sokolova ierr = VecRestoreArrayRead(xx,&x);CHKERRQ(ierr); 4127072be85SIrina Sokolova ierr = VecRestoreArrayPair(yy,zz,&y,&z);CHKERRQ(ierr); 4137072be85SIrina Sokolova PetscFunctionReturn(0); 4147072be85SIrina Sokolova } 4157072be85SIrina Sokolova 4167072be85SIrina Sokolova PetscErrorCode MatScale_SeqBAIJMKL(Mat inA,PetscScalar alpha) 4177072be85SIrina Sokolova { 4187072be85SIrina Sokolova PetscErrorCode ierr; 4197072be85SIrina Sokolova 4207072be85SIrina Sokolova PetscFunctionBegin; 4217072be85SIrina Sokolova ierr = MatScale_SeqBAIJ(inA,alpha);CHKERRQ(ierr); 4227072be85SIrina Sokolova ierr = MatSeqBAIJMKL_create_mkl_handle(inA);CHKERRQ(ierr); 4237072be85SIrina Sokolova PetscFunctionReturn(0); 4247072be85SIrina Sokolova } 4257072be85SIrina Sokolova 4267072be85SIrina Sokolova PetscErrorCode MatDiagonalScale_SeqBAIJMKL(Mat A,Vec ll,Vec rr) 4277072be85SIrina Sokolova { 4287072be85SIrina Sokolova PetscErrorCode ierr; 4297072be85SIrina Sokolova 4307072be85SIrina Sokolova PetscFunctionBegin; 4317072be85SIrina Sokolova ierr = MatDiagonalScale_SeqBAIJ(A,ll,rr);CHKERRQ(ierr); 4327072be85SIrina Sokolova ierr = MatSeqBAIJMKL_create_mkl_handle(A);CHKERRQ(ierr); 4337072be85SIrina Sokolova PetscFunctionReturn(0); 4347072be85SIrina Sokolova } 4357072be85SIrina Sokolova 4367072be85SIrina Sokolova PetscErrorCode MatAXPY_SeqBAIJMKL(Mat Y,PetscScalar a,Mat X,MatStructure str) 4377072be85SIrina Sokolova { 4387072be85SIrina Sokolova PetscErrorCode ierr; 4397072be85SIrina Sokolova 4407072be85SIrina Sokolova PetscFunctionBegin; 4417072be85SIrina Sokolova ierr = MatAXPY_SeqBAIJ(Y,a,X,str);CHKERRQ(ierr); 4427072be85SIrina Sokolova if (str == SAME_NONZERO_PATTERN) { 4437072be85SIrina Sokolova /* MatAssemblyEnd() is not called if SAME_NONZERO_PATTERN, so we need to force update of the MKL matrix handle. */ 4447072be85SIrina Sokolova ierr = MatSeqBAIJMKL_create_mkl_handle(Y);CHKERRQ(ierr); 4457072be85SIrina Sokolova } 4467072be85SIrina Sokolova PetscFunctionReturn(0); 4477072be85SIrina Sokolova } 4487072be85SIrina Sokolova /* MatConvert_SeqBAIJ_SeqBAIJMKL converts a SeqBAIJ matrix into a 4497072be85SIrina Sokolova * SeqBAIJMKL matrix. This routine is called by the MatCreate_SeqMKLBAIJ() 4507072be85SIrina Sokolova * routine, but can also be used to convert an assembled SeqBAIJ matrix 4517072be85SIrina Sokolova * into a SeqBAIJMKL one. */ 4527072be85SIrina Sokolova PETSC_INTERN PetscErrorCode MatConvert_SeqBAIJ_SeqBAIJMKL(Mat A,MatType type,MatReuse reuse,Mat *newmat) 4537072be85SIrina Sokolova { 4547072be85SIrina Sokolova PetscErrorCode ierr; 4557072be85SIrina Sokolova Mat B = *newmat; 4567072be85SIrina Sokolova Mat_SeqBAIJMKL *baijmkl; 4577072be85SIrina Sokolova PetscBool sametype; 4587072be85SIrina Sokolova 4597072be85SIrina Sokolova PetscFunctionBegin; 4607072be85SIrina Sokolova if (reuse == MAT_INITIAL_MATRIX) { 4617072be85SIrina Sokolova ierr = MatDuplicate(A,MAT_COPY_VALUES,&B);CHKERRQ(ierr); 4627072be85SIrina Sokolova } 4637072be85SIrina Sokolova 4647072be85SIrina Sokolova ierr = PetscObjectTypeCompare((PetscObject)A,type,&sametype);CHKERRQ(ierr); 4657072be85SIrina Sokolova if (sametype) PetscFunctionReturn(0); 4667072be85SIrina Sokolova 4677072be85SIrina Sokolova ierr = PetscNewLog(B,&baijmkl);CHKERRQ(ierr); 4687072be85SIrina Sokolova B->spptr = (void*)baijmkl; 4697072be85SIrina Sokolova 4707072be85SIrina Sokolova /* Set function pointers for methods that we inherit from BAIJ but override. 4717072be85SIrina Sokolova * We also parse some command line options below, since those determine some of the methods we point to. */ 4727072be85SIrina Sokolova B->ops->assemblyend = MatAssemblyEnd_SeqBAIJMKL; 4737072be85SIrina Sokolova 4747072be85SIrina Sokolova baijmkl->sparse_optimized = PETSC_FALSE; 4757072be85SIrina Sokolova 4767072be85SIrina Sokolova ierr = PetscObjectComposeFunction((PetscObject)B,"MatScale_SeqBAIJMKL_C",MatScale_SeqBAIJMKL);CHKERRQ(ierr); 4777072be85SIrina Sokolova ierr = PetscObjectComposeFunction((PetscObject)B,"MatConvert_seqbaijmkl_seqbaij_C",MatConvert_SeqBAIJMKL_SeqBAIJ);CHKERRQ(ierr); 4787072be85SIrina Sokolova 4797072be85SIrina Sokolova ierr = PetscObjectChangeTypeName((PetscObject)B,MATSEQBAIJMKL);CHKERRQ(ierr); 4807072be85SIrina Sokolova *newmat = B; 4817072be85SIrina Sokolova PetscFunctionReturn(0); 4827072be85SIrina Sokolova } 4834d6dccb5SIrina Sokolova PetscErrorCode MatAssemblyEnd_SeqBAIJMKL(Mat A, MatAssemblyType mode) 4844d6dccb5SIrina Sokolova { 4854d6dccb5SIrina Sokolova PetscErrorCode ierr; 4864d6dccb5SIrina Sokolova PetscFunctionBegin; 4874d6dccb5SIrina Sokolova if (mode == MAT_FLUSH_ASSEMBLY) PetscFunctionReturn(0); 4884d6dccb5SIrina Sokolova ierr = MatAssemblyEnd_SeqBAIJ(A, mode);CHKERRQ(ierr); 4894d6dccb5SIrina Sokolova ierr = MatSeqBAIJMKL_create_mkl_handle(A);CHKERRQ(ierr); 4904d6dccb5SIrina Sokolova A->ops->destroy = MatDestroy_SeqBAIJMKL; 4914d6dccb5SIrina Sokolova A->ops->mult = MatMult_SeqBAIJMKL_SpMV2; 4924d6dccb5SIrina Sokolova A->ops->multtranspose = MatMultTranspose_SeqBAIJMKL_SpMV2; 4934d6dccb5SIrina Sokolova A->ops->multadd = MatMultAdd_SeqBAIJMKL_SpMV2; 4944d6dccb5SIrina Sokolova A->ops->multtransposeadd = MatMultTransposeAdd_SeqBAIJMKL_SpMV2; 4954d6dccb5SIrina Sokolova A->ops->scale = MatScale_SeqBAIJMKL; 4964d6dccb5SIrina Sokolova A->ops->diagonalscale = MatDiagonalScale_SeqBAIJMKL; 4974d6dccb5SIrina Sokolova A->ops->axpy = MatAXPY_SeqBAIJMKL; 4984d6dccb5SIrina Sokolova A->ops->duplicate = MatDuplicate_SeqBAIJMKL; 4994d6dccb5SIrina Sokolova PetscFunctionReturn(0); 5004d6dccb5SIrina Sokolova } 5017072be85SIrina Sokolova #endif /* PETSC_HAVE_MKL_SPARSE_OPTIMIZE */ 5027072be85SIrina Sokolova /*@C 5037072be85SIrina Sokolova MatCreateSeqBAIJMKL - Creates a sparse matrix of type SEQBAIJMKL. 5047072be85SIrina Sokolova This type inherits from BAIJ and is largely identical, but uses sparse BLAS 5057072be85SIrina Sokolova routines from Intel MKL whenever possible. 5067072be85SIrina Sokolova MatMult, MatMultAdd, MatMultTranspose, and MatMultTransposeAdd 5077072be85SIrina Sokolova operations are currently supported. 5087072be85SIrina Sokolova If the installed version of MKL supports the "SpMV2" sparse 5097072be85SIrina Sokolova inspector-executor routines, then those are used by default. 5107072be85SIrina Sokolova Default PETSc kernels are used otherwise. 5117072be85SIrina Sokolova 5127072be85SIrina Sokolova Input Parameters: 5137072be85SIrina Sokolova + comm - MPI communicator, set to PETSC_COMM_SELF 5147072be85SIrina Sokolova . bs - size of block, the blocks are ALWAYS square. One can use MatSetBlockSizes() to set a different row and column blocksize but the row 5157072be85SIrina Sokolova blocksize always defines the size of the blocks. The column blocksize sets the blocksize of the vectors obtained with MatCreateVecs() 5167072be85SIrina Sokolova . m - number of rows 5177072be85SIrina Sokolova . n - number of columns 5187072be85SIrina Sokolova . nz - number of nonzero blocks per block row (same for all rows) 5197072be85SIrina Sokolova - nnz - array containing the number of nonzero blocks in the various block rows 5207072be85SIrina Sokolova (possibly different for each block row) or NULL 5217072be85SIrina Sokolova 5227072be85SIrina Sokolova 5237072be85SIrina Sokolova Output Parameter: 5247072be85SIrina Sokolova . A - the matrix 5257072be85SIrina Sokolova 5267072be85SIrina Sokolova It is recommended that one use the MatCreate(), MatSetType() and/or MatSetFromOptions(), 5277072be85SIrina Sokolova MatXXXXSetPreallocation() paradgm instead of this routine directly. 5287072be85SIrina Sokolova [MatXXXXSetPreallocation() is, for example, MatSeqAIJSetPreallocation] 5297072be85SIrina Sokolova 5307072be85SIrina Sokolova Options Database Keys: 5317072be85SIrina Sokolova . -mat_no_unroll - uses code that does not unroll the loops in the 5327072be85SIrina Sokolova block calculations (much slower) 5337072be85SIrina Sokolova . -mat_block_size - size of the blocks to use 5347072be85SIrina Sokolova 5357072be85SIrina Sokolova Level: intermediate 5367072be85SIrina Sokolova 5377072be85SIrina Sokolova Notes: 5387072be85SIrina Sokolova The number of rows and columns must be divisible by blocksize. 5397072be85SIrina Sokolova 5407072be85SIrina Sokolova If the nnz parameter is given then the nz parameter is ignored 5417072be85SIrina Sokolova 5427072be85SIrina Sokolova A nonzero block is any block that as 1 or more nonzeros in it 5437072be85SIrina Sokolova 5447072be85SIrina Sokolova The block AIJ format is fully compatible with standard Fortran 77 5457072be85SIrina Sokolova storage. That is, the stored row and column indices can begin at 5467072be85SIrina Sokolova either one (as in Fortran) or zero. See the users' manual for details. 5477072be85SIrina Sokolova 5487072be85SIrina Sokolova Specify the preallocated storage with either nz or nnz (not both). 5497072be85SIrina Sokolova Set nz=PETSC_DEFAULT and nnz=NULL for PETSc to control dynamic memory 5507072be85SIrina Sokolova allocation. See Users-Manual: ch_mat for details. 5517072be85SIrina Sokolova matrices. 5527072be85SIrina Sokolova 5537072be85SIrina Sokolova .seealso: MatCreate(), MatCreateSeqAIJ(), MatSetValues(), MatCreateBAIJ() 5547072be85SIrina Sokolova 5557072be85SIrina Sokolova @*/ 5567072be85SIrina Sokolova PetscErrorCode MatCreateSeqBAIJMKL(MPI_Comm comm,PetscInt bs,PetscInt m,PetscInt n,PetscInt nz,const PetscInt nnz[],Mat *A) 5577072be85SIrina Sokolova { 5587072be85SIrina Sokolova PetscErrorCode ierr; 5597072be85SIrina Sokolova 5607072be85SIrina Sokolova PetscFunctionBegin; 5617072be85SIrina Sokolova ierr = MatCreate(comm,A);CHKERRQ(ierr); 5627072be85SIrina Sokolova ierr = MatSetSizes(*A,m,n,m,n);CHKERRQ(ierr); 5637072be85SIrina Sokolova #ifdef PETSC_HAVE_MKL_SPARSE_OPTIMIZE 5647072be85SIrina Sokolova ierr = MatSetType(*A,MATSEQBAIJMKL);CHKERRQ(ierr); 5657072be85SIrina Sokolova ierr = MatSeqBAIJSetPreallocation_SeqBAIJ(*A,bs,nz,(PetscInt*)nnz);CHKERRQ(ierr); 5667072be85SIrina Sokolova #else 5677072be85SIrina Sokolova ierr = PetscInfo(A,"MKL baij routines are not supported for used version of MKL. Using PETSc default routines. \n Please use version of MKL 11.3 and higher. \n"); 5687072be85SIrina Sokolova ierr = MatSetType(*A,MATSEQBAIJ);CHKERRQ(ierr); 5697072be85SIrina Sokolova ierr = MatSeqBAIJSetPreallocation(*A,bs,nz,(PetscInt*)nnz);CHKERRQ(ierr); 5707072be85SIrina Sokolova #endif 5717072be85SIrina Sokolova PetscFunctionReturn(0); 5727072be85SIrina Sokolova } 5737072be85SIrina Sokolova PETSC_EXTERN PetscErrorCode MatCreate_SeqBAIJMKL(Mat A) 5747072be85SIrina Sokolova { 5757072be85SIrina Sokolova PetscErrorCode ierr; 5767072be85SIrina Sokolova 5777072be85SIrina Sokolova PetscFunctionBegin; 5787072be85SIrina Sokolova ierr = MatSetType(A,MATSEQBAIJ);CHKERRQ(ierr); 5797072be85SIrina Sokolova #ifdef PETSC_HAVE_MKL_SPARSE_OPTIMIZE 5807072be85SIrina Sokolova ierr = MatConvert_SeqBAIJ_SeqBAIJMKL(A,MATSEQBAIJMKL,MAT_INPLACE_MATRIX,&A);CHKERRQ(ierr); 5817072be85SIrina Sokolova #else 5827072be85SIrina Sokolova ierr = PetscInfo(A,"MKL baij routines are not supported for used version of MKL. Using PETSc default routines. \n Please use version of MKL 11.3 and higher. \n"); 5837072be85SIrina Sokolova #endif 5847072be85SIrina Sokolova PetscFunctionReturn(0); 5857072be85SIrina Sokolova } 586