1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2af0996ceSBarry Smith #include <petsc/private/snesimpl.h> /*I "petscsnes.h" I*/ 324cdb843SMatthew G. Knepley #include <petscds.h> 4af0996ceSBarry Smith #include <petsc/private/petscimpl.h> 5af0996ceSBarry Smith #include <petsc/private/petscfeimpl.h> 6552f7358SJed Brown 7d71ae5a4SJacob Faibussowitsch static void pressure_Private(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar p[]) 8d71ae5a4SJacob Faibussowitsch { 9649ef022SMatthew Knepley p[0] = u[uOff[1]]; 10649ef022SMatthew Knepley } 11649ef022SMatthew Knepley 12649ef022SMatthew Knepley /* 1320f4b53cSBarry Smith SNESCorrectDiscretePressure_Private - Add a vector in the nullspace to make the continuum integral of the pressure field equal to zero. 1420f4b53cSBarry Smith This is normally used only to evaluate convergence rates for the pressure accurately. 15649ef022SMatthew Knepley 16c3339decSBarry Smith Collective 17649ef022SMatthew Knepley 18649ef022SMatthew Knepley Input Parameters: 19649ef022SMatthew Knepley + snes - The SNES 20649ef022SMatthew Knepley . pfield - The field number for pressure 21649ef022SMatthew Knepley . nullspace - The pressure nullspace 22649ef022SMatthew Knepley . u - The solution vector 23649ef022SMatthew Knepley - ctx - An optional user context 24649ef022SMatthew Knepley 25649ef022SMatthew Knepley Output Parameter: 26649ef022SMatthew Knepley . u - The solution with a continuum pressure integral of zero 27649ef022SMatthew Knepley 282fe279fdSBarry Smith Level: developer 292fe279fdSBarry Smith 30649ef022SMatthew Knepley Notes: 31649ef022SMatthew Knepley If int(u) = a and int(n) = b, then int(u - a/b n) = a - a/b b = 0. We assume that the nullspace is a single vector given explicitly. 32649ef022SMatthew Knepley 33db781477SPatrick Sanan .seealso: `SNESConvergedCorrectPressure()` 34649ef022SMatthew Knepley */ 35d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESCorrectDiscretePressure_Private(SNES snes, PetscInt pfield, MatNullSpace nullspace, Vec u, void *ctx) 36d71ae5a4SJacob Faibussowitsch { 37649ef022SMatthew Knepley DM dm; 38649ef022SMatthew Knepley PetscDS ds; 39649ef022SMatthew Knepley const Vec *nullvecs; 40649ef022SMatthew Knepley PetscScalar pintd, *intc, *intn; 41649ef022SMatthew Knepley MPI_Comm comm; 42649ef022SMatthew Knepley PetscInt Nf, Nv; 43649ef022SMatthew Knepley 44649ef022SMatthew Knepley PetscFunctionBegin; 459566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)snes, &comm)); 469566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &dm)); 4728b400f6SJacob Faibussowitsch PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a SNES DM"); 4828b400f6SJacob Faibussowitsch PetscCheck(nullspace, comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a Jacobian nullspace"); 499566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &ds)); 509566063dSJacob Faibussowitsch PetscCall(PetscDSSetObjective(ds, pfield, pressure_Private)); 519566063dSJacob Faibussowitsch PetscCall(MatNullSpaceGetVecs(nullspace, NULL, &Nv, &nullvecs)); 5263a3b9bcSJacob Faibussowitsch PetscCheck(Nv == 1, comm, PETSC_ERR_ARG_OUTOFRANGE, "Can only handle a single null vector for pressure, not %" PetscInt_FMT, Nv); 539566063dSJacob Faibussowitsch PetscCall(VecDot(nullvecs[0], u, &pintd)); 5408401ef6SPierre Jolivet PetscCheck(PetscAbsScalar(pintd) <= PETSC_SMALL, comm, PETSC_ERR_ARG_WRONG, "Discrete integral of pressure: %g", (double)PetscRealPart(pintd)); 559566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 569566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(Nf, &intc, Nf, &intn)); 579566063dSJacob Faibussowitsch PetscCall(DMPlexComputeIntegralFEM(dm, nullvecs[0], intn, ctx)); 589566063dSJacob Faibussowitsch PetscCall(DMPlexComputeIntegralFEM(dm, u, intc, ctx)); 599566063dSJacob Faibussowitsch PetscCall(VecAXPY(u, -intc[pfield] / intn[pfield], nullvecs[0])); 60649ef022SMatthew Knepley #if defined(PETSC_USE_DEBUG) 619566063dSJacob Faibussowitsch PetscCall(DMPlexComputeIntegralFEM(dm, u, intc, ctx)); 6208401ef6SPierre Jolivet PetscCheck(PetscAbsScalar(intc[pfield]) <= PETSC_SMALL, comm, PETSC_ERR_ARG_WRONG, "Continuum integral of pressure after correction: %g", (double)PetscRealPart(intc[pfield])); 63649ef022SMatthew Knepley #endif 649566063dSJacob Faibussowitsch PetscCall(PetscFree2(intc, intn)); 653ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 66649ef022SMatthew Knepley } 67649ef022SMatthew Knepley 68649ef022SMatthew Knepley /*@C 69f6dfbefdSBarry Smith SNESConvergedCorrectPressure - Convergence test that adds a vector in the nullspace to make the continuum integral of the pressure field equal to zero. 70f6dfbefdSBarry Smith This is normally used only to evaluate convergence rates for the pressure accurately. The convergence test itself just mimics `SNESConvergedDefault()`. 71649ef022SMatthew Knepley 72c3339decSBarry Smith Logically Collective 73649ef022SMatthew Knepley 74649ef022SMatthew Knepley Input Parameters: 75f6dfbefdSBarry Smith + snes - the `SNES` context 76649ef022SMatthew Knepley . it - the iteration (0 indicates before any Newton steps) 77649ef022SMatthew Knepley . xnorm - 2-norm of current iterate 78*e4094ef1SJacob Faibussowitsch . gnorm - 2-norm of current step 79*e4094ef1SJacob Faibussowitsch . f - 2-norm of function at current iterate 80649ef022SMatthew Knepley - ctx - Optional user context 81649ef022SMatthew Knepley 82649ef022SMatthew Knepley Output Parameter: 83f6dfbefdSBarry Smith . reason - `SNES_CONVERGED_ITERATING`, `SNES_CONVERGED_ITS`, or `SNES_DIVERGED_FNORM_NAN` 84649ef022SMatthew Knepley 8520f4b53cSBarry Smith Options Database Key: 8620f4b53cSBarry Smith . -snes_convergence_test correct_pressure - see `SNESSetFromOptions()` 8720f4b53cSBarry Smith 8820f4b53cSBarry Smith Level: advanced 8920f4b53cSBarry Smith 90649ef022SMatthew Knepley Notes: 91f6dfbefdSBarry Smith In order to use this convergence test, you must set up several PETSc structures. First fields must be added to the `DM`, and a `PetscDS` 92f6dfbefdSBarry Smith must be created with discretizations of those fields. We currently assume that the pressure field has index 1. 93f6dfbefdSBarry Smith The pressure field must have a nullspace, likely created using the `DMSetNullSpaceConstructor()` interface. 94f6dfbefdSBarry Smith Last we must be able to integrate the pressure over the domain, so the `DM` attached to the SNES `must` be a `DMPLEX` at this time. 95f362779dSJed Brown 96*e4094ef1SJacob Faibussowitsch .seealso: `SNES`, `DM`, `SNESConvergedDefault()`, `SNESSetConvergenceTest()`, `DMSetNullSpaceConstructor()` 97649ef022SMatthew Knepley @*/ 98d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESConvergedCorrectPressure(SNES snes, PetscInt it, PetscReal xnorm, PetscReal gnorm, PetscReal f, SNESConvergedReason *reason, void *ctx) 99d71ae5a4SJacob Faibussowitsch { 100649ef022SMatthew Knepley PetscBool monitorIntegral = PETSC_FALSE; 101649ef022SMatthew Knepley 102649ef022SMatthew Knepley PetscFunctionBegin; 1039566063dSJacob Faibussowitsch PetscCall(SNESConvergedDefault(snes, it, xnorm, gnorm, f, reason, ctx)); 104649ef022SMatthew Knepley if (monitorIntegral) { 105649ef022SMatthew Knepley Mat J; 106649ef022SMatthew Knepley Vec u; 107649ef022SMatthew Knepley MatNullSpace nullspace; 108649ef022SMatthew Knepley const Vec *nullvecs; 109649ef022SMatthew Knepley PetscScalar pintd; 110649ef022SMatthew Knepley 1119566063dSJacob Faibussowitsch PetscCall(SNESGetSolution(snes, &u)); 1129566063dSJacob Faibussowitsch PetscCall(SNESGetJacobian(snes, &J, NULL, NULL, NULL)); 1139566063dSJacob Faibussowitsch PetscCall(MatGetNullSpace(J, &nullspace)); 1149566063dSJacob Faibussowitsch PetscCall(MatNullSpaceGetVecs(nullspace, NULL, NULL, &nullvecs)); 1159566063dSJacob Faibussowitsch PetscCall(VecDot(nullvecs[0], u, &pintd)); 1169566063dSJacob Faibussowitsch PetscCall(PetscInfo(snes, "SNES: Discrete integral of pressure: %g\n", (double)PetscRealPart(pintd))); 117649ef022SMatthew Knepley } 118649ef022SMatthew Knepley if (*reason > 0) { 119649ef022SMatthew Knepley Mat J; 120649ef022SMatthew Knepley Vec u; 121649ef022SMatthew Knepley MatNullSpace nullspace; 122649ef022SMatthew Knepley PetscInt pfield = 1; 123649ef022SMatthew Knepley 1249566063dSJacob Faibussowitsch PetscCall(SNESGetSolution(snes, &u)); 1259566063dSJacob Faibussowitsch PetscCall(SNESGetJacobian(snes, &J, NULL, NULL, NULL)); 1269566063dSJacob Faibussowitsch PetscCall(MatGetNullSpace(J, &nullspace)); 1279566063dSJacob Faibussowitsch PetscCall(SNESCorrectDiscretePressure_Private(snes, pfield, nullspace, u, ctx)); 128649ef022SMatthew Knepley } 1293ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 130649ef022SMatthew Knepley } 131649ef022SMatthew Knepley 13224cdb843SMatthew G. Knepley /************************** Interpolation *******************************/ 13324cdb843SMatthew G. Knepley 134d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESConvertPlex(DM dm, DM *plex, PetscBool copy) 135d71ae5a4SJacob Faibussowitsch { 1366da023fcSToby Isaac PetscBool isPlex; 1376da023fcSToby Isaac 1386da023fcSToby Isaac PetscFunctionBegin; 1399566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 1406da023fcSToby Isaac if (isPlex) { 1416da023fcSToby Isaac *plex = dm; 1429566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)dm)); 143f7148743SMatthew G. Knepley } else { 1449566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex)); 145f7148743SMatthew G. Knepley if (!*plex) { 1469566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, plex)); 1479566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex)); 1486da023fcSToby Isaac if (copy) { 1499566063dSJacob Faibussowitsch PetscCall(DMCopyDMSNES(dm, *plex)); 1509566063dSJacob Faibussowitsch PetscCall(DMCopyAuxiliaryVec(dm, *plex)); 1516da023fcSToby Isaac } 152f7148743SMatthew G. Knepley } else { 1539566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)*plex)); 154f7148743SMatthew G. Knepley } 1556da023fcSToby Isaac } 1563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1576da023fcSToby Isaac } 1586da023fcSToby Isaac 1594267b1a3SMatthew G. Knepley /*@C 160f6dfbefdSBarry Smith DMInterpolationCreate - Creates a `DMInterpolationInfo` context 1614267b1a3SMatthew G. Knepley 162d083f849SBarry Smith Collective 1634267b1a3SMatthew G. Knepley 1644267b1a3SMatthew G. Knepley Input Parameter: 1654267b1a3SMatthew G. Knepley . comm - the communicator 1664267b1a3SMatthew G. Knepley 1674267b1a3SMatthew G. Knepley Output Parameter: 1684267b1a3SMatthew G. Knepley . ctx - the context 1694267b1a3SMatthew G. Knepley 1704267b1a3SMatthew G. Knepley Level: beginner 1714267b1a3SMatthew G. Knepley 172f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationDestroy()` 1734267b1a3SMatthew G. Knepley @*/ 174d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationCreate(MPI_Comm comm, DMInterpolationInfo *ctx) 175d71ae5a4SJacob Faibussowitsch { 176552f7358SJed Brown PetscFunctionBegin; 177552f7358SJed Brown PetscValidPointer(ctx, 2); 1789566063dSJacob Faibussowitsch PetscCall(PetscNew(ctx)); 1791aa26658SKarl Rupp 180552f7358SJed Brown (*ctx)->comm = comm; 181552f7358SJed Brown (*ctx)->dim = -1; 182552f7358SJed Brown (*ctx)->nInput = 0; 1830298fd71SBarry Smith (*ctx)->points = NULL; 1840298fd71SBarry Smith (*ctx)->cells = NULL; 185552f7358SJed Brown (*ctx)->n = -1; 1860298fd71SBarry Smith (*ctx)->coords = NULL; 1873ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 188552f7358SJed Brown } 189552f7358SJed Brown 1904267b1a3SMatthew G. Knepley /*@C 1914267b1a3SMatthew G. Knepley DMInterpolationSetDim - Sets the spatial dimension for the interpolation context 1924267b1a3SMatthew G. Knepley 19320f4b53cSBarry Smith Not Collective 1944267b1a3SMatthew G. Knepley 1954267b1a3SMatthew G. Knepley Input Parameters: 1964267b1a3SMatthew G. Knepley + ctx - the context 1974267b1a3SMatthew G. Knepley - dim - the spatial dimension 1984267b1a3SMatthew G. Knepley 1994267b1a3SMatthew G. Knepley Level: intermediate 2004267b1a3SMatthew G. Knepley 201f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()` 2024267b1a3SMatthew G. Knepley @*/ 203d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationSetDim(DMInterpolationInfo ctx, PetscInt dim) 204d71ae5a4SJacob Faibussowitsch { 205552f7358SJed Brown PetscFunctionBegin; 20663a3b9bcSJacob Faibussowitsch PetscCheck(!(dim < 1) && !(dim > 3), ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension for points: %" PetscInt_FMT, dim); 207552f7358SJed Brown ctx->dim = dim; 2083ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 209552f7358SJed Brown } 210552f7358SJed Brown 2114267b1a3SMatthew G. Knepley /*@C 2124267b1a3SMatthew G. Knepley DMInterpolationGetDim - Gets the spatial dimension for the interpolation context 2134267b1a3SMatthew G. Knepley 21420f4b53cSBarry Smith Not Collective 2154267b1a3SMatthew G. Knepley 2164267b1a3SMatthew G. Knepley Input Parameter: 2174267b1a3SMatthew G. Knepley . ctx - the context 2184267b1a3SMatthew G. Knepley 2194267b1a3SMatthew G. Knepley Output Parameter: 2204267b1a3SMatthew G. Knepley . dim - the spatial dimension 2214267b1a3SMatthew G. Knepley 2224267b1a3SMatthew G. Knepley Level: intermediate 2234267b1a3SMatthew G. Knepley 224f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationSetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()` 2254267b1a3SMatthew G. Knepley @*/ 226d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetDim(DMInterpolationInfo ctx, PetscInt *dim) 227d71ae5a4SJacob Faibussowitsch { 228552f7358SJed Brown PetscFunctionBegin; 229552f7358SJed Brown PetscValidIntPointer(dim, 2); 230552f7358SJed Brown *dim = ctx->dim; 2313ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 232552f7358SJed Brown } 233552f7358SJed Brown 2344267b1a3SMatthew G. Knepley /*@C 2354267b1a3SMatthew G. Knepley DMInterpolationSetDof - Sets the number of fields interpolated at a point for the interpolation context 2364267b1a3SMatthew G. Knepley 23720f4b53cSBarry Smith Not Collective 2384267b1a3SMatthew G. Knepley 2394267b1a3SMatthew G. Knepley Input Parameters: 2404267b1a3SMatthew G. Knepley + ctx - the context 2414267b1a3SMatthew G. Knepley - dof - the number of fields 2424267b1a3SMatthew G. Knepley 2434267b1a3SMatthew G. Knepley Level: intermediate 2444267b1a3SMatthew G. Knepley 245f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetDof()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()` 2464267b1a3SMatthew G. Knepley @*/ 247d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationSetDof(DMInterpolationInfo ctx, PetscInt dof) 248d71ae5a4SJacob Faibussowitsch { 249552f7358SJed Brown PetscFunctionBegin; 25063a3b9bcSJacob Faibussowitsch PetscCheck(dof >= 1, ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of components: %" PetscInt_FMT, dof); 251552f7358SJed Brown ctx->dof = dof; 2523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 253552f7358SJed Brown } 254552f7358SJed Brown 2554267b1a3SMatthew G. Knepley /*@C 2564267b1a3SMatthew G. Knepley DMInterpolationGetDof - Gets the number of fields interpolated at a point for the interpolation context 2574267b1a3SMatthew G. Knepley 25820f4b53cSBarry Smith Not Collective 2594267b1a3SMatthew G. Knepley 2604267b1a3SMatthew G. Knepley Input Parameter: 2614267b1a3SMatthew G. Knepley . ctx - the context 2624267b1a3SMatthew G. Knepley 2634267b1a3SMatthew G. Knepley Output Parameter: 2644267b1a3SMatthew G. Knepley . dof - the number of fields 2654267b1a3SMatthew G. Knepley 2664267b1a3SMatthew G. Knepley Level: intermediate 2674267b1a3SMatthew G. Knepley 268*e4094ef1SJacob Faibussowitsch .seealso: `DMInterpolationInfo`, `DMInterpolationSetDof()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()` 2694267b1a3SMatthew G. Knepley @*/ 270d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetDof(DMInterpolationInfo ctx, PetscInt *dof) 271d71ae5a4SJacob Faibussowitsch { 272552f7358SJed Brown PetscFunctionBegin; 273552f7358SJed Brown PetscValidIntPointer(dof, 2); 274552f7358SJed Brown *dof = ctx->dof; 2753ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 276552f7358SJed Brown } 277552f7358SJed Brown 2784267b1a3SMatthew G. Knepley /*@C 2794267b1a3SMatthew G. Knepley DMInterpolationAddPoints - Add points at which we will interpolate the fields 2804267b1a3SMatthew G. Knepley 28120f4b53cSBarry Smith Not Collective 2824267b1a3SMatthew G. Knepley 2834267b1a3SMatthew G. Knepley Input Parameters: 2844267b1a3SMatthew G. Knepley + ctx - the context 2854267b1a3SMatthew G. Knepley . n - the number of points 2864267b1a3SMatthew G. Knepley - points - the coordinates for each point, an array of size n * dim 2874267b1a3SMatthew G. Knepley 2882fe279fdSBarry Smith Level: intermediate 2892fe279fdSBarry Smith 290f6dfbefdSBarry Smith Note: 291f6dfbefdSBarry Smith The coordinate information is copied. 2924267b1a3SMatthew G. Knepley 293f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationSetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationCreate()` 2944267b1a3SMatthew G. Knepley @*/ 295d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationAddPoints(DMInterpolationInfo ctx, PetscInt n, PetscReal points[]) 296d71ae5a4SJacob Faibussowitsch { 297552f7358SJed Brown PetscFunctionBegin; 29808401ef6SPierre Jolivet PetscCheck(ctx->dim >= 0, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set"); 29928b400f6SJacob Faibussowitsch PetscCheck(!ctx->points, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot add points multiple times yet"); 300552f7358SJed Brown ctx->nInput = n; 3011aa26658SKarl Rupp 3029566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n * ctx->dim, &ctx->points)); 3039566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(ctx->points, points, n * ctx->dim)); 3043ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 305552f7358SJed Brown } 306552f7358SJed Brown 3074267b1a3SMatthew G. Knepley /*@C 30852aa1562SMatthew G. Knepley DMInterpolationSetUp - Compute spatial indices for point location during interpolation 3094267b1a3SMatthew G. Knepley 310c3339decSBarry Smith Collective 3114267b1a3SMatthew G. Knepley 3124267b1a3SMatthew G. Knepley Input Parameters: 3134267b1a3SMatthew G. Knepley + ctx - the context 314f6dfbefdSBarry Smith . dm - the `DM` for the function space used for interpolation 315f6dfbefdSBarry Smith . redundantPoints - If `PETSC_TRUE`, all processes are passing in the same array of points. Otherwise, points need to be communicated among processes. 316f6dfbefdSBarry Smith - ignoreOutsideDomain - If `PETSC_TRUE`, ignore points outside the domain, otherwise return an error 3174267b1a3SMatthew G. Knepley 3184267b1a3SMatthew G. Knepley Level: intermediate 3194267b1a3SMatthew G. Knepley 320*e4094ef1SJacob Faibussowitsch .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 3214267b1a3SMatthew G. Knepley @*/ 322d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationSetUp(DMInterpolationInfo ctx, DM dm, PetscBool redundantPoints, PetscBool ignoreOutsideDomain) 323d71ae5a4SJacob Faibussowitsch { 324552f7358SJed Brown MPI_Comm comm = ctx->comm; 325552f7358SJed Brown PetscScalar *a; 326552f7358SJed Brown PetscInt p, q, i; 327552f7358SJed Brown PetscMPIInt rank, size; 328552f7358SJed Brown Vec pointVec; 3293a93e3b7SToby Isaac PetscSF cellSF; 330552f7358SJed Brown PetscLayout layout; 331552f7358SJed Brown PetscReal *globalPoints; 332cb313848SJed Brown PetscScalar *globalPointsScalar; 333552f7358SJed Brown const PetscInt *ranges; 334552f7358SJed Brown PetscMPIInt *counts, *displs; 3353a93e3b7SToby Isaac const PetscSFNode *foundCells; 3363a93e3b7SToby Isaac const PetscInt *foundPoints; 337552f7358SJed Brown PetscMPIInt *foundProcs, *globalProcs; 3383a93e3b7SToby Isaac PetscInt n, N, numFound; 339552f7358SJed Brown 34019436ca2SJed Brown PetscFunctionBegin; 341064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 3429566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(comm, &size)); 3439566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 34408401ef6SPierre Jolivet PetscCheck(ctx->dim >= 0, comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set"); 34519436ca2SJed Brown /* Locate points */ 34619436ca2SJed Brown n = ctx->nInput; 347552f7358SJed Brown if (!redundantPoints) { 3489566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(comm, &layout)); 3499566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(layout, 1)); 3509566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(layout, n)); 3519566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(layout)); 3529566063dSJacob Faibussowitsch PetscCall(PetscLayoutGetSize(layout, &N)); 353552f7358SJed Brown /* Communicate all points to all processes */ 3549566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(N * ctx->dim, &globalPoints, size, &counts, size, &displs)); 3559566063dSJacob Faibussowitsch PetscCall(PetscLayoutGetRanges(layout, &ranges)); 356552f7358SJed Brown for (p = 0; p < size; ++p) { 357552f7358SJed Brown counts[p] = (ranges[p + 1] - ranges[p]) * ctx->dim; 358552f7358SJed Brown displs[p] = ranges[p] * ctx->dim; 359552f7358SJed Brown } 3609566063dSJacob Faibussowitsch PetscCallMPI(MPI_Allgatherv(ctx->points, n * ctx->dim, MPIU_REAL, globalPoints, counts, displs, MPIU_REAL, comm)); 361552f7358SJed Brown } else { 362552f7358SJed Brown N = n; 363552f7358SJed Brown globalPoints = ctx->points; 36438ea73c8SJed Brown counts = displs = NULL; 36538ea73c8SJed Brown layout = NULL; 366552f7358SJed Brown } 367552f7358SJed Brown #if 0 3689566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(N,&foundCells,N,&foundProcs,N,&globalProcs)); 36919436ca2SJed Brown /* foundCells[p] = m->locatePoint(&globalPoints[p*ctx->dim]); */ 370552f7358SJed Brown #else 371cb313848SJed Brown #if defined(PETSC_USE_COMPLEX) 3729566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(N * ctx->dim, &globalPointsScalar)); 37346b3086cSToby Isaac for (i = 0; i < N * ctx->dim; i++) globalPointsScalar[i] = globalPoints[i]; 374cb313848SJed Brown #else 375cb313848SJed Brown globalPointsScalar = globalPoints; 376cb313848SJed Brown #endif 3779566063dSJacob Faibussowitsch PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, ctx->dim, N * ctx->dim, globalPointsScalar, &pointVec)); 3789566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(N, &foundProcs, N, &globalProcs)); 379ad540459SPierre Jolivet for (p = 0; p < N; ++p) foundProcs[p] = size; 3803a93e3b7SToby Isaac cellSF = NULL; 3819566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dm, pointVec, DM_POINTLOCATION_REMOVE, &cellSF)); 3829566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(cellSF, NULL, &numFound, &foundPoints, &foundCells)); 383552f7358SJed Brown #endif 3843a93e3b7SToby Isaac for (p = 0; p < numFound; ++p) { 3853a93e3b7SToby Isaac if (foundCells[p].index >= 0) foundProcs[foundPoints ? foundPoints[p] : p] = rank; 386552f7358SJed Brown } 387552f7358SJed Brown /* Let the lowest rank process own each point */ 3881c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(foundProcs, globalProcs, N, MPI_INT, MPI_MIN, comm)); 389552f7358SJed Brown ctx->n = 0; 390552f7358SJed Brown for (p = 0; p < N; ++p) { 39152aa1562SMatthew G. Knepley if (globalProcs[p] == size) { 3929371c9d4SSatish Balay PetscCheck(ignoreOutsideDomain, comm, PETSC_ERR_PLIB, "Point %" PetscInt_FMT ": %g %g %g not located in mesh", p, (double)globalPoints[p * ctx->dim + 0], (double)(ctx->dim > 1 ? globalPoints[p * ctx->dim + 1] : 0.0), 3939371c9d4SSatish Balay (double)(ctx->dim > 2 ? globalPoints[p * ctx->dim + 2] : 0.0)); 394f7d195e4SLawrence Mitchell if (rank == 0) ++ctx->n; 39552aa1562SMatthew G. Knepley } else if (globalProcs[p] == rank) ++ctx->n; 396552f7358SJed Brown } 397552f7358SJed Brown /* Create coordinates vector and array of owned cells */ 3989566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(ctx->n, &ctx->cells)); 3999566063dSJacob Faibussowitsch PetscCall(VecCreate(comm, &ctx->coords)); 4009566063dSJacob Faibussowitsch PetscCall(VecSetSizes(ctx->coords, ctx->n * ctx->dim, PETSC_DECIDE)); 4019566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(ctx->coords, ctx->dim)); 4029566063dSJacob Faibussowitsch PetscCall(VecSetType(ctx->coords, VECSTANDARD)); 4039566063dSJacob Faibussowitsch PetscCall(VecGetArray(ctx->coords, &a)); 404552f7358SJed Brown for (p = 0, q = 0, i = 0; p < N; ++p) { 405552f7358SJed Brown if (globalProcs[p] == rank) { 406552f7358SJed Brown PetscInt d; 407552f7358SJed Brown 4081aa26658SKarl Rupp for (d = 0; d < ctx->dim; ++d, ++i) a[i] = globalPoints[p * ctx->dim + d]; 409f317b747SMatthew G. Knepley ctx->cells[q] = foundCells[q].index; 410f317b747SMatthew G. Knepley ++q; 411552f7358SJed Brown } 412dd400576SPatrick Sanan if (globalProcs[p] == size && rank == 0) { 41352aa1562SMatthew G. Knepley PetscInt d; 41452aa1562SMatthew G. Knepley 41552aa1562SMatthew G. Knepley for (d = 0; d < ctx->dim; ++d, ++i) a[i] = 0.; 41652aa1562SMatthew G. Knepley ctx->cells[q] = -1; 41752aa1562SMatthew G. Knepley ++q; 41852aa1562SMatthew G. Knepley } 419552f7358SJed Brown } 4209566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(ctx->coords, &a)); 421552f7358SJed Brown #if 0 4229566063dSJacob Faibussowitsch PetscCall(PetscFree3(foundCells,foundProcs,globalProcs)); 423552f7358SJed Brown #else 4249566063dSJacob Faibussowitsch PetscCall(PetscFree2(foundProcs, globalProcs)); 4259566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&cellSF)); 4269566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 427552f7358SJed Brown #endif 4289566063dSJacob Faibussowitsch if ((void *)globalPointsScalar != (void *)globalPoints) PetscCall(PetscFree(globalPointsScalar)); 4299566063dSJacob Faibussowitsch if (!redundantPoints) PetscCall(PetscFree3(globalPoints, counts, displs)); 4309566063dSJacob Faibussowitsch PetscCall(PetscLayoutDestroy(&layout)); 4313ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 432552f7358SJed Brown } 433552f7358SJed Brown 4344267b1a3SMatthew G. Knepley /*@C 435f6dfbefdSBarry Smith DMInterpolationGetCoordinates - Gets a `Vec` with the coordinates of each interpolation point 4364267b1a3SMatthew G. Knepley 437c3339decSBarry Smith Collective 4384267b1a3SMatthew G. Knepley 4394267b1a3SMatthew G. Knepley Input Parameter: 4404267b1a3SMatthew G. Knepley . ctx - the context 4414267b1a3SMatthew G. Knepley 4424267b1a3SMatthew G. Knepley Output Parameter: 4434267b1a3SMatthew G. Knepley . coordinates - the coordinates of interpolation points 4444267b1a3SMatthew G. Knepley 44520f4b53cSBarry Smith Level: intermediate 44620f4b53cSBarry Smith 447f6dfbefdSBarry Smith Note: 448f6dfbefdSBarry Smith The local vector entries correspond to interpolation points lying on this process, according to the associated `DM`. 449f6dfbefdSBarry Smith This is a borrowed vector that the user should not destroy. 4504267b1a3SMatthew G. Knepley 451f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 4524267b1a3SMatthew G. Knepley @*/ 453d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetCoordinates(DMInterpolationInfo ctx, Vec *coordinates) 454d71ae5a4SJacob Faibussowitsch { 455552f7358SJed Brown PetscFunctionBegin; 456552f7358SJed Brown PetscValidPointer(coordinates, 2); 45728b400f6SJacob Faibussowitsch PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup."); 458552f7358SJed Brown *coordinates = ctx->coords; 4593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 460552f7358SJed Brown } 461552f7358SJed Brown 4624267b1a3SMatthew G. Knepley /*@C 463f6dfbefdSBarry Smith DMInterpolationGetVector - Gets a `Vec` which can hold all the interpolated field values 4644267b1a3SMatthew G. Knepley 465c3339decSBarry Smith Collective 4664267b1a3SMatthew G. Knepley 4674267b1a3SMatthew G. Knepley Input Parameter: 4684267b1a3SMatthew G. Knepley . ctx - the context 4694267b1a3SMatthew G. Knepley 4704267b1a3SMatthew G. Knepley Output Parameter: 4714267b1a3SMatthew G. Knepley . v - a vector capable of holding the interpolated field values 4724267b1a3SMatthew G. Knepley 4732fe279fdSBarry Smith Level: intermediate 4742fe279fdSBarry Smith 475f6dfbefdSBarry Smith Note: 476f6dfbefdSBarry Smith This vector should be returned using `DMInterpolationRestoreVector()`. 4774267b1a3SMatthew G. Knepley 478f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationRestoreVector()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 4794267b1a3SMatthew G. Knepley @*/ 480d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetVector(DMInterpolationInfo ctx, Vec *v) 481d71ae5a4SJacob Faibussowitsch { 482552f7358SJed Brown PetscFunctionBegin; 483552f7358SJed Brown PetscValidPointer(v, 2); 48428b400f6SJacob Faibussowitsch PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup."); 4859566063dSJacob Faibussowitsch PetscCall(VecCreate(ctx->comm, v)); 4869566063dSJacob Faibussowitsch PetscCall(VecSetSizes(*v, ctx->n * ctx->dof, PETSC_DECIDE)); 4879566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(*v, ctx->dof)); 4889566063dSJacob Faibussowitsch PetscCall(VecSetType(*v, VECSTANDARD)); 4893ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 490552f7358SJed Brown } 491552f7358SJed Brown 4924267b1a3SMatthew G. Knepley /*@C 493f6dfbefdSBarry Smith DMInterpolationRestoreVector - Returns a `Vec` which can hold all the interpolated field values 4944267b1a3SMatthew G. Knepley 495c3339decSBarry Smith Collective 4964267b1a3SMatthew G. Knepley 4974267b1a3SMatthew G. Knepley Input Parameters: 4984267b1a3SMatthew G. Knepley + ctx - the context 4994267b1a3SMatthew G. Knepley - v - a vector capable of holding the interpolated field values 5004267b1a3SMatthew G. Knepley 5014267b1a3SMatthew G. Knepley Level: intermediate 5024267b1a3SMatthew G. Knepley 503f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetVector()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 5044267b1a3SMatthew G. Knepley @*/ 505d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationRestoreVector(DMInterpolationInfo ctx, Vec *v) 506d71ae5a4SJacob Faibussowitsch { 507552f7358SJed Brown PetscFunctionBegin; 508552f7358SJed Brown PetscValidPointer(v, 2); 50928b400f6SJacob Faibussowitsch PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup."); 5109566063dSJacob Faibussowitsch PetscCall(VecDestroy(v)); 5113ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 512552f7358SJed Brown } 513552f7358SJed Brown 514d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Segment_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 515d71ae5a4SJacob Faibussowitsch { 516cfe5744fSMatthew G. Knepley PetscReal v0, J, invJ, detJ; 517cfe5744fSMatthew G. Knepley const PetscInt dof = ctx->dof; 518cfe5744fSMatthew G. Knepley const PetscScalar *coords; 519cfe5744fSMatthew G. Knepley PetscScalar *a; 520cfe5744fSMatthew G. Knepley PetscInt p; 521cfe5744fSMatthew G. Knepley 522cfe5744fSMatthew G. Knepley PetscFunctionBegin; 5239566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 5249566063dSJacob Faibussowitsch PetscCall(VecGetArray(v, &a)); 525cfe5744fSMatthew G. Knepley for (p = 0; p < ctx->n; ++p) { 526cfe5744fSMatthew G. Knepley PetscInt c = ctx->cells[p]; 527cfe5744fSMatthew G. Knepley PetscScalar *x = NULL; 528cfe5744fSMatthew G. Knepley PetscReal xir[1]; 529cfe5744fSMatthew G. Knepley PetscInt xSize, comp; 530cfe5744fSMatthew G. Knepley 5319566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, &v0, &J, &invJ, &detJ)); 532cfe5744fSMatthew G. Knepley PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c); 533cfe5744fSMatthew G. Knepley xir[0] = invJ * PetscRealPart(coords[p] - v0); 5349566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x)); 535cfe5744fSMatthew G. Knepley if (2 * dof == xSize) { 536cfe5744fSMatthew G. Knepley for (comp = 0; comp < dof; ++comp) a[p * dof + comp] = x[0 * dof + comp] * (1 - xir[0]) + x[1 * dof + comp] * xir[0]; 537cfe5744fSMatthew G. Knepley } else if (dof == xSize) { 538cfe5744fSMatthew G. Knepley for (comp = 0; comp < dof; ++comp) a[p * dof + comp] = x[0 * dof + comp]; 539cfe5744fSMatthew G. Knepley } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Input closure size %" PetscInt_FMT " must be either %" PetscInt_FMT " or %" PetscInt_FMT, xSize, 2 * dof, dof); 5409566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x)); 541cfe5744fSMatthew G. Knepley } 5429566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(v, &a)); 5439566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 5443ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 545cfe5744fSMatthew G. Knepley } 546cfe5744fSMatthew G. Knepley 547d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Triangle_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 548d71ae5a4SJacob Faibussowitsch { 549552f7358SJed Brown PetscReal *v0, *J, *invJ, detJ; 55056044e6dSMatthew G. Knepley const PetscScalar *coords; 55156044e6dSMatthew G. Knepley PetscScalar *a; 552552f7358SJed Brown PetscInt p; 553552f7358SJed Brown 554552f7358SJed Brown PetscFunctionBegin; 5559566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(ctx->dim, &v0, ctx->dim * ctx->dim, &J, ctx->dim * ctx->dim, &invJ)); 5569566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 5579566063dSJacob Faibussowitsch PetscCall(VecGetArray(v, &a)); 558552f7358SJed Brown for (p = 0; p < ctx->n; ++p) { 559552f7358SJed Brown PetscInt c = ctx->cells[p]; 560a1e44745SMatthew G. Knepley PetscScalar *x = NULL; 561552f7358SJed Brown PetscReal xi[4]; 562552f7358SJed Brown PetscInt d, f, comp; 563552f7358SJed Brown 5649566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ)); 56563a3b9bcSJacob Faibussowitsch PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c); 5669566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x)); 5671aa26658SKarl Rupp for (comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp]; 5681aa26658SKarl Rupp 569552f7358SJed Brown for (d = 0; d < ctx->dim; ++d) { 570552f7358SJed Brown xi[d] = 0.0; 5711aa26658SKarl Rupp for (f = 0; f < ctx->dim; ++f) xi[d] += invJ[d * ctx->dim + f] * 0.5 * PetscRealPart(coords[p * ctx->dim + f] - v0[f]); 5721aa26658SKarl Rupp for (comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] += PetscRealPart(x[(d + 1) * ctx->dof + comp] - x[0 * ctx->dof + comp]) * xi[d]; 573552f7358SJed Brown } 5749566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x)); 575552f7358SJed Brown } 5769566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(v, &a)); 5779566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 5789566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 5793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 580552f7358SJed Brown } 581552f7358SJed Brown 582d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Tetrahedron_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 583d71ae5a4SJacob Faibussowitsch { 5847a1931ceSMatthew G. Knepley PetscReal *v0, *J, *invJ, detJ; 58556044e6dSMatthew G. Knepley const PetscScalar *coords; 58656044e6dSMatthew G. Knepley PetscScalar *a; 5877a1931ceSMatthew G. Knepley PetscInt p; 5887a1931ceSMatthew G. Knepley 5897a1931ceSMatthew G. Knepley PetscFunctionBegin; 5909566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(ctx->dim, &v0, ctx->dim * ctx->dim, &J, ctx->dim * ctx->dim, &invJ)); 5919566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 5929566063dSJacob Faibussowitsch PetscCall(VecGetArray(v, &a)); 5937a1931ceSMatthew G. Knepley for (p = 0; p < ctx->n; ++p) { 5947a1931ceSMatthew G. Knepley PetscInt c = ctx->cells[p]; 5957a1931ceSMatthew G. Knepley const PetscInt order[3] = {2, 1, 3}; 5962584bbe8SMatthew G. Knepley PetscScalar *x = NULL; 5977a1931ceSMatthew G. Knepley PetscReal xi[4]; 5987a1931ceSMatthew G. Knepley PetscInt d, f, comp; 5997a1931ceSMatthew G. Knepley 6009566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ)); 60163a3b9bcSJacob Faibussowitsch PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c); 6029566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x)); 6037a1931ceSMatthew G. Knepley for (comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp]; 6047a1931ceSMatthew G. Knepley 6057a1931ceSMatthew G. Knepley for (d = 0; d < ctx->dim; ++d) { 6067a1931ceSMatthew G. Knepley xi[d] = 0.0; 6077a1931ceSMatthew G. Knepley for (f = 0; f < ctx->dim; ++f) xi[d] += invJ[d * ctx->dim + f] * 0.5 * PetscRealPart(coords[p * ctx->dim + f] - v0[f]); 6087a1931ceSMatthew G. Knepley for (comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] += PetscRealPart(x[order[d] * ctx->dof + comp] - x[0 * ctx->dof + comp]) * xi[d]; 6097a1931ceSMatthew G. Knepley } 6109566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x)); 6117a1931ceSMatthew G. Knepley } 6129566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(v, &a)); 6139566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 6149566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 6153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 6167a1931ceSMatthew G. Knepley } 6177a1931ceSMatthew G. Knepley 618d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode QuadMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx) 619d71ae5a4SJacob Faibussowitsch { 620552f7358SJed Brown const PetscScalar *vertices = (const PetscScalar *)ctx; 621552f7358SJed Brown const PetscScalar x0 = vertices[0]; 622552f7358SJed Brown const PetscScalar y0 = vertices[1]; 623552f7358SJed Brown const PetscScalar x1 = vertices[2]; 624552f7358SJed Brown const PetscScalar y1 = vertices[3]; 625552f7358SJed Brown const PetscScalar x2 = vertices[4]; 626552f7358SJed Brown const PetscScalar y2 = vertices[5]; 627552f7358SJed Brown const PetscScalar x3 = vertices[6]; 628552f7358SJed Brown const PetscScalar y3 = vertices[7]; 629552f7358SJed Brown const PetscScalar f_1 = x1 - x0; 630552f7358SJed Brown const PetscScalar g_1 = y1 - y0; 631552f7358SJed Brown const PetscScalar f_3 = x3 - x0; 632552f7358SJed Brown const PetscScalar g_3 = y3 - y0; 633552f7358SJed Brown const PetscScalar f_01 = x2 - x1 - x3 + x0; 634552f7358SJed Brown const PetscScalar g_01 = y2 - y1 - y3 + y0; 63556044e6dSMatthew G. Knepley const PetscScalar *ref; 63656044e6dSMatthew G. Knepley PetscScalar *real; 637552f7358SJed Brown 638552f7358SJed Brown PetscFunctionBegin; 6399566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(Xref, &ref)); 6409566063dSJacob Faibussowitsch PetscCall(VecGetArray(Xreal, &real)); 641552f7358SJed Brown { 642552f7358SJed Brown const PetscScalar p0 = ref[0]; 643552f7358SJed Brown const PetscScalar p1 = ref[1]; 644552f7358SJed Brown 645552f7358SJed Brown real[0] = x0 + f_1 * p0 + f_3 * p1 + f_01 * p0 * p1; 646552f7358SJed Brown real[1] = y0 + g_1 * p0 + g_3 * p1 + g_01 * p0 * p1; 647552f7358SJed Brown } 6489566063dSJacob Faibussowitsch PetscCall(PetscLogFlops(28)); 6499566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(Xref, &ref)); 6509566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(Xreal, &real)); 6513ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 652552f7358SJed Brown } 653552f7358SJed Brown 654af0996ceSBarry Smith #include <petsc/private/dmimpl.h> 655d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode QuadJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx) 656d71ae5a4SJacob Faibussowitsch { 657552f7358SJed Brown const PetscScalar *vertices = (const PetscScalar *)ctx; 658552f7358SJed Brown const PetscScalar x0 = vertices[0]; 659552f7358SJed Brown const PetscScalar y0 = vertices[1]; 660552f7358SJed Brown const PetscScalar x1 = vertices[2]; 661552f7358SJed Brown const PetscScalar y1 = vertices[3]; 662552f7358SJed Brown const PetscScalar x2 = vertices[4]; 663552f7358SJed Brown const PetscScalar y2 = vertices[5]; 664552f7358SJed Brown const PetscScalar x3 = vertices[6]; 665552f7358SJed Brown const PetscScalar y3 = vertices[7]; 666552f7358SJed Brown const PetscScalar f_01 = x2 - x1 - x3 + x0; 667552f7358SJed Brown const PetscScalar g_01 = y2 - y1 - y3 + y0; 66856044e6dSMatthew G. Knepley const PetscScalar *ref; 669552f7358SJed Brown 670552f7358SJed Brown PetscFunctionBegin; 6719566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(Xref, &ref)); 672552f7358SJed Brown { 673552f7358SJed Brown const PetscScalar x = ref[0]; 674552f7358SJed Brown const PetscScalar y = ref[1]; 675552f7358SJed Brown const PetscInt rows[2] = {0, 1}; 676da80777bSKarl Rupp PetscScalar values[4]; 677da80777bSKarl Rupp 6789371c9d4SSatish Balay values[0] = (x1 - x0 + f_01 * y) * 0.5; 6799371c9d4SSatish Balay values[1] = (x3 - x0 + f_01 * x) * 0.5; 6809371c9d4SSatish Balay values[2] = (y1 - y0 + g_01 * y) * 0.5; 6819371c9d4SSatish Balay values[3] = (y3 - y0 + g_01 * x) * 0.5; 6829566063dSJacob Faibussowitsch PetscCall(MatSetValues(J, 2, rows, 2, rows, values, INSERT_VALUES)); 683552f7358SJed Brown } 6849566063dSJacob Faibussowitsch PetscCall(PetscLogFlops(30)); 6859566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(Xref, &ref)); 6869566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY)); 6879566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY)); 6883ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 689552f7358SJed Brown } 690552f7358SJed Brown 691d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Quad_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 692d71ae5a4SJacob Faibussowitsch { 693fafc0619SMatthew G Knepley DM dmCoord; 694de73a395SMatthew G. Knepley PetscFE fem = NULL; 695552f7358SJed Brown SNES snes; 696552f7358SJed Brown KSP ksp; 697552f7358SJed Brown PC pc; 698552f7358SJed Brown Vec coordsLocal, r, ref, real; 699552f7358SJed Brown Mat J; 700716009bfSMatthew G. Knepley PetscTabulation T = NULL; 70156044e6dSMatthew G. Knepley const PetscScalar *coords; 70256044e6dSMatthew G. Knepley PetscScalar *a; 703716009bfSMatthew G. Knepley PetscReal xir[2] = {0., 0.}; 704de73a395SMatthew G. Knepley PetscInt Nf, p; 7055509d985SMatthew G. Knepley const PetscInt dof = ctx->dof; 706552f7358SJed Brown 707552f7358SJed Brown PetscFunctionBegin; 7089566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 709716009bfSMatthew G. Knepley if (Nf) { 710cfe5744fSMatthew G. Knepley PetscObject obj; 711cfe5744fSMatthew G. Knepley PetscClassId id; 712cfe5744fSMatthew G. Knepley 7139566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, 0, NULL, &obj)); 7149566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 7159371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 7169371c9d4SSatish Balay fem = (PetscFE)obj; 7179371c9d4SSatish Balay PetscCall(PetscFECreateTabulation(fem, 1, 1, xir, 0, &T)); 7189371c9d4SSatish Balay } 719716009bfSMatthew G. Knepley } 7209566063dSJacob Faibussowitsch PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 7219566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDM(dm, &dmCoord)); 7229566063dSJacob Faibussowitsch PetscCall(SNESCreate(PETSC_COMM_SELF, &snes)); 7239566063dSJacob Faibussowitsch PetscCall(SNESSetOptionsPrefix(snes, "quad_interp_")); 7249566063dSJacob Faibussowitsch PetscCall(VecCreate(PETSC_COMM_SELF, &r)); 7259566063dSJacob Faibussowitsch PetscCall(VecSetSizes(r, 2, 2)); 7269566063dSJacob Faibussowitsch PetscCall(VecSetType(r, dm->vectype)); 7279566063dSJacob Faibussowitsch PetscCall(VecDuplicate(r, &ref)); 7289566063dSJacob Faibussowitsch PetscCall(VecDuplicate(r, &real)); 7299566063dSJacob Faibussowitsch PetscCall(MatCreate(PETSC_COMM_SELF, &J)); 7309566063dSJacob Faibussowitsch PetscCall(MatSetSizes(J, 2, 2, 2, 2)); 7319566063dSJacob Faibussowitsch PetscCall(MatSetType(J, MATSEQDENSE)); 7329566063dSJacob Faibussowitsch PetscCall(MatSetUp(J)); 7339566063dSJacob Faibussowitsch PetscCall(SNESSetFunction(snes, r, QuadMap_Private, NULL)); 7349566063dSJacob Faibussowitsch PetscCall(SNESSetJacobian(snes, J, J, QuadJacobian_Private, NULL)); 7359566063dSJacob Faibussowitsch PetscCall(SNESGetKSP(snes, &ksp)); 7369566063dSJacob Faibussowitsch PetscCall(KSPGetPC(ksp, &pc)); 7379566063dSJacob Faibussowitsch PetscCall(PCSetType(pc, PCLU)); 7389566063dSJacob Faibussowitsch PetscCall(SNESSetFromOptions(snes)); 739552f7358SJed Brown 7409566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 7419566063dSJacob Faibussowitsch PetscCall(VecGetArray(v, &a)); 742552f7358SJed Brown for (p = 0; p < ctx->n; ++p) { 743a1e44745SMatthew G. Knepley PetscScalar *x = NULL, *vertices = NULL; 744552f7358SJed Brown PetscScalar *xi; 745552f7358SJed Brown PetscInt c = ctx->cells[p], comp, coordSize, xSize; 746552f7358SJed Brown 747552f7358SJed Brown /* Can make this do all points at once */ 7489566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices)); 74963a3b9bcSJacob Faibussowitsch PetscCheck(4 * 2 == coordSize, ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid closure size %" PetscInt_FMT " should be %d", coordSize, 4 * 2); 7509566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x)); 7519566063dSJacob Faibussowitsch PetscCall(SNESSetFunction(snes, NULL, NULL, vertices)); 7529566063dSJacob Faibussowitsch PetscCall(SNESSetJacobian(snes, NULL, NULL, NULL, vertices)); 7539566063dSJacob Faibussowitsch PetscCall(VecGetArray(real, &xi)); 754552f7358SJed Brown xi[0] = coords[p * ctx->dim + 0]; 755552f7358SJed Brown xi[1] = coords[p * ctx->dim + 1]; 7569566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(real, &xi)); 7579566063dSJacob Faibussowitsch PetscCall(SNESSolve(snes, real, ref)); 7589566063dSJacob Faibussowitsch PetscCall(VecGetArray(ref, &xi)); 759cb313848SJed Brown xir[0] = PetscRealPart(xi[0]); 760cb313848SJed Brown xir[1] = PetscRealPart(xi[1]); 761cfe5744fSMatthew G. Knepley if (4 * dof == xSize) { 7629371c9d4SSatish Balay for (comp = 0; comp < dof; ++comp) a[p * dof + comp] = x[0 * dof + comp] * (1 - xir[0]) * (1 - xir[1]) + x[1 * dof + comp] * xir[0] * (1 - xir[1]) + x[2 * dof + comp] * xir[0] * xir[1] + x[3 * dof + comp] * (1 - xir[0]) * xir[1]; 763cfe5744fSMatthew G. Knepley } else if (dof == xSize) { 764cfe5744fSMatthew G. Knepley for (comp = 0; comp < dof; ++comp) a[p * dof + comp] = x[0 * dof + comp]; 765cfe5744fSMatthew G. Knepley } else { 7665509d985SMatthew G. Knepley PetscInt d; 7671aa26658SKarl Rupp 7682c71b3e2SJacob Faibussowitsch PetscCheck(fem, ctx->comm, PETSC_ERR_ARG_WRONG, "Cannot have a higher order interpolant if the discretization is not PetscFE"); 7699371c9d4SSatish Balay xir[0] = 2.0 * xir[0] - 1.0; 7709371c9d4SSatish Balay xir[1] = 2.0 * xir[1] - 1.0; 7719566063dSJacob Faibussowitsch PetscCall(PetscFEComputeTabulation(fem, 1, xir, 0, T)); 7725509d985SMatthew G. Knepley for (comp = 0; comp < dof; ++comp) { 7735509d985SMatthew G. Knepley a[p * dof + comp] = 0.0; 774ad540459SPierre Jolivet for (d = 0; d < xSize / dof; ++d) a[p * dof + comp] += x[d * dof + comp] * T->T[0][d * dof + comp]; 7755509d985SMatthew G. Knepley } 7765509d985SMatthew G. Knepley } 7779566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(ref, &xi)); 7789566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices)); 7799566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x)); 780552f7358SJed Brown } 7819566063dSJacob Faibussowitsch PetscCall(PetscTabulationDestroy(&T)); 7829566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(v, &a)); 7839566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 784552f7358SJed Brown 7859566063dSJacob Faibussowitsch PetscCall(SNESDestroy(&snes)); 7869566063dSJacob Faibussowitsch PetscCall(VecDestroy(&r)); 7879566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ref)); 7889566063dSJacob Faibussowitsch PetscCall(VecDestroy(&real)); 7899566063dSJacob Faibussowitsch PetscCall(MatDestroy(&J)); 7903ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 791552f7358SJed Brown } 792552f7358SJed Brown 793d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode HexMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx) 794d71ae5a4SJacob Faibussowitsch { 795552f7358SJed Brown const PetscScalar *vertices = (const PetscScalar *)ctx; 796552f7358SJed Brown const PetscScalar x0 = vertices[0]; 797552f7358SJed Brown const PetscScalar y0 = vertices[1]; 798552f7358SJed Brown const PetscScalar z0 = vertices[2]; 7997a1931ceSMatthew G. Knepley const PetscScalar x1 = vertices[9]; 8007a1931ceSMatthew G. Knepley const PetscScalar y1 = vertices[10]; 8017a1931ceSMatthew G. Knepley const PetscScalar z1 = vertices[11]; 802552f7358SJed Brown const PetscScalar x2 = vertices[6]; 803552f7358SJed Brown const PetscScalar y2 = vertices[7]; 804552f7358SJed Brown const PetscScalar z2 = vertices[8]; 8057a1931ceSMatthew G. Knepley const PetscScalar x3 = vertices[3]; 8067a1931ceSMatthew G. Knepley const PetscScalar y3 = vertices[4]; 8077a1931ceSMatthew G. Knepley const PetscScalar z3 = vertices[5]; 808552f7358SJed Brown const PetscScalar x4 = vertices[12]; 809552f7358SJed Brown const PetscScalar y4 = vertices[13]; 810552f7358SJed Brown const PetscScalar z4 = vertices[14]; 811552f7358SJed Brown const PetscScalar x5 = vertices[15]; 812552f7358SJed Brown const PetscScalar y5 = vertices[16]; 813552f7358SJed Brown const PetscScalar z5 = vertices[17]; 814552f7358SJed Brown const PetscScalar x6 = vertices[18]; 815552f7358SJed Brown const PetscScalar y6 = vertices[19]; 816552f7358SJed Brown const PetscScalar z6 = vertices[20]; 817552f7358SJed Brown const PetscScalar x7 = vertices[21]; 818552f7358SJed Brown const PetscScalar y7 = vertices[22]; 819552f7358SJed Brown const PetscScalar z7 = vertices[23]; 820552f7358SJed Brown const PetscScalar f_1 = x1 - x0; 821552f7358SJed Brown const PetscScalar g_1 = y1 - y0; 822552f7358SJed Brown const PetscScalar h_1 = z1 - z0; 823552f7358SJed Brown const PetscScalar f_3 = x3 - x0; 824552f7358SJed Brown const PetscScalar g_3 = y3 - y0; 825552f7358SJed Brown const PetscScalar h_3 = z3 - z0; 826552f7358SJed Brown const PetscScalar f_4 = x4 - x0; 827552f7358SJed Brown const PetscScalar g_4 = y4 - y0; 828552f7358SJed Brown const PetscScalar h_4 = z4 - z0; 829552f7358SJed Brown const PetscScalar f_01 = x2 - x1 - x3 + x0; 830552f7358SJed Brown const PetscScalar g_01 = y2 - y1 - y3 + y0; 831552f7358SJed Brown const PetscScalar h_01 = z2 - z1 - z3 + z0; 832552f7358SJed Brown const PetscScalar f_12 = x7 - x3 - x4 + x0; 833552f7358SJed Brown const PetscScalar g_12 = y7 - y3 - y4 + y0; 834552f7358SJed Brown const PetscScalar h_12 = z7 - z3 - z4 + z0; 835552f7358SJed Brown const PetscScalar f_02 = x5 - x1 - x4 + x0; 836552f7358SJed Brown const PetscScalar g_02 = y5 - y1 - y4 + y0; 837552f7358SJed Brown const PetscScalar h_02 = z5 - z1 - z4 + z0; 838552f7358SJed Brown const PetscScalar f_012 = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7; 839552f7358SJed Brown const PetscScalar g_012 = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7; 840552f7358SJed Brown const PetscScalar h_012 = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7; 84156044e6dSMatthew G. Knepley const PetscScalar *ref; 84256044e6dSMatthew G. Knepley PetscScalar *real; 843552f7358SJed Brown 844552f7358SJed Brown PetscFunctionBegin; 8459566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(Xref, &ref)); 8469566063dSJacob Faibussowitsch PetscCall(VecGetArray(Xreal, &real)); 847552f7358SJed Brown { 848552f7358SJed Brown const PetscScalar p0 = ref[0]; 849552f7358SJed Brown const PetscScalar p1 = ref[1]; 850552f7358SJed Brown const PetscScalar p2 = ref[2]; 851552f7358SJed Brown 852552f7358SJed Brown real[0] = x0 + f_1 * p0 + f_3 * p1 + f_4 * p2 + f_01 * p0 * p1 + f_12 * p1 * p2 + f_02 * p0 * p2 + f_012 * p0 * p1 * p2; 853552f7358SJed Brown real[1] = y0 + g_1 * p0 + g_3 * p1 + g_4 * p2 + g_01 * p0 * p1 + g_01 * p0 * p1 + g_12 * p1 * p2 + g_02 * p0 * p2 + g_012 * p0 * p1 * p2; 854552f7358SJed Brown real[2] = z0 + h_1 * p0 + h_3 * p1 + h_4 * p2 + h_01 * p0 * p1 + h_01 * p0 * p1 + h_12 * p1 * p2 + h_02 * p0 * p2 + h_012 * p0 * p1 * p2; 855552f7358SJed Brown } 8569566063dSJacob Faibussowitsch PetscCall(PetscLogFlops(114)); 8579566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(Xref, &ref)); 8589566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(Xreal, &real)); 8593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 860552f7358SJed Brown } 861552f7358SJed Brown 862d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode HexJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx) 863d71ae5a4SJacob Faibussowitsch { 864552f7358SJed Brown const PetscScalar *vertices = (const PetscScalar *)ctx; 865552f7358SJed Brown const PetscScalar x0 = vertices[0]; 866552f7358SJed Brown const PetscScalar y0 = vertices[1]; 867552f7358SJed Brown const PetscScalar z0 = vertices[2]; 8687a1931ceSMatthew G. Knepley const PetscScalar x1 = vertices[9]; 8697a1931ceSMatthew G. Knepley const PetscScalar y1 = vertices[10]; 8707a1931ceSMatthew G. Knepley const PetscScalar z1 = vertices[11]; 871552f7358SJed Brown const PetscScalar x2 = vertices[6]; 872552f7358SJed Brown const PetscScalar y2 = vertices[7]; 873552f7358SJed Brown const PetscScalar z2 = vertices[8]; 8747a1931ceSMatthew G. Knepley const PetscScalar x3 = vertices[3]; 8757a1931ceSMatthew G. Knepley const PetscScalar y3 = vertices[4]; 8767a1931ceSMatthew G. Knepley const PetscScalar z3 = vertices[5]; 877552f7358SJed Brown const PetscScalar x4 = vertices[12]; 878552f7358SJed Brown const PetscScalar y4 = vertices[13]; 879552f7358SJed Brown const PetscScalar z4 = vertices[14]; 880552f7358SJed Brown const PetscScalar x5 = vertices[15]; 881552f7358SJed Brown const PetscScalar y5 = vertices[16]; 882552f7358SJed Brown const PetscScalar z5 = vertices[17]; 883552f7358SJed Brown const PetscScalar x6 = vertices[18]; 884552f7358SJed Brown const PetscScalar y6 = vertices[19]; 885552f7358SJed Brown const PetscScalar z6 = vertices[20]; 886552f7358SJed Brown const PetscScalar x7 = vertices[21]; 887552f7358SJed Brown const PetscScalar y7 = vertices[22]; 888552f7358SJed Brown const PetscScalar z7 = vertices[23]; 889552f7358SJed Brown const PetscScalar f_xy = x2 - x1 - x3 + x0; 890552f7358SJed Brown const PetscScalar g_xy = y2 - y1 - y3 + y0; 891552f7358SJed Brown const PetscScalar h_xy = z2 - z1 - z3 + z0; 892552f7358SJed Brown const PetscScalar f_yz = x7 - x3 - x4 + x0; 893552f7358SJed Brown const PetscScalar g_yz = y7 - y3 - y4 + y0; 894552f7358SJed Brown const PetscScalar h_yz = z7 - z3 - z4 + z0; 895552f7358SJed Brown const PetscScalar f_xz = x5 - x1 - x4 + x0; 896552f7358SJed Brown const PetscScalar g_xz = y5 - y1 - y4 + y0; 897552f7358SJed Brown const PetscScalar h_xz = z5 - z1 - z4 + z0; 898552f7358SJed Brown const PetscScalar f_xyz = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7; 899552f7358SJed Brown const PetscScalar g_xyz = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7; 900552f7358SJed Brown const PetscScalar h_xyz = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7; 90156044e6dSMatthew G. Knepley const PetscScalar *ref; 902552f7358SJed Brown 903552f7358SJed Brown PetscFunctionBegin; 9049566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(Xref, &ref)); 905552f7358SJed Brown { 906552f7358SJed Brown const PetscScalar x = ref[0]; 907552f7358SJed Brown const PetscScalar y = ref[1]; 908552f7358SJed Brown const PetscScalar z = ref[2]; 909552f7358SJed Brown const PetscInt rows[3] = {0, 1, 2}; 910da80777bSKarl Rupp PetscScalar values[9]; 911da80777bSKarl Rupp 912da80777bSKarl Rupp values[0] = (x1 - x0 + f_xy * y + f_xz * z + f_xyz * y * z) / 2.0; 913da80777bSKarl Rupp values[1] = (x3 - x0 + f_xy * x + f_yz * z + f_xyz * x * z) / 2.0; 914da80777bSKarl Rupp values[2] = (x4 - x0 + f_yz * y + f_xz * x + f_xyz * x * y) / 2.0; 915da80777bSKarl Rupp values[3] = (y1 - y0 + g_xy * y + g_xz * z + g_xyz * y * z) / 2.0; 916da80777bSKarl Rupp values[4] = (y3 - y0 + g_xy * x + g_yz * z + g_xyz * x * z) / 2.0; 917da80777bSKarl Rupp values[5] = (y4 - y0 + g_yz * y + g_xz * x + g_xyz * x * y) / 2.0; 918da80777bSKarl Rupp values[6] = (z1 - z0 + h_xy * y + h_xz * z + h_xyz * y * z) / 2.0; 919da80777bSKarl Rupp values[7] = (z3 - z0 + h_xy * x + h_yz * z + h_xyz * x * z) / 2.0; 920da80777bSKarl Rupp values[8] = (z4 - z0 + h_yz * y + h_xz * x + h_xyz * x * y) / 2.0; 9211aa26658SKarl Rupp 9229566063dSJacob Faibussowitsch PetscCall(MatSetValues(J, 3, rows, 3, rows, values, INSERT_VALUES)); 923552f7358SJed Brown } 9249566063dSJacob Faibussowitsch PetscCall(PetscLogFlops(152)); 9259566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(Xref, &ref)); 9269566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY)); 9279566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY)); 9283ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 929552f7358SJed Brown } 930552f7358SJed Brown 931d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Hex_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 932d71ae5a4SJacob Faibussowitsch { 933fafc0619SMatthew G Knepley DM dmCoord; 934552f7358SJed Brown SNES snes; 935552f7358SJed Brown KSP ksp; 936552f7358SJed Brown PC pc; 937552f7358SJed Brown Vec coordsLocal, r, ref, real; 938552f7358SJed Brown Mat J; 93956044e6dSMatthew G. Knepley const PetscScalar *coords; 94056044e6dSMatthew G. Knepley PetscScalar *a; 941552f7358SJed Brown PetscInt p; 942552f7358SJed Brown 943552f7358SJed Brown PetscFunctionBegin; 9449566063dSJacob Faibussowitsch PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9459566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDM(dm, &dmCoord)); 9469566063dSJacob Faibussowitsch PetscCall(SNESCreate(PETSC_COMM_SELF, &snes)); 9479566063dSJacob Faibussowitsch PetscCall(SNESSetOptionsPrefix(snes, "hex_interp_")); 9489566063dSJacob Faibussowitsch PetscCall(VecCreate(PETSC_COMM_SELF, &r)); 9499566063dSJacob Faibussowitsch PetscCall(VecSetSizes(r, 3, 3)); 9509566063dSJacob Faibussowitsch PetscCall(VecSetType(r, dm->vectype)); 9519566063dSJacob Faibussowitsch PetscCall(VecDuplicate(r, &ref)); 9529566063dSJacob Faibussowitsch PetscCall(VecDuplicate(r, &real)); 9539566063dSJacob Faibussowitsch PetscCall(MatCreate(PETSC_COMM_SELF, &J)); 9549566063dSJacob Faibussowitsch PetscCall(MatSetSizes(J, 3, 3, 3, 3)); 9559566063dSJacob Faibussowitsch PetscCall(MatSetType(J, MATSEQDENSE)); 9569566063dSJacob Faibussowitsch PetscCall(MatSetUp(J)); 9579566063dSJacob Faibussowitsch PetscCall(SNESSetFunction(snes, r, HexMap_Private, NULL)); 9589566063dSJacob Faibussowitsch PetscCall(SNESSetJacobian(snes, J, J, HexJacobian_Private, NULL)); 9599566063dSJacob Faibussowitsch PetscCall(SNESGetKSP(snes, &ksp)); 9609566063dSJacob Faibussowitsch PetscCall(KSPGetPC(ksp, &pc)); 9619566063dSJacob Faibussowitsch PetscCall(PCSetType(pc, PCLU)); 9629566063dSJacob Faibussowitsch PetscCall(SNESSetFromOptions(snes)); 963552f7358SJed Brown 9649566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 9659566063dSJacob Faibussowitsch PetscCall(VecGetArray(v, &a)); 966552f7358SJed Brown for (p = 0; p < ctx->n; ++p) { 967a1e44745SMatthew G. Knepley PetscScalar *x = NULL, *vertices = NULL; 968552f7358SJed Brown PetscScalar *xi; 969cb313848SJed Brown PetscReal xir[3]; 970552f7358SJed Brown PetscInt c = ctx->cells[p], comp, coordSize, xSize; 971552f7358SJed Brown 972552f7358SJed Brown /* Can make this do all points at once */ 9739566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices)); 974cfe5744fSMatthew G. Knepley PetscCheck(8 * 3 == coordSize, ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid coordinate closure size %" PetscInt_FMT " should be %d", coordSize, 8 * 3); 9759566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x)); 976cfe5744fSMatthew G. Knepley PetscCheck((8 * ctx->dof == xSize) || (ctx->dof == xSize), ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid input closure size %" PetscInt_FMT " should be %" PetscInt_FMT " or %" PetscInt_FMT, xSize, 8 * ctx->dof, ctx->dof); 9779566063dSJacob Faibussowitsch PetscCall(SNESSetFunction(snes, NULL, NULL, vertices)); 9789566063dSJacob Faibussowitsch PetscCall(SNESSetJacobian(snes, NULL, NULL, NULL, vertices)); 9799566063dSJacob Faibussowitsch PetscCall(VecGetArray(real, &xi)); 980552f7358SJed Brown xi[0] = coords[p * ctx->dim + 0]; 981552f7358SJed Brown xi[1] = coords[p * ctx->dim + 1]; 982552f7358SJed Brown xi[2] = coords[p * ctx->dim + 2]; 9839566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(real, &xi)); 9849566063dSJacob Faibussowitsch PetscCall(SNESSolve(snes, real, ref)); 9859566063dSJacob Faibussowitsch PetscCall(VecGetArray(ref, &xi)); 986cb313848SJed Brown xir[0] = PetscRealPart(xi[0]); 987cb313848SJed Brown xir[1] = PetscRealPart(xi[1]); 988cb313848SJed Brown xir[2] = PetscRealPart(xi[2]); 989cfe5744fSMatthew G. Knepley if (8 * ctx->dof == xSize) { 990552f7358SJed Brown for (comp = 0; comp < ctx->dof; ++comp) { 9919371c9d4SSatish Balay a[p * ctx->dof + comp] = x[0 * ctx->dof + comp] * (1 - xir[0]) * (1 - xir[1]) * (1 - xir[2]) + x[3 * ctx->dof + comp] * xir[0] * (1 - xir[1]) * (1 - xir[2]) + x[2 * ctx->dof + comp] * xir[0] * xir[1] * (1 - xir[2]) + x[1 * ctx->dof + comp] * (1 - xir[0]) * xir[1] * (1 - xir[2]) + 9929371c9d4SSatish Balay x[4 * ctx->dof + comp] * (1 - xir[0]) * (1 - xir[1]) * xir[2] + x[5 * ctx->dof + comp] * xir[0] * (1 - xir[1]) * xir[2] + x[6 * ctx->dof + comp] * xir[0] * xir[1] * xir[2] + x[7 * ctx->dof + comp] * (1 - xir[0]) * xir[1] * xir[2]; 993552f7358SJed Brown } 994cfe5744fSMatthew G. Knepley } else { 995cfe5744fSMatthew G. Knepley for (comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp]; 996cfe5744fSMatthew G. Knepley } 9979566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(ref, &xi)); 9989566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices)); 9999566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x)); 1000552f7358SJed Brown } 10019566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(v, &a)); 10029566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 1003552f7358SJed Brown 10049566063dSJacob Faibussowitsch PetscCall(SNESDestroy(&snes)); 10059566063dSJacob Faibussowitsch PetscCall(VecDestroy(&r)); 10069566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ref)); 10079566063dSJacob Faibussowitsch PetscCall(VecDestroy(&real)); 10089566063dSJacob Faibussowitsch PetscCall(MatDestroy(&J)); 10093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1010552f7358SJed Brown } 1011552f7358SJed Brown 10124267b1a3SMatthew G. Knepley /*@C 10134267b1a3SMatthew G. Knepley DMInterpolationEvaluate - Using the input from dm and x, calculates interpolated field values at the interpolation points. 10144267b1a3SMatthew G. Knepley 1015552f7358SJed Brown Input Parameters: 1016f6dfbefdSBarry Smith + ctx - The `DMInterpolationInfo` context 1017f6dfbefdSBarry Smith . dm - The `DM` 1018552f7358SJed Brown - x - The local vector containing the field to be interpolated 1019552f7358SJed Brown 10202fe279fdSBarry Smith Output Parameter: 1021552f7358SJed Brown . v - The vector containing the interpolated values 10224267b1a3SMatthew G. Knepley 10234267b1a3SMatthew G. Knepley Level: beginner 10244267b1a3SMatthew G. Knepley 10252fe279fdSBarry Smith Note: 10262fe279fdSBarry Smith A suitable `v` can be obtained using `DMInterpolationGetVector()`. 10272fe279fdSBarry Smith 1028f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetVector()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 10294267b1a3SMatthew G. Knepley @*/ 1030d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationEvaluate(DMInterpolationInfo ctx, DM dm, Vec x, Vec v) 1031d71ae5a4SJacob Faibussowitsch { 103266a0a883SMatthew G. Knepley PetscDS ds; 103366a0a883SMatthew G. Knepley PetscInt n, p, Nf, field; 103466a0a883SMatthew G. Knepley PetscBool useDS = PETSC_FALSE; 1035552f7358SJed Brown 1036552f7358SJed Brown PetscFunctionBegin; 1037552f7358SJed Brown PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 1038552f7358SJed Brown PetscValidHeaderSpecific(x, VEC_CLASSID, 3); 1039552f7358SJed Brown PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 10409566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(v, &n)); 104163a3b9bcSJacob Faibussowitsch PetscCheck(n == ctx->n * ctx->dof, ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid input vector size %" PetscInt_FMT " should be %" PetscInt_FMT, n, ctx->n * ctx->dof); 10423ba16761SJacob Faibussowitsch if (!n) PetscFunctionReturn(PETSC_SUCCESS); 10439566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &ds)); 1044680d18d5SMatthew G. Knepley if (ds) { 104566a0a883SMatthew G. Knepley useDS = PETSC_TRUE; 10469566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 1047680d18d5SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 104866a0a883SMatthew G. Knepley PetscObject obj; 1049680d18d5SMatthew G. Knepley PetscClassId id; 1050680d18d5SMatthew G. Knepley 10519566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, field, &obj)); 10529566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 10539371c9d4SSatish Balay if (id != PETSCFE_CLASSID) { 10549371c9d4SSatish Balay useDS = PETSC_FALSE; 10559371c9d4SSatish Balay break; 10569371c9d4SSatish Balay } 105766a0a883SMatthew G. Knepley } 105866a0a883SMatthew G. Knepley } 105966a0a883SMatthew G. Knepley if (useDS) { 106066a0a883SMatthew G. Knepley const PetscScalar *coords; 106166a0a883SMatthew G. Knepley PetscScalar *interpolant; 106266a0a883SMatthew G. Knepley PetscInt cdim, d; 106366a0a883SMatthew G. Knepley 10649566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &cdim)); 10659566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 10669566063dSJacob Faibussowitsch PetscCall(VecGetArrayWrite(v, &interpolant)); 1067680d18d5SMatthew G. Knepley for (p = 0; p < ctx->n; ++p) { 106866a0a883SMatthew G. Knepley PetscReal pcoords[3], xi[3]; 1069680d18d5SMatthew G. Knepley PetscScalar *xa = NULL; 107066a0a883SMatthew G. Knepley PetscInt coff = 0, foff = 0, clSize; 1071680d18d5SMatthew G. Knepley 107252aa1562SMatthew G. Knepley if (ctx->cells[p] < 0) continue; 1073680d18d5SMatthew G. Knepley for (d = 0; d < cdim; ++d) pcoords[d] = PetscRealPart(coords[p * cdim + d]); 10749566063dSJacob Faibussowitsch PetscCall(DMPlexCoordinatesToReference(dm, ctx->cells[p], 1, pcoords, xi)); 10759566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa)); 107666a0a883SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 107766a0a883SMatthew G. Knepley PetscTabulation T; 107866a0a883SMatthew G. Knepley PetscFE fe; 107966a0a883SMatthew G. Knepley 10809566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *)&fe)); 10819566063dSJacob Faibussowitsch PetscCall(PetscFECreateTabulation(fe, 1, 1, xi, 0, &T)); 1082680d18d5SMatthew G. Knepley { 1083680d18d5SMatthew G. Knepley const PetscReal *basis = T->T[0]; 1084680d18d5SMatthew G. Knepley const PetscInt Nb = T->Nb; 1085680d18d5SMatthew G. Knepley const PetscInt Nc = T->Nc; 108666a0a883SMatthew G. Knepley PetscInt f, fc; 108766a0a883SMatthew G. Knepley 1088680d18d5SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 108966a0a883SMatthew G. Knepley interpolant[p * ctx->dof + coff + fc] = 0.0; 1090ad540459SPierre Jolivet for (f = 0; f < Nb; ++f) interpolant[p * ctx->dof + coff + fc] += xa[foff + f] * basis[(0 * Nb + f) * Nc + fc]; 1091680d18d5SMatthew G. Knepley } 109266a0a883SMatthew G. Knepley coff += Nc; 109366a0a883SMatthew G. Knepley foff += Nb; 1094680d18d5SMatthew G. Knepley } 10959566063dSJacob Faibussowitsch PetscCall(PetscTabulationDestroy(&T)); 1096680d18d5SMatthew G. Knepley } 10979566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa)); 109863a3b9bcSJacob Faibussowitsch PetscCheck(coff == ctx->dof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total components %" PetscInt_FMT " != %" PetscInt_FMT " dof specified for interpolation", coff, ctx->dof); 109963a3b9bcSJacob Faibussowitsch PetscCheck(foff == clSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total FE space size %" PetscInt_FMT " != %" PetscInt_FMT " closure size", foff, clSize); 110066a0a883SMatthew G. Knepley } 11019566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 11029566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayWrite(v, &interpolant)); 110366a0a883SMatthew G. Knepley } else { 110466a0a883SMatthew G. Knepley DMPolytopeType ct; 110566a0a883SMatthew G. Knepley 1106680d18d5SMatthew G. Knepley /* TODO Check each cell individually */ 11079566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellType(dm, ctx->cells[0], &ct)); 1108680d18d5SMatthew G. Knepley switch (ct) { 1109d71ae5a4SJacob Faibussowitsch case DM_POLYTOPE_SEGMENT: 1110d71ae5a4SJacob Faibussowitsch PetscCall(DMInterpolate_Segment_Private(ctx, dm, x, v)); 1111d71ae5a4SJacob Faibussowitsch break; 1112d71ae5a4SJacob Faibussowitsch case DM_POLYTOPE_TRIANGLE: 1113d71ae5a4SJacob Faibussowitsch PetscCall(DMInterpolate_Triangle_Private(ctx, dm, x, v)); 1114d71ae5a4SJacob Faibussowitsch break; 1115d71ae5a4SJacob Faibussowitsch case DM_POLYTOPE_QUADRILATERAL: 1116d71ae5a4SJacob Faibussowitsch PetscCall(DMInterpolate_Quad_Private(ctx, dm, x, v)); 1117d71ae5a4SJacob Faibussowitsch break; 1118d71ae5a4SJacob Faibussowitsch case DM_POLYTOPE_TETRAHEDRON: 1119d71ae5a4SJacob Faibussowitsch PetscCall(DMInterpolate_Tetrahedron_Private(ctx, dm, x, v)); 1120d71ae5a4SJacob Faibussowitsch break; 1121d71ae5a4SJacob Faibussowitsch case DM_POLYTOPE_HEXAHEDRON: 1122d71ae5a4SJacob Faibussowitsch PetscCall(DMInterpolate_Hex_Private(ctx, dm, x, v)); 1123d71ae5a4SJacob Faibussowitsch break; 1124d71ae5a4SJacob Faibussowitsch default: 1125d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for cell type %s", DMPolytopeTypes[PetscMax(0, PetscMin(ct, DM_NUM_POLYTOPES))]); 1126680d18d5SMatthew G. Knepley } 1127552f7358SJed Brown } 11283ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1129552f7358SJed Brown } 1130552f7358SJed Brown 11314267b1a3SMatthew G. Knepley /*@C 1132f6dfbefdSBarry Smith DMInterpolationDestroy - Destroys a `DMInterpolationInfo` context 11334267b1a3SMatthew G. Knepley 1134c3339decSBarry Smith Collective 11354267b1a3SMatthew G. Knepley 11364267b1a3SMatthew G. Knepley Input Parameter: 11374267b1a3SMatthew G. Knepley . ctx - the context 11384267b1a3SMatthew G. Knepley 11394267b1a3SMatthew G. Knepley Level: beginner 11404267b1a3SMatthew G. Knepley 1141f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 11424267b1a3SMatthew G. Knepley @*/ 1143d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationDestroy(DMInterpolationInfo *ctx) 1144d71ae5a4SJacob Faibussowitsch { 1145552f7358SJed Brown PetscFunctionBegin; 1146064a246eSJacob Faibussowitsch PetscValidPointer(ctx, 1); 11479566063dSJacob Faibussowitsch PetscCall(VecDestroy(&(*ctx)->coords)); 11489566063dSJacob Faibussowitsch PetscCall(PetscFree((*ctx)->points)); 11499566063dSJacob Faibussowitsch PetscCall(PetscFree((*ctx)->cells)); 11509566063dSJacob Faibussowitsch PetscCall(PetscFree(*ctx)); 11510298fd71SBarry Smith *ctx = NULL; 11523ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1153552f7358SJed Brown } 1154cc0c4584SMatthew G. Knepley 1155cc0c4584SMatthew G. Knepley /*@C 1156cc0c4584SMatthew G. Knepley SNESMonitorFields - Monitors the residual for each field separately 1157cc0c4584SMatthew G. Knepley 1158c3339decSBarry Smith Collective 1159cc0c4584SMatthew G. Knepley 1160cc0c4584SMatthew G. Knepley Input Parameters: 1161f6dfbefdSBarry Smith + snes - the `SNES` context 1162cc0c4584SMatthew G. Knepley . its - iteration number 1163cc0c4584SMatthew G. Knepley . fgnorm - 2-norm of residual 1164f6dfbefdSBarry Smith - vf - `PetscViewerAndFormat` of `PetscViewerType` `PETSCVIEWERASCII` 1165cc0c4584SMatthew G. Knepley 11662fe279fdSBarry Smith Level: intermediate 11672fe279fdSBarry Smith 1168f6dfbefdSBarry Smith Note: 1169cc0c4584SMatthew G. Knepley This routine prints the residual norm at each iteration. 1170cc0c4584SMatthew G. Knepley 1171f6dfbefdSBarry Smith .seealso: `SNES`, `SNESMonitorSet()`, `SNESMonitorDefault()` 1172cc0c4584SMatthew G. Knepley @*/ 1173d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESMonitorFields(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf) 1174d71ae5a4SJacob Faibussowitsch { 1175d43b4f6eSBarry Smith PetscViewer viewer = vf->viewer; 1176cc0c4584SMatthew G. Knepley Vec res; 1177cc0c4584SMatthew G. Knepley DM dm; 1178cc0c4584SMatthew G. Knepley PetscSection s; 1179cc0c4584SMatthew G. Knepley const PetscScalar *r; 1180cc0c4584SMatthew G. Knepley PetscReal *lnorms, *norms; 1181cc0c4584SMatthew G. Knepley PetscInt numFields, f, pStart, pEnd, p; 1182cc0c4584SMatthew G. Knepley 1183cc0c4584SMatthew G. Knepley PetscFunctionBegin; 11844d4332d5SBarry Smith PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4); 11859566063dSJacob Faibussowitsch PetscCall(SNESGetFunction(snes, &res, NULL, NULL)); 11869566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &dm)); 11879566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 11889566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(s, &numFields)); 11899566063dSJacob Faibussowitsch PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 11909566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFields, &lnorms, numFields, &norms)); 11919566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(res, &r)); 1192cc0c4584SMatthew G. Knepley for (p = pStart; p < pEnd; ++p) { 1193cc0c4584SMatthew G. Knepley for (f = 0; f < numFields; ++f) { 1194cc0c4584SMatthew G. Knepley PetscInt fdof, foff, d; 1195cc0c4584SMatthew G. Knepley 11969566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, p, f, &fdof)); 11979566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldOffset(s, p, f, &foff)); 1198cc0c4584SMatthew G. Knepley for (d = 0; d < fdof; ++d) lnorms[f] += PetscRealPart(PetscSqr(r[foff + d])); 1199cc0c4584SMatthew G. Knepley } 1200cc0c4584SMatthew G. Knepley } 12019566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(res, &r)); 12021c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(lnorms, norms, numFields, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 12039566063dSJacob Faibussowitsch PetscCall(PetscViewerPushFormat(viewer, vf->format)); 12049566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)snes)->tablevel)); 120563a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %14.12e [", its, (double)fgnorm)); 1206cc0c4584SMatthew G. Knepley for (f = 0; f < numFields; ++f) { 12079566063dSJacob Faibussowitsch if (f > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 12089566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "%14.12e", (double)PetscSqrtReal(norms[f]))); 1209cc0c4584SMatthew G. Knepley } 12109566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "]\n")); 12119566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)snes)->tablevel)); 12129566063dSJacob Faibussowitsch PetscCall(PetscViewerPopFormat(viewer)); 12139566063dSJacob Faibussowitsch PetscCall(PetscFree2(lnorms, norms)); 12143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1215cc0c4584SMatthew G. Knepley } 121624cdb843SMatthew G. Knepley 121724cdb843SMatthew G. Knepley /********************* Residual Computation **************************/ 121824cdb843SMatthew G. Knepley 1219d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 1220d71ae5a4SJacob Faibussowitsch { 12216528b96dSMatthew G. Knepley PetscInt depth; 12226528b96dSMatthew G. Knepley 12236528b96dSMatthew G. Knepley PetscFunctionBegin; 12249566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepth(plex, &depth)); 12259566063dSJacob Faibussowitsch PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 12269566063dSJacob Faibussowitsch if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 12273ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 12286528b96dSMatthew G. Knepley } 12296528b96dSMatthew G. Knepley 123024cdb843SMatthew G. Knepley /*@ 12318db23a53SJed Brown DMPlexSNESComputeResidualFEM - Sums the local residual into vector F from the local input X using pointwise functions specified by the user 123224cdb843SMatthew G. Knepley 123324cdb843SMatthew G. Knepley Input Parameters: 123424cdb843SMatthew G. Knepley + dm - The mesh 123524cdb843SMatthew G. Knepley . X - Local solution 123624cdb843SMatthew G. Knepley - user - The user context 123724cdb843SMatthew G. Knepley 123824cdb843SMatthew G. Knepley Output Parameter: 123924cdb843SMatthew G. Knepley . F - Local output vector 124024cdb843SMatthew G. Knepley 12412fe279fdSBarry Smith Level: developer 12422fe279fdSBarry Smith 1243f6dfbefdSBarry Smith Note: 1244f6dfbefdSBarry Smith The residual is summed into F; the caller is responsible for using `VecZeroEntries()` or otherwise ensuring that any data in F is intentional. 12458db23a53SJed Brown 1246f6dfbefdSBarry Smith .seealso: `DM`, `DMPlexComputeJacobianAction()` 124724cdb843SMatthew G. Knepley @*/ 1248d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSNESComputeResidualFEM(DM dm, Vec X, Vec F, void *user) 1249d71ae5a4SJacob Faibussowitsch { 12506da023fcSToby Isaac DM plex; 1251083401c6SMatthew G. Knepley IS allcellIS; 12526528b96dSMatthew G. Knepley PetscInt Nds, s; 125324cdb843SMatthew G. Knepley 125424cdb843SMatthew G. Knepley PetscFunctionBegin; 12559566063dSJacob Faibussowitsch PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 12569566063dSJacob Faibussowitsch PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS)); 12579566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 12586528b96dSMatthew G. Knepley for (s = 0; s < Nds; ++s) { 12596528b96dSMatthew G. Knepley PetscDS ds; 12606528b96dSMatthew G. Knepley IS cellIS; 126106ad1575SMatthew G. Knepley PetscFormKey key; 12626528b96dSMatthew G. Knepley 126307218a29SMatthew G. Knepley PetscCall(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds, NULL)); 12646528b96dSMatthew G. Knepley key.value = 0; 12656528b96dSMatthew G. Knepley key.field = 0; 126606ad1575SMatthew G. Knepley key.part = 0; 12676528b96dSMatthew G. Knepley if (!key.label) { 12689566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)allcellIS)); 12696528b96dSMatthew G. Knepley cellIS = allcellIS; 12706528b96dSMatthew G. Knepley } else { 12716528b96dSMatthew G. Knepley IS pointIS; 12726528b96dSMatthew G. Knepley 12736528b96dSMatthew G. Knepley key.value = 1; 12749566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 12759566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS)); 12769566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 12776528b96dSMatthew G. Knepley } 12789566063dSJacob Faibussowitsch PetscCall(DMPlexComputeResidual_Internal(plex, key, cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user)); 12799566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 12806528b96dSMatthew G. Knepley } 12819566063dSJacob Faibussowitsch PetscCall(ISDestroy(&allcellIS)); 12829566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 12833ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 12846528b96dSMatthew G. Knepley } 12856528b96dSMatthew G. Knepley 1286d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESComputeResidual(DM dm, Vec X, Vec F, void *user) 1287d71ae5a4SJacob Faibussowitsch { 12886528b96dSMatthew G. Knepley DM plex; 12896528b96dSMatthew G. Knepley IS allcellIS; 12906528b96dSMatthew G. Knepley PetscInt Nds, s; 12916528b96dSMatthew G. Knepley 12926528b96dSMatthew G. Knepley PetscFunctionBegin; 12939566063dSJacob Faibussowitsch PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 12949566063dSJacob Faibussowitsch PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS)); 12959566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 1296083401c6SMatthew G. Knepley for (s = 0; s < Nds; ++s) { 1297083401c6SMatthew G. Knepley PetscDS ds; 1298083401c6SMatthew G. Knepley DMLabel label; 1299083401c6SMatthew G. Knepley IS cellIS; 1300083401c6SMatthew G. Knepley 130107218a29SMatthew G. Knepley PetscCall(DMGetRegionNumDS(dm, s, &label, NULL, &ds, NULL)); 13026528b96dSMatthew G. Knepley { 130306ad1575SMatthew G. Knepley PetscWeakFormKind resmap[2] = {PETSC_WF_F0, PETSC_WF_F1}; 13046528b96dSMatthew G. Knepley PetscWeakForm wf; 13056528b96dSMatthew G. Knepley PetscInt Nm = 2, m, Nk = 0, k, kp, off = 0; 130606ad1575SMatthew G. Knepley PetscFormKey *reskeys; 13076528b96dSMatthew G. Knepley 13086528b96dSMatthew G. Knepley /* Get unique residual keys */ 13096528b96dSMatthew G. Knepley for (m = 0; m < Nm; ++m) { 13106528b96dSMatthew G. Knepley PetscInt Nkm; 13119566063dSJacob Faibussowitsch PetscCall(PetscHMapFormGetSize(ds->wf->form[resmap[m]], &Nkm)); 13126528b96dSMatthew G. Knepley Nk += Nkm; 13136528b96dSMatthew G. Knepley } 13149566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nk, &reskeys)); 131548a46eb9SPierre Jolivet for (m = 0; m < Nm; ++m) PetscCall(PetscHMapFormGetKeys(ds->wf->form[resmap[m]], &off, reskeys)); 131663a3b9bcSJacob Faibussowitsch PetscCheck(off == Nk, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %" PetscInt_FMT " should be %" PetscInt_FMT, off, Nk); 13179566063dSJacob Faibussowitsch PetscCall(PetscFormKeySort(Nk, reskeys)); 13186528b96dSMatthew G. Knepley for (k = 0, kp = 1; kp < Nk; ++kp) { 13196528b96dSMatthew G. Knepley if ((reskeys[k].label != reskeys[kp].label) || (reskeys[k].value != reskeys[kp].value)) { 13206528b96dSMatthew G. Knepley ++k; 13216528b96dSMatthew G. Knepley if (kp != k) reskeys[k] = reskeys[kp]; 13226528b96dSMatthew G. Knepley } 13236528b96dSMatthew G. Knepley } 13246528b96dSMatthew G. Knepley Nk = k; 13256528b96dSMatthew G. Knepley 13269566063dSJacob Faibussowitsch PetscCall(PetscDSGetWeakForm(ds, &wf)); 13276528b96dSMatthew G. Knepley for (k = 0; k < Nk; ++k) { 13286528b96dSMatthew G. Knepley DMLabel label = reskeys[k].label; 13296528b96dSMatthew G. Knepley PetscInt val = reskeys[k].value; 13306528b96dSMatthew G. Knepley 1331083401c6SMatthew G. Knepley if (!label) { 13329566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)allcellIS)); 1333083401c6SMatthew G. Knepley cellIS = allcellIS; 1334083401c6SMatthew G. Knepley } else { 1335083401c6SMatthew G. Knepley IS pointIS; 1336083401c6SMatthew G. Knepley 13379566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, val, &pointIS)); 13389566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS)); 13399566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 13404a3e9fdbSToby Isaac } 13419566063dSJacob Faibussowitsch PetscCall(DMPlexComputeResidual_Internal(plex, reskeys[k], cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user)); 13429566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 1343083401c6SMatthew G. Knepley } 13449566063dSJacob Faibussowitsch PetscCall(PetscFree(reskeys)); 13456528b96dSMatthew G. Knepley } 13466528b96dSMatthew G. Knepley } 13479566063dSJacob Faibussowitsch PetscCall(ISDestroy(&allcellIS)); 13489566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 13493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 135024cdb843SMatthew G. Knepley } 135124cdb843SMatthew G. Knepley 1352bdd6f66aSToby Isaac /*@ 1353bdd6f66aSToby Isaac DMPlexSNESComputeBoundaryFEM - Form the boundary values for the local input X 1354bdd6f66aSToby Isaac 1355bdd6f66aSToby Isaac Input Parameters: 1356bdd6f66aSToby Isaac + dm - The mesh 1357bdd6f66aSToby Isaac - user - The user context 1358bdd6f66aSToby Isaac 1359bdd6f66aSToby Isaac Output Parameter: 1360bdd6f66aSToby Isaac . X - Local solution 1361bdd6f66aSToby Isaac 1362bdd6f66aSToby Isaac Level: developer 1363bdd6f66aSToby Isaac 1364f6dfbefdSBarry Smith .seealso: `DMPLEX`, `DMPlexComputeJacobianAction()` 1365bdd6f66aSToby Isaac @*/ 1366d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSNESComputeBoundaryFEM(DM dm, Vec X, void *user) 1367d71ae5a4SJacob Faibussowitsch { 1368bdd6f66aSToby Isaac DM plex; 1369bdd6f66aSToby Isaac 1370bdd6f66aSToby Isaac PetscFunctionBegin; 13719566063dSJacob Faibussowitsch PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 13729566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, X, PETSC_MIN_REAL, NULL, NULL, NULL)); 13739566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 13743ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1375bdd6f66aSToby Isaac } 1376bdd6f66aSToby Isaac 13777a73cf09SMatthew G. Knepley /*@ 13788e3a2eefSMatthew G. Knepley DMSNESComputeJacobianAction - Compute the action of the Jacobian J(X) on Y 13797a73cf09SMatthew G. Knepley 13807a73cf09SMatthew G. Knepley Input Parameters: 1381f6dfbefdSBarry Smith + dm - The `DM` 13827a73cf09SMatthew G. Knepley . X - Local solution vector 13837a73cf09SMatthew G. Knepley . Y - Local input vector 13847a73cf09SMatthew G. Knepley - user - The user context 13857a73cf09SMatthew G. Knepley 13867a73cf09SMatthew G. Knepley Output Parameter: 138769d47153SPierre Jolivet . F - local output vector 13887a73cf09SMatthew G. Knepley 13897a73cf09SMatthew G. Knepley Level: developer 13907a73cf09SMatthew G. Knepley 13918e3a2eefSMatthew G. Knepley Notes: 1392f6dfbefdSBarry Smith Users will typically use `DMSNESCreateJacobianMF()` followed by `MatMult()` instead of calling this routine directly. 13938e3a2eefSMatthew G. Knepley 1394f6dfbefdSBarry Smith .seealso: `DM`, ``DMSNESCreateJacobianMF()`, `DMPlexSNESComputeResidualFEM()` 13957a73cf09SMatthew G. Knepley @*/ 1396d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESComputeJacobianAction(DM dm, Vec X, Vec Y, Vec F, void *user) 1397d71ae5a4SJacob Faibussowitsch { 13988e3a2eefSMatthew G. Knepley DM plex; 13998e3a2eefSMatthew G. Knepley IS allcellIS; 14008e3a2eefSMatthew G. Knepley PetscInt Nds, s; 1401a925c78cSMatthew G. Knepley 1402a925c78cSMatthew G. Knepley PetscFunctionBegin; 14039566063dSJacob Faibussowitsch PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 14049566063dSJacob Faibussowitsch PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS)); 14059566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 14068e3a2eefSMatthew G. Knepley for (s = 0; s < Nds; ++s) { 14078e3a2eefSMatthew G. Knepley PetscDS ds; 14088e3a2eefSMatthew G. Knepley DMLabel label; 14098e3a2eefSMatthew G. Knepley IS cellIS; 14107a73cf09SMatthew G. Knepley 141107218a29SMatthew G. Knepley PetscCall(DMGetRegionNumDS(dm, s, &label, NULL, &ds, NULL)); 14128e3a2eefSMatthew G. Knepley { 141306ad1575SMatthew G. Knepley PetscWeakFormKind jacmap[4] = {PETSC_WF_G0, PETSC_WF_G1, PETSC_WF_G2, PETSC_WF_G3}; 14148e3a2eefSMatthew G. Knepley PetscWeakForm wf; 14158e3a2eefSMatthew G. Knepley PetscInt Nm = 4, m, Nk = 0, k, kp, off = 0; 141606ad1575SMatthew G. Knepley PetscFormKey *jackeys; 14178e3a2eefSMatthew G. Knepley 14188e3a2eefSMatthew G. Knepley /* Get unique Jacobian keys */ 14198e3a2eefSMatthew G. Knepley for (m = 0; m < Nm; ++m) { 14208e3a2eefSMatthew G. Knepley PetscInt Nkm; 14219566063dSJacob Faibussowitsch PetscCall(PetscHMapFormGetSize(ds->wf->form[jacmap[m]], &Nkm)); 14228e3a2eefSMatthew G. Knepley Nk += Nkm; 14238e3a2eefSMatthew G. Knepley } 14249566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nk, &jackeys)); 142548a46eb9SPierre Jolivet for (m = 0; m < Nm; ++m) PetscCall(PetscHMapFormGetKeys(ds->wf->form[jacmap[m]], &off, jackeys)); 142663a3b9bcSJacob Faibussowitsch PetscCheck(off == Nk, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %" PetscInt_FMT " should be %" PetscInt_FMT, off, Nk); 14279566063dSJacob Faibussowitsch PetscCall(PetscFormKeySort(Nk, jackeys)); 14288e3a2eefSMatthew G. Knepley for (k = 0, kp = 1; kp < Nk; ++kp) { 14298e3a2eefSMatthew G. Knepley if ((jackeys[k].label != jackeys[kp].label) || (jackeys[k].value != jackeys[kp].value)) { 14308e3a2eefSMatthew G. Knepley ++k; 14318e3a2eefSMatthew G. Knepley if (kp != k) jackeys[k] = jackeys[kp]; 14328e3a2eefSMatthew G. Knepley } 14338e3a2eefSMatthew G. Knepley } 14348e3a2eefSMatthew G. Knepley Nk = k; 14358e3a2eefSMatthew G. Knepley 14369566063dSJacob Faibussowitsch PetscCall(PetscDSGetWeakForm(ds, &wf)); 14378e3a2eefSMatthew G. Knepley for (k = 0; k < Nk; ++k) { 14388e3a2eefSMatthew G. Knepley DMLabel label = jackeys[k].label; 14398e3a2eefSMatthew G. Knepley PetscInt val = jackeys[k].value; 14408e3a2eefSMatthew G. Knepley 14418e3a2eefSMatthew G. Knepley if (!label) { 14429566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)allcellIS)); 14438e3a2eefSMatthew G. Knepley cellIS = allcellIS; 14447a73cf09SMatthew G. Knepley } else { 14458e3a2eefSMatthew G. Knepley IS pointIS; 1446a925c78cSMatthew G. Knepley 14479566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, val, &pointIS)); 14489566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS)); 14499566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 1450a925c78cSMatthew G. Knepley } 14519566063dSJacob Faibussowitsch PetscCall(DMPlexComputeJacobian_Action_Internal(plex, jackeys[k], cellIS, 0.0, 0.0, X, NULL, Y, F, user)); 14529566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 14538e3a2eefSMatthew G. Knepley } 14549566063dSJacob Faibussowitsch PetscCall(PetscFree(jackeys)); 14558e3a2eefSMatthew G. Knepley } 14568e3a2eefSMatthew G. Knepley } 14579566063dSJacob Faibussowitsch PetscCall(ISDestroy(&allcellIS)); 14589566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 14593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1460a925c78cSMatthew G. Knepley } 1461a925c78cSMatthew G. Knepley 146224cdb843SMatthew G. Knepley /*@ 14632fe279fdSBarry Smith DMPlexSNESComputeJacobianFEM - Form the local portion of the Jacobian matrix `Jac` at the local solution `X` using pointwise functions specified by the user. 146424cdb843SMatthew G. Knepley 146524cdb843SMatthew G. Knepley Input Parameters: 14662fe279fdSBarry Smith + dm - The `DM` 146724cdb843SMatthew G. Knepley . X - Local input vector 146824cdb843SMatthew G. Knepley - user - The user context 146924cdb843SMatthew G. Knepley 14702fe279fdSBarry Smith Output Parameters: 14712fe279fdSBarry Smith + Jac - Jacobian matrix 14722fe279fdSBarry Smith - JacP - approximate Jacobian from which the preconditioner will be built, often `Jac` 14732fe279fdSBarry Smith 14742fe279fdSBarry Smith Level: developer 147524cdb843SMatthew G. Knepley 147624cdb843SMatthew G. Knepley Note: 147724cdb843SMatthew G. Knepley We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator, 147824cdb843SMatthew G. Knepley like a GPU, or vectorize on a multicore machine. 147924cdb843SMatthew G. Knepley 1480f6dfbefdSBarry Smith .seealso: `DMPLEX`, `Mat` 148124cdb843SMatthew G. Knepley @*/ 1482d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSNESComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, void *user) 1483d71ae5a4SJacob Faibussowitsch { 14846da023fcSToby Isaac DM plex; 1485083401c6SMatthew G. Knepley IS allcellIS; 1486f04eb4edSMatthew G. Knepley PetscBool hasJac, hasPrec; 14876528b96dSMatthew G. Knepley PetscInt Nds, s; 148824cdb843SMatthew G. Knepley 148924cdb843SMatthew G. Knepley PetscFunctionBegin; 14909566063dSJacob Faibussowitsch PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 14919566063dSJacob Faibussowitsch PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS)); 14929566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 1493083401c6SMatthew G. Knepley for (s = 0; s < Nds; ++s) { 1494083401c6SMatthew G. Knepley PetscDS ds; 1495083401c6SMatthew G. Knepley IS cellIS; 149606ad1575SMatthew G. Knepley PetscFormKey key; 1497083401c6SMatthew G. Knepley 149807218a29SMatthew G. Knepley PetscCall(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds, NULL)); 14996528b96dSMatthew G. Knepley key.value = 0; 15006528b96dSMatthew G. Knepley key.field = 0; 150106ad1575SMatthew G. Knepley key.part = 0; 15026528b96dSMatthew G. Knepley if (!key.label) { 15039566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)allcellIS)); 1504083401c6SMatthew G. Knepley cellIS = allcellIS; 1505083401c6SMatthew G. Knepley } else { 1506083401c6SMatthew G. Knepley IS pointIS; 1507083401c6SMatthew G. Knepley 15086528b96dSMatthew G. Knepley key.value = 1; 15099566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 15109566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS)); 15119566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 1512083401c6SMatthew G. Knepley } 1513083401c6SMatthew G. Knepley if (!s) { 15149566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(ds, &hasJac)); 15159566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(ds, &hasPrec)); 15169566063dSJacob Faibussowitsch if (hasJac && hasPrec) PetscCall(MatZeroEntries(Jac)); 15179566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(JacP)); 1518083401c6SMatthew G. Knepley } 15199566063dSJacob Faibussowitsch PetscCall(DMPlexComputeJacobian_Internal(plex, key, cellIS, 0.0, 0.0, X, NULL, Jac, JacP, user)); 15209566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 1521083401c6SMatthew G. Knepley } 15229566063dSJacob Faibussowitsch PetscCall(ISDestroy(&allcellIS)); 15239566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 15243ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 152524cdb843SMatthew G. Knepley } 15261878804aSMatthew G. Knepley 15279371c9d4SSatish Balay struct _DMSNESJacobianMFCtx { 15288e3a2eefSMatthew G. Knepley DM dm; 15298e3a2eefSMatthew G. Knepley Vec X; 15308e3a2eefSMatthew G. Knepley void *ctx; 15318e3a2eefSMatthew G. Knepley }; 15328e3a2eefSMatthew G. Knepley 1533d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESJacobianMF_Destroy_Private(Mat A) 1534d71ae5a4SJacob Faibussowitsch { 15358e3a2eefSMatthew G. Knepley struct _DMSNESJacobianMFCtx *ctx; 15368e3a2eefSMatthew G. Knepley 15378e3a2eefSMatthew G. Knepley PetscFunctionBegin; 15389566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &ctx)); 15399566063dSJacob Faibussowitsch PetscCall(MatShellSetContext(A, NULL)); 15409566063dSJacob Faibussowitsch PetscCall(DMDestroy(&ctx->dm)); 15419566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ctx->X)); 15429566063dSJacob Faibussowitsch PetscCall(PetscFree(ctx)); 15433ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15448e3a2eefSMatthew G. Knepley } 15458e3a2eefSMatthew G. Knepley 1546d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESJacobianMF_Mult_Private(Mat A, Vec Y, Vec Z) 1547d71ae5a4SJacob Faibussowitsch { 15488e3a2eefSMatthew G. Knepley struct _DMSNESJacobianMFCtx *ctx; 15498e3a2eefSMatthew G. Knepley 15508e3a2eefSMatthew G. Knepley PetscFunctionBegin; 15519566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &ctx)); 15529566063dSJacob Faibussowitsch PetscCall(DMSNESComputeJacobianAction(ctx->dm, ctx->X, Y, Z, ctx->ctx)); 15533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15548e3a2eefSMatthew G. Knepley } 15558e3a2eefSMatthew G. Knepley 15568e3a2eefSMatthew G. Knepley /*@ 1557f6dfbefdSBarry Smith DMSNESCreateJacobianMF - Create a `Mat` which computes the action of the Jacobian matrix-free 15588e3a2eefSMatthew G. Knepley 1559c3339decSBarry Smith Collective 15608e3a2eefSMatthew G. Knepley 15618e3a2eefSMatthew G. Knepley Input Parameters: 1562f6dfbefdSBarry Smith + dm - The `DM` 15638e3a2eefSMatthew G. Knepley . X - The evaluation point for the Jacobian 15642fe279fdSBarry Smith - user - A user context, or `NULL` 15658e3a2eefSMatthew G. Knepley 15668e3a2eefSMatthew G. Knepley Output Parameter: 1567f6dfbefdSBarry Smith . J - The `Mat` 15688e3a2eefSMatthew G. Knepley 15698e3a2eefSMatthew G. Knepley Level: advanced 15708e3a2eefSMatthew G. Knepley 1571f6dfbefdSBarry Smith Note: 15722fe279fdSBarry Smith Vec `X` is kept in `J`, so updating `X` then updates the evaluation point. 15738e3a2eefSMatthew G. Knepley 1574f6dfbefdSBarry Smith .seealso: `DM`, `DMSNESComputeJacobianAction()` 15758e3a2eefSMatthew G. Knepley @*/ 1576d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCreateJacobianMF(DM dm, Vec X, void *user, Mat *J) 1577d71ae5a4SJacob Faibussowitsch { 15788e3a2eefSMatthew G. Knepley struct _DMSNESJacobianMFCtx *ctx; 15798e3a2eefSMatthew G. Knepley PetscInt n, N; 15808e3a2eefSMatthew G. Knepley 15818e3a2eefSMatthew G. Knepley PetscFunctionBegin; 15829566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 15839566063dSJacob Faibussowitsch PetscCall(MatSetType(*J, MATSHELL)); 15849566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(X, &n)); 15859566063dSJacob Faibussowitsch PetscCall(VecGetSize(X, &N)); 15869566063dSJacob Faibussowitsch PetscCall(MatSetSizes(*J, n, n, N, N)); 15879566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)dm)); 15889566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)X)); 15899566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(1, &ctx)); 15908e3a2eefSMatthew G. Knepley ctx->dm = dm; 15918e3a2eefSMatthew G. Knepley ctx->X = X; 15928e3a2eefSMatthew G. Knepley ctx->ctx = user; 15939566063dSJacob Faibussowitsch PetscCall(MatShellSetContext(*J, ctx)); 15949566063dSJacob Faibussowitsch PetscCall(MatShellSetOperation(*J, MATOP_DESTROY, (void (*)(void))DMSNESJacobianMF_Destroy_Private)); 15959566063dSJacob Faibussowitsch PetscCall(MatShellSetOperation(*J, MATOP_MULT, (void (*)(void))DMSNESJacobianMF_Mult_Private)); 15963ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15978e3a2eefSMatthew G. Knepley } 15988e3a2eefSMatthew G. Knepley 159938cfc46eSPierre Jolivet /* 160038cfc46eSPierre Jolivet MatComputeNeumannOverlap - Computes an unassembled (Neumann) local overlapping Mat in nonlinear context. 160138cfc46eSPierre Jolivet 160238cfc46eSPierre Jolivet Input Parameters: 16032fe279fdSBarry Smith + X - `SNES` linearization point 160438cfc46eSPierre Jolivet . ovl - index set of overlapping subdomains 160538cfc46eSPierre Jolivet 160638cfc46eSPierre Jolivet Output Parameter: 160738cfc46eSPierre Jolivet . J - unassembled (Neumann) local matrix 160838cfc46eSPierre Jolivet 160938cfc46eSPierre Jolivet Level: intermediate 161038cfc46eSPierre Jolivet 1611db781477SPatrick Sanan .seealso: `DMCreateNeumannOverlap()`, `MATIS`, `PCHPDDMSetAuxiliaryMat()` 161238cfc46eSPierre Jolivet */ 1613d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatComputeNeumannOverlap_Plex(Mat J, PetscReal t, Vec X, Vec X_t, PetscReal s, IS ovl, void *ctx) 1614d71ae5a4SJacob Faibussowitsch { 161538cfc46eSPierre Jolivet SNES snes; 161638cfc46eSPierre Jolivet Mat pJ; 161738cfc46eSPierre Jolivet DM ovldm, origdm; 161838cfc46eSPierre Jolivet DMSNES sdm; 161938cfc46eSPierre Jolivet PetscErrorCode (*bfun)(DM, Vec, void *); 162038cfc46eSPierre Jolivet PetscErrorCode (*jfun)(DM, Vec, Mat, Mat, void *); 162138cfc46eSPierre Jolivet void *bctx, *jctx; 162238cfc46eSPierre Jolivet 162338cfc46eSPierre Jolivet PetscFunctionBegin; 16249566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Overlap_HPDDM_MATIS", (PetscObject *)&pJ)); 162528b400f6SJacob Faibussowitsch PetscCheck(pJ, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing overlapping Mat"); 16269566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Original_HPDDM", (PetscObject *)&origdm)); 162728b400f6SJacob Faibussowitsch PetscCheck(origdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing original DM"); 16289566063dSJacob Faibussowitsch PetscCall(MatGetDM(pJ, &ovldm)); 16299566063dSJacob Faibussowitsch PetscCall(DMSNESGetBoundaryLocal(origdm, &bfun, &bctx)); 16309566063dSJacob Faibussowitsch PetscCall(DMSNESSetBoundaryLocal(ovldm, bfun, bctx)); 16319566063dSJacob Faibussowitsch PetscCall(DMSNESGetJacobianLocal(origdm, &jfun, &jctx)); 16329566063dSJacob Faibussowitsch PetscCall(DMSNESSetJacobianLocal(ovldm, jfun, jctx)); 16339566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Overlap_HPDDM_SNES", (PetscObject *)&snes)); 163438cfc46eSPierre Jolivet if (!snes) { 16359566063dSJacob Faibussowitsch PetscCall(SNESCreate(PetscObjectComm((PetscObject)ovl), &snes)); 16369566063dSJacob Faibussowitsch PetscCall(SNESSetDM(snes, ovldm)); 16379566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)ovl, "_DM_Overlap_HPDDM_SNES", (PetscObject)snes)); 16389566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)snes)); 163938cfc46eSPierre Jolivet } 16409566063dSJacob Faibussowitsch PetscCall(DMGetDMSNES(ovldm, &sdm)); 16419566063dSJacob Faibussowitsch PetscCall(VecLockReadPush(X)); 1642800f99ffSJeremy L Thompson { 1643800f99ffSJeremy L Thompson void *ctx; 1644800f99ffSJeremy L Thompson PetscErrorCode (*J)(SNES, Vec, Mat, Mat, void *); 1645800f99ffSJeremy L Thompson PetscCall(DMSNESGetJacobian(ovldm, &J, &ctx)); 1646800f99ffSJeremy L Thompson PetscCallBack("SNES callback Jacobian", (*J)(snes, X, pJ, pJ, ctx)); 1647800f99ffSJeremy L Thompson } 16489566063dSJacob Faibussowitsch PetscCall(VecLockReadPop(X)); 164938cfc46eSPierre Jolivet /* this is a no-hop, just in case we decide to change the placeholder for the local Neumann matrix */ 165038cfc46eSPierre Jolivet { 165138cfc46eSPierre Jolivet Mat locpJ; 165238cfc46eSPierre Jolivet 16539566063dSJacob Faibussowitsch PetscCall(MatISGetLocalMat(pJ, &locpJ)); 16549566063dSJacob Faibussowitsch PetscCall(MatCopy(locpJ, J, SAME_NONZERO_PATTERN)); 165538cfc46eSPierre Jolivet } 16563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 165738cfc46eSPierre Jolivet } 165838cfc46eSPierre Jolivet 1659a925c78cSMatthew G. Knepley /*@ 1660f6dfbefdSBarry Smith DMPlexSetSNESLocalFEM - Use `DMPLEX`'s internal FEM routines to compute `SNES` boundary values, residual, and Jacobian. 16619f520fc2SToby Isaac 16629f520fc2SToby Isaac Input Parameters: 1663f6dfbefdSBarry Smith + dm - The `DM` object 1664f6dfbefdSBarry Smith . boundaryctx - the user context that will be passed to pointwise evaluation of boundary values (see `PetscDSAddBoundary()`) 1665f6dfbefdSBarry Smith . residualctx - the user context that will be passed to pointwise evaluation of finite element residual computations (see `PetscDSSetResidual()`) 1666f6dfbefdSBarry Smith - jacobianctx - the user context that will be passed to pointwise evaluation of finite element Jacobian construction (see `PetscDSSetJacobian()`) 16671a244344SSatish Balay 16681a244344SSatish Balay Level: developer 1669f6dfbefdSBarry Smith 1670f6dfbefdSBarry Smith .seealso: `DMPLEX`, `SNES` 16719f520fc2SToby Isaac @*/ 1672d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSNESLocalFEM(DM dm, void *boundaryctx, void *residualctx, void *jacobianctx) 1673d71ae5a4SJacob Faibussowitsch { 16749f520fc2SToby Isaac PetscFunctionBegin; 16759566063dSJacob Faibussowitsch PetscCall(DMSNESSetBoundaryLocal(dm, DMPlexSNESComputeBoundaryFEM, boundaryctx)); 16769566063dSJacob Faibussowitsch PetscCall(DMSNESSetFunctionLocal(dm, DMPlexSNESComputeResidualFEM, residualctx)); 16779566063dSJacob Faibussowitsch PetscCall(DMSNESSetJacobianLocal(dm, DMPlexSNESComputeJacobianFEM, jacobianctx)); 16789566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", MatComputeNeumannOverlap_Plex)); 16793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 16809f520fc2SToby Isaac } 16819f520fc2SToby Isaac 1682f017bcb6SMatthew G. Knepley /*@C 1683f017bcb6SMatthew G. Knepley DMSNESCheckDiscretization - Check the discretization error of the exact solution 1684f017bcb6SMatthew G. Knepley 1685f017bcb6SMatthew G. Knepley Input Parameters: 1686f6dfbefdSBarry Smith + snes - the `SNES` object 1687f6dfbefdSBarry Smith . dm - the `DM` 1688f2cacb80SMatthew G. Knepley . t - the time 1689f6dfbefdSBarry Smith . u - a `DM` vector 1690f0fc11ceSJed Brown - tol - A tolerance for the check, or -1 to print the results instead 1691f017bcb6SMatthew G. Knepley 16922fe279fdSBarry Smith Output Parameter: 16932fe279fdSBarry Smith . error - An array which holds the discretization error in each field, or `NULL` 16942fe279fdSBarry Smith 16952fe279fdSBarry Smith Level: developer 1696f3c94560SMatthew G. Knepley 1697f6dfbefdSBarry Smith Note: 1698f6dfbefdSBarry Smith The user must call `PetscDSSetExactSolution()` beforehand 16997f96f943SMatthew G. Knepley 1700*e4094ef1SJacob Faibussowitsch .seealso: `PetscDSSetExactSolution()`, `DNSNESCheckFromOptions()`, `DMSNESCheckResidual()`, `DMSNESCheckJacobian()` 1701f017bcb6SMatthew G. Knepley @*/ 1702d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckDiscretization(SNES snes, DM dm, PetscReal t, Vec u, PetscReal tol, PetscReal error[]) 1703d71ae5a4SJacob Faibussowitsch { 1704f017bcb6SMatthew G. Knepley PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx); 1705f017bcb6SMatthew G. Knepley void **ectxs; 1706f3c94560SMatthew G. Knepley PetscReal *err; 17077f96f943SMatthew G. Knepley MPI_Comm comm; 17087f96f943SMatthew G. Knepley PetscInt Nf, f; 17091878804aSMatthew G. Knepley 17101878804aSMatthew G. Knepley PetscFunctionBegin; 1711f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 1712f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 1713064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(u, VEC_CLASSID, 4); 1714534a8f05SLisandro Dalcin if (error) PetscValidRealPointer(error, 6); 17157f96f943SMatthew G. Knepley 17169566063dSJacob Faibussowitsch PetscCall(DMComputeExactSolution(dm, t, u, NULL)); 17179566063dSJacob Faibussowitsch PetscCall(VecViewFromOptions(u, NULL, "-vec_view")); 17187f96f943SMatthew G. Knepley 17199566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)snes, &comm)); 17209566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 17219566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(Nf, &exacts, Nf, &ectxs, PetscMax(1, Nf), &err)); 17227f96f943SMatthew G. Knepley { 17237f96f943SMatthew G. Knepley PetscInt Nds, s; 17247f96f943SMatthew G. Knepley 17259566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 1726083401c6SMatthew G. Knepley for (s = 0; s < Nds; ++s) { 17277f96f943SMatthew G. Knepley PetscDS ds; 1728083401c6SMatthew G. Knepley DMLabel label; 1729083401c6SMatthew G. Knepley IS fieldIS; 17307f96f943SMatthew G. Knepley const PetscInt *fields; 17317f96f943SMatthew G. Knepley PetscInt dsNf, f; 1732083401c6SMatthew G. Knepley 173307218a29SMatthew G. Knepley PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 17349566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &dsNf)); 17359566063dSJacob Faibussowitsch PetscCall(ISGetIndices(fieldIS, &fields)); 1736083401c6SMatthew G. Knepley for (f = 0; f < dsNf; ++f) { 1737083401c6SMatthew G. Knepley const PetscInt field = fields[f]; 17389566063dSJacob Faibussowitsch PetscCall(PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field])); 1739083401c6SMatthew G. Knepley } 17409566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(fieldIS, &fields)); 1741083401c6SMatthew G. Knepley } 1742083401c6SMatthew G. Knepley } 1743f017bcb6SMatthew G. Knepley if (Nf > 1) { 17449566063dSJacob Faibussowitsch PetscCall(DMComputeL2FieldDiff(dm, t, exacts, ectxs, u, err)); 1745f017bcb6SMatthew G. Knepley if (tol >= 0.0) { 1746ad540459SPierre Jolivet for (f = 0; f < Nf; ++f) PetscCheck(err[f] <= tol, comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g for field %" PetscInt_FMT " exceeds tolerance %g", (double)err[f], f, (double)tol); 1747b878532fSMatthew G. Knepley } else if (error) { 1748b878532fSMatthew G. Knepley for (f = 0; f < Nf; ++f) error[f] = err[f]; 17491878804aSMatthew G. Knepley } else { 17509566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "L_2 Error: [")); 1751f017bcb6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 17529566063dSJacob Faibussowitsch if (f) PetscCall(PetscPrintf(comm, ", ")); 17539566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "%g", (double)err[f])); 17541878804aSMatthew G. Knepley } 17559566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "]\n")); 1756f017bcb6SMatthew G. Knepley } 1757f017bcb6SMatthew G. Knepley } else { 17589566063dSJacob Faibussowitsch PetscCall(DMComputeL2Diff(dm, t, exacts, ectxs, u, &err[0])); 1759f017bcb6SMatthew G. Knepley if (tol >= 0.0) { 176008401ef6SPierre Jolivet PetscCheck(err[0] <= tol, comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g exceeds tolerance %g", (double)err[0], (double)tol); 1761b878532fSMatthew G. Knepley } else if (error) { 1762b878532fSMatthew G. Knepley error[0] = err[0]; 1763f017bcb6SMatthew G. Knepley } else { 17649566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "L_2 Error: %g\n", (double)err[0])); 1765f017bcb6SMatthew G. Knepley } 1766f017bcb6SMatthew G. Knepley } 17679566063dSJacob Faibussowitsch PetscCall(PetscFree3(exacts, ectxs, err)); 17683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1769f017bcb6SMatthew G. Knepley } 1770f017bcb6SMatthew G. Knepley 1771f017bcb6SMatthew G. Knepley /*@C 1772f017bcb6SMatthew G. Knepley DMSNESCheckResidual - Check the residual of the exact solution 1773f017bcb6SMatthew G. Knepley 1774f017bcb6SMatthew G. Knepley Input Parameters: 1775f6dfbefdSBarry Smith + snes - the `SNES` object 1776f6dfbefdSBarry Smith . dm - the `DM` 1777f6dfbefdSBarry Smith . u - a `DM` vector 1778f0fc11ceSJed Brown - tol - A tolerance for the check, or -1 to print the results instead 1779f017bcb6SMatthew G. Knepley 1780f6dfbefdSBarry Smith Output Parameter: 17812fe279fdSBarry Smith . residual - The residual norm of the exact solution, or `NULL` 1782f3c94560SMatthew G. Knepley 1783f017bcb6SMatthew G. Knepley Level: developer 1784f017bcb6SMatthew G. Knepley 1785db781477SPatrick Sanan .seealso: `DNSNESCheckFromOptions()`, `DMSNESCheckDiscretization()`, `DMSNESCheckJacobian()` 1786f017bcb6SMatthew G. Knepley @*/ 1787d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckResidual(SNES snes, DM dm, Vec u, PetscReal tol, PetscReal *residual) 1788d71ae5a4SJacob Faibussowitsch { 1789f017bcb6SMatthew G. Knepley MPI_Comm comm; 1790f017bcb6SMatthew G. Knepley Vec r; 1791f017bcb6SMatthew G. Knepley PetscReal res; 1792f017bcb6SMatthew G. Knepley 1793f017bcb6SMatthew G. Knepley PetscFunctionBegin; 1794f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 1795f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 1796f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(u, VEC_CLASSID, 3); 1797534a8f05SLisandro Dalcin if (residual) PetscValidRealPointer(residual, 5); 17989566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)snes, &comm)); 17999566063dSJacob Faibussowitsch PetscCall(DMComputeExactSolution(dm, 0.0, u, NULL)); 18009566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &r)); 18019566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes, u, r)); 18029566063dSJacob Faibussowitsch PetscCall(VecNorm(r, NORM_2, &res)); 1803f017bcb6SMatthew G. Knepley if (tol >= 0.0) { 180408401ef6SPierre Jolivet PetscCheck(res <= tol, comm, PETSC_ERR_ARG_WRONG, "L_2 Residual %g exceeds tolerance %g", (double)res, (double)tol); 1805b878532fSMatthew G. Knepley } else if (residual) { 1806b878532fSMatthew G. Knepley *residual = res; 1807f017bcb6SMatthew G. Knepley } else { 18089566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "L_2 Residual: %g\n", (double)res)); 18099566063dSJacob Faibussowitsch PetscCall(VecChop(r, 1.0e-10)); 18109566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)r, "Initial Residual")); 18119566063dSJacob Faibussowitsch PetscCall(PetscObjectSetOptionsPrefix((PetscObject)r, "res_")); 18129566063dSJacob Faibussowitsch PetscCall(VecViewFromOptions(r, NULL, "-vec_view")); 1813f017bcb6SMatthew G. Knepley } 18149566063dSJacob Faibussowitsch PetscCall(VecDestroy(&r)); 18153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1816f017bcb6SMatthew G. Knepley } 1817f017bcb6SMatthew G. Knepley 1818f017bcb6SMatthew G. Knepley /*@C 1819f3c94560SMatthew G. Knepley DMSNESCheckJacobian - Check the Jacobian of the exact solution against the residual using the Taylor Test 1820f017bcb6SMatthew G. Knepley 1821f017bcb6SMatthew G. Knepley Input Parameters: 1822f6dfbefdSBarry Smith + snes - the `SNES` object 1823f6dfbefdSBarry Smith . dm - the `DM` 1824f6dfbefdSBarry Smith . u - a `DM` vector 1825f0fc11ceSJed Brown - tol - A tolerance for the check, or -1 to print the results instead 1826f017bcb6SMatthew G. Knepley 1827f3c94560SMatthew G. Knepley Output Parameters: 18282fe279fdSBarry Smith + isLinear - Flag indicaing that the function looks linear, or `NULL` 18292fe279fdSBarry Smith - convRate - The rate of convergence of the linear model, or `NULL` 1830f3c94560SMatthew G. Knepley 1831f017bcb6SMatthew G. Knepley Level: developer 1832f017bcb6SMatthew G. Knepley 1833db781477SPatrick Sanan .seealso: `DNSNESCheckFromOptions()`, `DMSNESCheckDiscretization()`, `DMSNESCheckResidual()` 1834f017bcb6SMatthew G. Knepley @*/ 1835d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckJacobian(SNES snes, DM dm, Vec u, PetscReal tol, PetscBool *isLinear, PetscReal *convRate) 1836d71ae5a4SJacob Faibussowitsch { 1837f017bcb6SMatthew G. Knepley MPI_Comm comm; 1838f017bcb6SMatthew G. Knepley PetscDS ds; 1839f017bcb6SMatthew G. Knepley Mat J, M; 1840f017bcb6SMatthew G. Knepley MatNullSpace nullspace; 1841f3c94560SMatthew G. Knepley PetscReal slope, intercept; 18427f96f943SMatthew G. Knepley PetscBool hasJac, hasPrec, isLin = PETSC_FALSE; 1843f017bcb6SMatthew G. Knepley 1844f017bcb6SMatthew G. Knepley PetscFunctionBegin; 1845f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 1846f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 1847f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(u, VEC_CLASSID, 3); 1848534a8f05SLisandro Dalcin if (isLinear) PetscValidBoolPointer(isLinear, 5); 1849064a246eSJacob Faibussowitsch if (convRate) PetscValidRealPointer(convRate, 6); 18509566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)snes, &comm)); 18519566063dSJacob Faibussowitsch PetscCall(DMComputeExactSolution(dm, 0.0, u, NULL)); 1852f017bcb6SMatthew G. Knepley /* Create and view matrices */ 18539566063dSJacob Faibussowitsch PetscCall(DMCreateMatrix(dm, &J)); 18549566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &ds)); 18559566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(ds, &hasJac)); 18569566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(ds, &hasPrec)); 1857282e7bb4SMatthew G. Knepley if (hasJac && hasPrec) { 18589566063dSJacob Faibussowitsch PetscCall(DMCreateMatrix(dm, &M)); 18599566063dSJacob Faibussowitsch PetscCall(SNESComputeJacobian(snes, u, J, M)); 18609566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)M, "Preconditioning Matrix")); 18619566063dSJacob Faibussowitsch PetscCall(PetscObjectSetOptionsPrefix((PetscObject)M, "jacpre_")); 18629566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(M, NULL, "-mat_view")); 18639566063dSJacob Faibussowitsch PetscCall(MatDestroy(&M)); 1864282e7bb4SMatthew G. Knepley } else { 18659566063dSJacob Faibussowitsch PetscCall(SNESComputeJacobian(snes, u, J, J)); 1866282e7bb4SMatthew G. Knepley } 18679566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)J, "Jacobian")); 18689566063dSJacob Faibussowitsch PetscCall(PetscObjectSetOptionsPrefix((PetscObject)J, "jac_")); 18699566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(J, NULL, "-mat_view")); 1870f017bcb6SMatthew G. Knepley /* Check nullspace */ 18719566063dSJacob Faibussowitsch PetscCall(MatGetNullSpace(J, &nullspace)); 1872f017bcb6SMatthew G. Knepley if (nullspace) { 18731878804aSMatthew G. Knepley PetscBool isNull; 18749566063dSJacob Faibussowitsch PetscCall(MatNullSpaceTest(nullspace, J, &isNull)); 187528b400f6SJacob Faibussowitsch PetscCheck(isNull, comm, PETSC_ERR_PLIB, "The null space calculated for the system operator is invalid."); 18761878804aSMatthew G. Knepley } 1877f017bcb6SMatthew G. Knepley /* Taylor test */ 1878f017bcb6SMatthew G. Knepley { 1879f017bcb6SMatthew G. Knepley PetscRandom rand; 1880f017bcb6SMatthew G. Knepley Vec du, uhat, r, rhat, df; 1881f3c94560SMatthew G. Knepley PetscReal h; 1882f017bcb6SMatthew G. Knepley PetscReal *es, *hs, *errors; 1883f017bcb6SMatthew G. Knepley PetscReal hMax = 1.0, hMin = 1e-6, hMult = 0.1; 1884f017bcb6SMatthew G. Knepley PetscInt Nv, v; 1885f017bcb6SMatthew G. Knepley 1886f017bcb6SMatthew G. Knepley /* Choose a perturbation direction */ 18879566063dSJacob Faibussowitsch PetscCall(PetscRandomCreate(comm, &rand)); 18889566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &du)); 18899566063dSJacob Faibussowitsch PetscCall(VecSetRandom(du, rand)); 18909566063dSJacob Faibussowitsch PetscCall(PetscRandomDestroy(&rand)); 18919566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &df)); 18929566063dSJacob Faibussowitsch PetscCall(MatMult(J, du, df)); 1893f017bcb6SMatthew G. Knepley /* Evaluate residual at u, F(u), save in vector r */ 18949566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &r)); 18959566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes, u, r)); 1896f017bcb6SMatthew G. Knepley /* Look at the convergence of our Taylor approximation as we approach u */ 18979371c9d4SSatish Balay for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv) 18989371c9d4SSatish Balay ; 18999566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(Nv, &es, Nv, &hs, Nv, &errors)); 19009566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &uhat)); 19019566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &rhat)); 1902f017bcb6SMatthew G. Knepley for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv) { 19039566063dSJacob Faibussowitsch PetscCall(VecWAXPY(uhat, h, du, u)); 1904f017bcb6SMatthew G. Knepley /* F(\hat u) \approx F(u) + J(u) (uhat - u) = F(u) + h * J(u) du */ 19059566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes, uhat, rhat)); 19069566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(rhat, -1.0, -h, 1.0, r, df)); 19079566063dSJacob Faibussowitsch PetscCall(VecNorm(rhat, NORM_2, &errors[Nv])); 1908f017bcb6SMatthew G. Knepley 190938d69901SMatthew G. Knepley es[Nv] = errors[Nv] == 0 ? -16.0 : PetscLog10Real(errors[Nv]); 1910f017bcb6SMatthew G. Knepley hs[Nv] = PetscLog10Real(h); 1911f017bcb6SMatthew G. Knepley } 19129566063dSJacob Faibussowitsch PetscCall(VecDestroy(&uhat)); 19139566063dSJacob Faibussowitsch PetscCall(VecDestroy(&rhat)); 19149566063dSJacob Faibussowitsch PetscCall(VecDestroy(&df)); 19159566063dSJacob Faibussowitsch PetscCall(VecDestroy(&r)); 19169566063dSJacob Faibussowitsch PetscCall(VecDestroy(&du)); 1917f017bcb6SMatthew G. Knepley for (v = 0; v < Nv; ++v) { 1918f017bcb6SMatthew G. Knepley if ((tol >= 0) && (errors[v] > tol)) break; 1919f017bcb6SMatthew G. Knepley else if (errors[v] > PETSC_SMALL) break; 1920f017bcb6SMatthew G. Knepley } 1921f3c94560SMatthew G. Knepley if (v == Nv) isLin = PETSC_TRUE; 19229566063dSJacob Faibussowitsch PetscCall(PetscLinearRegression(Nv, hs, es, &slope, &intercept)); 19239566063dSJacob Faibussowitsch PetscCall(PetscFree3(es, hs, errors)); 1924f017bcb6SMatthew G. Knepley /* Slope should be about 2 */ 1925f017bcb6SMatthew G. Knepley if (tol >= 0) { 19260b121fc5SBarry Smith PetscCheck(isLin || PetscAbsReal(2 - slope) <= tol, comm, PETSC_ERR_ARG_WRONG, "Taylor approximation convergence rate should be 2, not %0.2f", (double)slope); 1927b878532fSMatthew G. Knepley } else if (isLinear || convRate) { 1928b878532fSMatthew G. Knepley if (isLinear) *isLinear = isLin; 1929b878532fSMatthew G. Knepley if (convRate) *convRate = slope; 1930f017bcb6SMatthew G. Knepley } else { 19319566063dSJacob Faibussowitsch if (!isLin) PetscCall(PetscPrintf(comm, "Taylor approximation converging at order %3.2f\n", (double)slope)); 19329566063dSJacob Faibussowitsch else PetscCall(PetscPrintf(comm, "Function appears to be linear\n")); 1933f017bcb6SMatthew G. Knepley } 1934f017bcb6SMatthew G. Knepley } 19359566063dSJacob Faibussowitsch PetscCall(MatDestroy(&J)); 19363ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 19371878804aSMatthew G. Knepley } 19381878804aSMatthew G. Knepley 1939d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheck_Internal(SNES snes, DM dm, Vec u) 1940d71ae5a4SJacob Faibussowitsch { 1941f017bcb6SMatthew G. Knepley PetscFunctionBegin; 19429566063dSJacob Faibussowitsch PetscCall(DMSNESCheckDiscretization(snes, dm, 0.0, u, -1.0, NULL)); 19439566063dSJacob Faibussowitsch PetscCall(DMSNESCheckResidual(snes, dm, u, -1.0, NULL)); 19449566063dSJacob Faibussowitsch PetscCall(DMSNESCheckJacobian(snes, dm, u, -1.0, NULL, NULL)); 19453ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1946f017bcb6SMatthew G. Knepley } 1947f017bcb6SMatthew G. Knepley 1948bee9a294SMatthew G. Knepley /*@C 1949bee9a294SMatthew G. Knepley DMSNESCheckFromOptions - Check the residual and Jacobian functions using the exact solution by outputting some diagnostic information 1950bee9a294SMatthew G. Knepley 1951bee9a294SMatthew G. Knepley Input Parameters: 1952f6dfbefdSBarry Smith + snes - the `SNES` object 1953f6dfbefdSBarry Smith - u - representative `SNES` vector 19547f96f943SMatthew G. Knepley 19552fe279fdSBarry Smith Level: developer 19562fe279fdSBarry Smith 1957f6dfbefdSBarry Smith Note: 1958f6dfbefdSBarry Smith The user must call `PetscDSSetExactSolution()` beforehand 1959bee9a294SMatthew G. Knepley 19602fe279fdSBarry Smith .seealso: `SNES`, `DM` 1961bee9a294SMatthew G. Knepley @*/ 1962d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckFromOptions(SNES snes, Vec u) 1963d71ae5a4SJacob Faibussowitsch { 19641878804aSMatthew G. Knepley DM dm; 19651878804aSMatthew G. Knepley Vec sol; 19661878804aSMatthew G. Knepley PetscBool check; 19671878804aSMatthew G. Knepley 19681878804aSMatthew G. Knepley PetscFunctionBegin; 19699566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-dmsnes_check", &check)); 19703ba16761SJacob Faibussowitsch if (!check) PetscFunctionReturn(PETSC_SUCCESS); 19719566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &dm)); 19729566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &sol)); 19739566063dSJacob Faibussowitsch PetscCall(SNESSetSolution(snes, sol)); 19749566063dSJacob Faibussowitsch PetscCall(DMSNESCheck_Internal(snes, dm, sol)); 19759566063dSJacob Faibussowitsch PetscCall(VecDestroy(&sol)); 19763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1977552f7358SJed Brown } 1978