1f17f7ee2SSatish Balay #include <petsc/private/matimpl.h> 2f17f7ee2SSatish Balay #include <petsc/private/vecimpl.h> 3f17f7ee2SSatish Balay #include <petscsf.h> 4f17f7ee2SSatish Balay #if defined(PETSC_HAVE_CUDA) 5f17f7ee2SSatish Balay #include <thrust/for_each.h> 6f17f7ee2SSatish Balay #include <thrust/device_vector.h> 7f17f7ee2SSatish Balay #include <thrust/execution_policy.h> 8f17f7ee2SSatish Balay #endif 9f17f7ee2SSatish Balay 10d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscSFGetVectorSF(PetscSF sf, PetscInt nv, PetscInt ldr, PetscInt ldl, PetscSF *vsf) 11d71ae5a4SJacob Faibussowitsch { 12f17f7ee2SSatish Balay PetscSF rankssf; 13f17f7ee2SSatish Balay const PetscSFNode *iremote; 14f17f7ee2SSatish Balay PetscSFNode *viremote, *rremotes; 15f17f7ee2SSatish Balay const PetscInt *ilocal; 16f17f7ee2SSatish Balay PetscInt *vilocal = NULL, *ldrs; 17f17f7ee2SSatish Balay const PetscMPIInt *ranks; 18f17f7ee2SSatish Balay PetscMPIInt *sranks; 19f17f7ee2SSatish Balay PetscInt nranks, nr, nl, vnr, vnl, i, v, j, maxl; 20f17f7ee2SSatish Balay MPI_Comm comm; 21f17f7ee2SSatish Balay 22f17f7ee2SSatish Balay PetscFunctionBegin; 23f17f7ee2SSatish Balay PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1); 24f17f7ee2SSatish Balay PetscValidLogicalCollectiveInt(sf, nv, 2); 25f17f7ee2SSatish Balay PetscValidPointer(vsf, 5); 26f17f7ee2SSatish Balay if (nv == 1) { 27f17f7ee2SSatish Balay PetscCall(PetscObjectReference((PetscObject)sf)); 28f17f7ee2SSatish Balay *vsf = sf; 29*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 30f17f7ee2SSatish Balay } 31f17f7ee2SSatish Balay PetscCall(PetscObjectGetComm((PetscObject)sf, &comm)); 32f17f7ee2SSatish Balay PetscCall(PetscSFGetGraph(sf, &nr, &nl, &ilocal, &iremote)); 33f17f7ee2SSatish Balay PetscCall(PetscSFGetLeafRange(sf, NULL, &maxl)); 34f17f7ee2SSatish Balay maxl += 1; 35f17f7ee2SSatish Balay if (ldl == PETSC_DECIDE) ldl = maxl; 36f17f7ee2SSatish Balay if (ldr == PETSC_DECIDE) ldr = nr; 37f17f7ee2SSatish Balay PetscCheck(ldr >= nr, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid leading dimension %" PetscInt_FMT " < %" PetscInt_FMT, ldr, nr); 38f17f7ee2SSatish Balay PetscCheck(ldl >= maxl, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid leading dimension %" PetscInt_FMT " < %" PetscInt_FMT, ldl, maxl); 39f17f7ee2SSatish Balay vnr = nr * nv; 40f17f7ee2SSatish Balay vnl = nl * nv; 41f17f7ee2SSatish Balay PetscCall(PetscMalloc1(vnl, &viremote)); 42f17f7ee2SSatish Balay if (ilocal) PetscCall(PetscMalloc1(vnl, &vilocal)); 43f17f7ee2SSatish Balay 44f17f7ee2SSatish Balay /* TODO: Should this special SF be available, e.g. 45f17f7ee2SSatish Balay PetscSFGetRanksSF or similar? */ 46f17f7ee2SSatish Balay PetscCall(PetscSFGetRootRanks(sf, &nranks, &ranks, NULL, NULL, NULL)); 47f17f7ee2SSatish Balay PetscCall(PetscMalloc1(nranks, &sranks)); 48f17f7ee2SSatish Balay PetscCall(PetscArraycpy(sranks, ranks, nranks)); 49f17f7ee2SSatish Balay PetscCall(PetscSortMPIInt(nranks, sranks)); 50f17f7ee2SSatish Balay PetscCall(PetscMalloc1(nranks, &rremotes)); 51f17f7ee2SSatish Balay for (i = 0; i < nranks; i++) { 52f17f7ee2SSatish Balay rremotes[i].rank = sranks[i]; 53f17f7ee2SSatish Balay rremotes[i].index = 0; 54f17f7ee2SSatish Balay } 55f17f7ee2SSatish Balay PetscCall(PetscSFDuplicate(sf, PETSCSF_DUPLICATE_CONFONLY, &rankssf)); 56f17f7ee2SSatish Balay PetscCall(PetscSFSetGraph(rankssf, 1, nranks, NULL, PETSC_OWN_POINTER, rremotes, PETSC_OWN_POINTER)); 57f17f7ee2SSatish Balay PetscCall(PetscMalloc1(nranks, &ldrs)); 58f17f7ee2SSatish Balay PetscCall(PetscSFBcastBegin(rankssf, MPIU_INT, &ldr, ldrs, MPI_REPLACE)); 59f17f7ee2SSatish Balay PetscCall(PetscSFBcastEnd(rankssf, MPIU_INT, &ldr, ldrs, MPI_REPLACE)); 60f17f7ee2SSatish Balay PetscCall(PetscSFDestroy(&rankssf)); 61f17f7ee2SSatish Balay 62f17f7ee2SSatish Balay j = -1; 63f17f7ee2SSatish Balay for (i = 0; i < nl; i++) { 64f17f7ee2SSatish Balay const PetscInt r = iremote[i].rank; 65f17f7ee2SSatish Balay const PetscInt ii = iremote[i].index; 66f17f7ee2SSatish Balay 6748a46eb9SPierre Jolivet if (j < 0 || sranks[j] != r) PetscCall(PetscFindMPIInt(r, nranks, sranks, &j)); 68f17f7ee2SSatish Balay PetscCheck(j >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unable to locate neighbor rank %" PetscInt_FMT, r); 69f17f7ee2SSatish Balay for (v = 0; v < nv; v++) { 70f17f7ee2SSatish Balay viremote[v * nl + i].rank = r; 71f17f7ee2SSatish Balay viremote[v * nl + i].index = v * ldrs[j] + ii; 72f17f7ee2SSatish Balay if (ilocal) vilocal[v * nl + i] = v * ldl + ilocal[i]; 73f17f7ee2SSatish Balay } 74f17f7ee2SSatish Balay } 75f17f7ee2SSatish Balay PetscCall(PetscFree(sranks)); 76f17f7ee2SSatish Balay PetscCall(PetscFree(ldrs)); 77f17f7ee2SSatish Balay PetscCall(PetscSFCreate(comm, vsf)); 78f17f7ee2SSatish Balay PetscCall(PetscSFSetGraph(*vsf, vnr, vnl, vilocal, PETSC_OWN_POINTER, viremote, PETSC_OWN_POINTER)); 79*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 80f17f7ee2SSatish Balay } 81f17f7ee2SSatish Balay 82d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatDenseGetH2OpusVectorSF(Mat A, PetscSF h2sf, PetscSF *osf) 83d71ae5a4SJacob Faibussowitsch { 84f17f7ee2SSatish Balay PetscSF asf; 85f17f7ee2SSatish Balay 86f17f7ee2SSatish Balay PetscFunctionBegin; 87f17f7ee2SSatish Balay PetscValidHeaderSpecific(A, MAT_CLASSID, 1); 88f17f7ee2SSatish Balay PetscValidHeaderSpecific(h2sf, PETSCSF_CLASSID, 2); 89f17f7ee2SSatish Balay PetscValidPointer(osf, 3); 90f17f7ee2SSatish Balay PetscCall(PetscObjectQuery((PetscObject)A, "_math2opus_vectorsf", (PetscObject *)&asf)); 91f17f7ee2SSatish Balay if (!asf) { 92f17f7ee2SSatish Balay PetscInt lda; 93f17f7ee2SSatish Balay 94f17f7ee2SSatish Balay PetscCall(MatDenseGetLDA(A, &lda)); 95f17f7ee2SSatish Balay PetscCall(PetscSFGetVectorSF(h2sf, A->cmap->N, lda, PETSC_DECIDE, &asf)); 96f17f7ee2SSatish Balay PetscCall(PetscObjectCompose((PetscObject)A, "_math2opus_vectorsf", (PetscObject)asf)); 97f17f7ee2SSatish Balay PetscCall(PetscObjectDereference((PetscObject)asf)); 98f17f7ee2SSatish Balay } 99f17f7ee2SSatish Balay *osf = asf; 100*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 101f17f7ee2SSatish Balay } 102f17f7ee2SSatish Balay 103f17f7ee2SSatish Balay #if defined(PETSC_HAVE_CUDA) 1049371c9d4SSatish Balay struct SignVector_Functor { 105f17f7ee2SSatish Balay const PetscScalar *v; 106f17f7ee2SSatish Balay PetscScalar *s; 107f17f7ee2SSatish Balay SignVector_Functor(const PetscScalar *_v, PetscScalar *_s) : v(_v), s(_s) { } 108f17f7ee2SSatish Balay 1099371c9d4SSatish Balay __host__ __device__ void operator()(PetscInt i) { s[i] = (v[i] < 0 ? -1 : 1); } 110f17f7ee2SSatish Balay }; 111f17f7ee2SSatish Balay #endif 112f17f7ee2SSatish Balay 113d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode VecSign(Vec v, Vec s) 114d71ae5a4SJacob Faibussowitsch { 115f17f7ee2SSatish Balay const PetscScalar *av; 116f17f7ee2SSatish Balay PetscScalar *as; 117f17f7ee2SSatish Balay PetscInt i, n; 118f17f7ee2SSatish Balay #if defined(PETSC_HAVE_CUDA) 119f17f7ee2SSatish Balay PetscBool viscuda, siscuda; 120f17f7ee2SSatish Balay #endif 121f17f7ee2SSatish Balay 122f17f7ee2SSatish Balay PetscFunctionBegin; 123f17f7ee2SSatish Balay PetscValidHeaderSpecific(v, VEC_CLASSID, 1); 124f17f7ee2SSatish Balay PetscValidHeaderSpecific(s, VEC_CLASSID, 2); 125f17f7ee2SSatish Balay PetscCall(VecGetLocalSize(s, &n)); 126f17f7ee2SSatish Balay PetscCall(VecGetLocalSize(v, &i)); 127f17f7ee2SSatish Balay PetscCheck(i == n, PETSC_COMM_SELF, PETSC_ERR_SUP, "Invalid local sizes %" PetscInt_FMT " != %" PetscInt_FMT, i, n); 128f17f7ee2SSatish Balay #if defined(PETSC_HAVE_CUDA) 129f17f7ee2SSatish Balay PetscCall(PetscObjectTypeCompareAny((PetscObject)v, &viscuda, VECSEQCUDA, VECMPICUDA, "")); 130f17f7ee2SSatish Balay PetscCall(PetscObjectTypeCompareAny((PetscObject)s, &siscuda, VECSEQCUDA, VECMPICUDA, "")); 131f17f7ee2SSatish Balay viscuda = (PetscBool)(viscuda && !v->boundtocpu); 132f17f7ee2SSatish Balay siscuda = (PetscBool)(siscuda && !s->boundtocpu); 133f17f7ee2SSatish Balay if (viscuda && siscuda) { 134f17f7ee2SSatish Balay PetscCall(VecCUDAGetArrayRead(v, &av)); 135f17f7ee2SSatish Balay PetscCall(VecCUDAGetArrayWrite(s, &as)); 136f17f7ee2SSatish Balay SignVector_Functor sign_vector(av, as); 1379371c9d4SSatish Balay thrust::for_each(thrust::device, thrust::counting_iterator<PetscInt>(0), thrust::counting_iterator<PetscInt>(n), sign_vector); 138f17f7ee2SSatish Balay PetscCall(VecCUDARestoreArrayWrite(s, &as)); 139f17f7ee2SSatish Balay PetscCall(VecCUDARestoreArrayRead(v, &av)); 140f17f7ee2SSatish Balay } else 141f17f7ee2SSatish Balay #endif 142f17f7ee2SSatish Balay { 143f17f7ee2SSatish Balay PetscCall(VecGetArrayRead(v, &av)); 144f17f7ee2SSatish Balay PetscCall(VecGetArrayWrite(s, &as)); 145f17f7ee2SSatish Balay for (i = 0; i < n; i++) as[i] = PetscAbsScalar(av[i]) < 0 ? -1. : 1.; 146f17f7ee2SSatish Balay PetscCall(VecRestoreArrayWrite(s, &as)); 147f17f7ee2SSatish Balay PetscCall(VecRestoreArrayRead(v, &av)); 148f17f7ee2SSatish Balay } 149*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 150f17f7ee2SSatish Balay } 151f17f7ee2SSatish Balay 152f17f7ee2SSatish Balay #if defined(PETSC_HAVE_CUDA) 1539371c9d4SSatish Balay struct StandardBasis_Functor { 154f17f7ee2SSatish Balay PetscScalar *v; 155f17f7ee2SSatish Balay PetscInt j; 156f17f7ee2SSatish Balay 157f17f7ee2SSatish Balay StandardBasis_Functor(PetscScalar *_v, PetscInt _j) : v(_v), j(_j) { } 1589371c9d4SSatish Balay __host__ __device__ void operator()(PetscInt i) { v[i] = (i == j ? 1 : 0); } 159f17f7ee2SSatish Balay }; 160f17f7ee2SSatish Balay #endif 161f17f7ee2SSatish Balay 162d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode VecSetDelta(Vec x, PetscInt i) 163d71ae5a4SJacob Faibussowitsch { 164f17f7ee2SSatish Balay #if defined(PETSC_HAVE_CUDA) 165f17f7ee2SSatish Balay PetscBool iscuda; 166f17f7ee2SSatish Balay #endif 167f17f7ee2SSatish Balay PetscInt st, en; 168f17f7ee2SSatish Balay 169f17f7ee2SSatish Balay PetscFunctionBegin; 170f17f7ee2SSatish Balay PetscCall(VecGetOwnershipRange(x, &st, &en)); 171f17f7ee2SSatish Balay #if defined(PETSC_HAVE_CUDA) 172f17f7ee2SSatish Balay PetscCall(PetscObjectTypeCompareAny((PetscObject)x, &iscuda, VECSEQCUDA, VECMPICUDA, "")); 173f17f7ee2SSatish Balay iscuda = (PetscBool)(iscuda && !x->boundtocpu); 174f17f7ee2SSatish Balay if (iscuda) { 175f17f7ee2SSatish Balay PetscScalar *ax; 176f17f7ee2SSatish Balay PetscCall(VecCUDAGetArrayWrite(x, &ax)); 177f17f7ee2SSatish Balay StandardBasis_Functor delta(ax, i - st); 1789371c9d4SSatish Balay thrust::for_each(thrust::device, thrust::counting_iterator<PetscInt>(0), thrust::counting_iterator<PetscInt>(en - st), delta); 179f17f7ee2SSatish Balay PetscCall(VecCUDARestoreArrayWrite(x, &ax)); 180f17f7ee2SSatish Balay } else 181f17f7ee2SSatish Balay #endif 182f17f7ee2SSatish Balay { 183f17f7ee2SSatish Balay PetscCall(VecSet(x, 0.)); 18448a46eb9SPierre Jolivet if (st <= i && i < en) PetscCall(VecSetValue(x, i, 1.0, INSERT_VALUES)); 185f17f7ee2SSatish Balay PetscCall(VecAssemblyBegin(x)); 186f17f7ee2SSatish Balay PetscCall(VecAssemblyEnd(x)); 187f17f7ee2SSatish Balay } 188*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 189f17f7ee2SSatish Balay } 190f17f7ee2SSatish Balay 191f17f7ee2SSatish Balay /* these are approximate norms */ 192f17f7ee2SSatish Balay /* NORM_2: Estimating the matrix p-norm Nicholas J. Higham 193f17f7ee2SSatish Balay NORM_1/NORM_INFINITY: A block algorithm for matrix 1-norm estimation, with an application to 1-norm pseudospectra Higham, Nicholas J. and Tisseur, Francoise */ 194d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode MatApproximateNorm_Private(Mat A, NormType normtype, PetscInt normsamples, PetscReal *n) 195d71ae5a4SJacob Faibussowitsch { 196f17f7ee2SSatish Balay Vec x, y, w, z; 197f17f7ee2SSatish Balay PetscReal normz, adot; 198f17f7ee2SSatish Balay PetscScalar dot; 199f17f7ee2SSatish Balay PetscInt i, j, N, jold = -1; 200f17f7ee2SSatish Balay PetscBool boundtocpu = PETSC_TRUE; 201f17f7ee2SSatish Balay 202f17f7ee2SSatish Balay PetscFunctionBegin; 203f17f7ee2SSatish Balay #if defined(PETSC_HAVE_DEVICE) 204f17f7ee2SSatish Balay boundtocpu = A->boundtocpu; 205f17f7ee2SSatish Balay #endif 206f17f7ee2SSatish Balay switch (normtype) { 207f17f7ee2SSatish Balay case NORM_INFINITY: 208f17f7ee2SSatish Balay case NORM_1: 209f17f7ee2SSatish Balay if (normsamples < 0) normsamples = 10; /* pure guess */ 210f17f7ee2SSatish Balay if (normtype == NORM_INFINITY) { 211f17f7ee2SSatish Balay Mat B; 212f17f7ee2SSatish Balay PetscCall(MatCreateTranspose(A, &B)); 213f17f7ee2SSatish Balay A = B; 214f17f7ee2SSatish Balay } else { 215f17f7ee2SSatish Balay PetscCall(PetscObjectReference((PetscObject)A)); 216f17f7ee2SSatish Balay } 217f17f7ee2SSatish Balay PetscCall(MatCreateVecs(A, &x, &y)); 218f17f7ee2SSatish Balay PetscCall(MatCreateVecs(A, &z, &w)); 219f17f7ee2SSatish Balay PetscCall(VecBindToCPU(x, boundtocpu)); 220f17f7ee2SSatish Balay PetscCall(VecBindToCPU(y, boundtocpu)); 221f17f7ee2SSatish Balay PetscCall(VecBindToCPU(z, boundtocpu)); 222f17f7ee2SSatish Balay PetscCall(VecBindToCPU(w, boundtocpu)); 223f17f7ee2SSatish Balay PetscCall(VecGetSize(x, &N)); 224f17f7ee2SSatish Balay PetscCall(VecSet(x, 1. / N)); 225f17f7ee2SSatish Balay *n = 0.0; 226f17f7ee2SSatish Balay for (i = 0; i < normsamples; i++) { 227f17f7ee2SSatish Balay PetscCall(MatMult(A, x, y)); 228f17f7ee2SSatish Balay PetscCall(VecSign(y, w)); 229f17f7ee2SSatish Balay PetscCall(MatMultTranspose(A, w, z)); 230f17f7ee2SSatish Balay PetscCall(VecNorm(z, NORM_INFINITY, &normz)); 231f17f7ee2SSatish Balay PetscCall(VecDot(x, z, &dot)); 232f17f7ee2SSatish Balay adot = PetscAbsScalar(dot); 233f17f7ee2SSatish Balay PetscCall(PetscInfo(A, "%s norm it %" PetscInt_FMT " -> (%g %g)\n", NormTypes[normtype], i, (double)normz, (double)adot)); 234f17f7ee2SSatish Balay if (normz <= adot && i > 0) { 235f17f7ee2SSatish Balay PetscCall(VecNorm(y, NORM_1, n)); 236f17f7ee2SSatish Balay break; 237f17f7ee2SSatish Balay } 238f17f7ee2SSatish Balay PetscCall(VecMax(z, &j, &normz)); 239f17f7ee2SSatish Balay if (j == jold) { 240f17f7ee2SSatish Balay PetscCall(VecNorm(y, NORM_1, n)); 241f17f7ee2SSatish Balay PetscCall(PetscInfo(A, "%s norm it %" PetscInt_FMT " -> breakdown (j==jold)\n", NormTypes[normtype], i)); 242f17f7ee2SSatish Balay break; 243f17f7ee2SSatish Balay } 244f17f7ee2SSatish Balay jold = j; 245f17f7ee2SSatish Balay PetscCall(VecSetDelta(x, j)); 246f17f7ee2SSatish Balay } 247f17f7ee2SSatish Balay PetscCall(MatDestroy(&A)); 248f17f7ee2SSatish Balay PetscCall(VecDestroy(&x)); 249f17f7ee2SSatish Balay PetscCall(VecDestroy(&w)); 250f17f7ee2SSatish Balay PetscCall(VecDestroy(&y)); 251f17f7ee2SSatish Balay PetscCall(VecDestroy(&z)); 252f17f7ee2SSatish Balay break; 253f17f7ee2SSatish Balay case NORM_2: 254f17f7ee2SSatish Balay if (normsamples < 0) normsamples = 20; /* pure guess */ 255f17f7ee2SSatish Balay PetscCall(MatCreateVecs(A, &x, &y)); 256f17f7ee2SSatish Balay PetscCall(MatCreateVecs(A, &z, NULL)); 257f17f7ee2SSatish Balay PetscCall(VecBindToCPU(x, boundtocpu)); 258f17f7ee2SSatish Balay PetscCall(VecBindToCPU(y, boundtocpu)); 259f17f7ee2SSatish Balay PetscCall(VecBindToCPU(z, boundtocpu)); 260f17f7ee2SSatish Balay PetscCall(VecSetRandom(x, NULL)); 261f17f7ee2SSatish Balay PetscCall(VecNormalize(x, NULL)); 262f17f7ee2SSatish Balay *n = 0.0; 263f17f7ee2SSatish Balay for (i = 0; i < normsamples; i++) { 264f17f7ee2SSatish Balay PetscCall(MatMult(A, x, y)); 265f17f7ee2SSatish Balay PetscCall(VecNormalize(y, n)); 266f17f7ee2SSatish Balay PetscCall(MatMultTranspose(A, y, z)); 267f17f7ee2SSatish Balay PetscCall(VecNorm(z, NORM_2, &normz)); 268f17f7ee2SSatish Balay PetscCall(VecDot(x, z, &dot)); 269f17f7ee2SSatish Balay adot = PetscAbsScalar(dot); 270f17f7ee2SSatish Balay PetscCall(PetscInfo(A, "%s norm it %" PetscInt_FMT " -> %g (%g %g)\n", NormTypes[normtype], i, (double)*n, (double)normz, (double)adot)); 271f17f7ee2SSatish Balay if (normz <= adot) break; 272f17f7ee2SSatish Balay if (i < normsamples - 1) { 273f17f7ee2SSatish Balay Vec t; 274f17f7ee2SSatish Balay 275f17f7ee2SSatish Balay PetscCall(VecNormalize(z, NULL)); 276f17f7ee2SSatish Balay t = x; 277f17f7ee2SSatish Balay x = z; 278f17f7ee2SSatish Balay z = t; 279f17f7ee2SSatish Balay } 280f17f7ee2SSatish Balay } 281f17f7ee2SSatish Balay PetscCall(VecDestroy(&x)); 282f17f7ee2SSatish Balay PetscCall(VecDestroy(&y)); 283f17f7ee2SSatish Balay PetscCall(VecDestroy(&z)); 284f17f7ee2SSatish Balay break; 285d71ae5a4SJacob Faibussowitsch default: 286d71ae5a4SJacob Faibussowitsch SETERRQ(PetscObjectComm((PetscObject)A), PETSC_ERR_SUP, "%s norm not supported", NormTypes[normtype]); 287f17f7ee2SSatish Balay } 288f17f7ee2SSatish Balay PetscCall(PetscInfo(A, "%s norm %g computed in %" PetscInt_FMT " iterations\n", NormTypes[normtype], (double)*n, i)); 289*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 290f17f7ee2SSatish Balay } 291