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 69*ceaaa498SBarry Smith SNESConvergedCorrectPressure - The regular `SNES` convergence test that, up on convergence, adds a vector in the nullspace 70*ceaaa498SBarry Smith to make the continuum integral of the pressure field equal to zero. 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 78e4094ef1SJacob Faibussowitsch . gnorm - 2-norm of current step 79e4094ef1SJacob 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*ceaaa498SBarry Smith Developer Note: 97*ceaaa498SBarry Smith This is a total misuse of the `SNES` convergence test handling system. It should be removed. Perhaps a `SNESSetPostSolve()` could 98*ceaaa498SBarry Smith be constructed to handle this process. 99*ceaaa498SBarry Smith 100e4094ef1SJacob Faibussowitsch .seealso: `SNES`, `DM`, `SNESConvergedDefault()`, `SNESSetConvergenceTest()`, `DMSetNullSpaceConstructor()` 101649ef022SMatthew Knepley @*/ 102d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESConvergedCorrectPressure(SNES snes, PetscInt it, PetscReal xnorm, PetscReal gnorm, PetscReal f, SNESConvergedReason *reason, void *ctx) 103d71ae5a4SJacob Faibussowitsch { 104649ef022SMatthew Knepley PetscBool monitorIntegral = PETSC_FALSE; 105649ef022SMatthew Knepley 106649ef022SMatthew Knepley PetscFunctionBegin; 1079566063dSJacob Faibussowitsch PetscCall(SNESConvergedDefault(snes, it, xnorm, gnorm, f, reason, ctx)); 108649ef022SMatthew Knepley if (monitorIntegral) { 109649ef022SMatthew Knepley Mat J; 110649ef022SMatthew Knepley Vec u; 111649ef022SMatthew Knepley MatNullSpace nullspace; 112649ef022SMatthew Knepley const Vec *nullvecs; 113649ef022SMatthew Knepley PetscScalar pintd; 114649ef022SMatthew Knepley 1159566063dSJacob Faibussowitsch PetscCall(SNESGetSolution(snes, &u)); 1169566063dSJacob Faibussowitsch PetscCall(SNESGetJacobian(snes, &J, NULL, NULL, NULL)); 1179566063dSJacob Faibussowitsch PetscCall(MatGetNullSpace(J, &nullspace)); 1189566063dSJacob Faibussowitsch PetscCall(MatNullSpaceGetVecs(nullspace, NULL, NULL, &nullvecs)); 1199566063dSJacob Faibussowitsch PetscCall(VecDot(nullvecs[0], u, &pintd)); 1209566063dSJacob Faibussowitsch PetscCall(PetscInfo(snes, "SNES: Discrete integral of pressure: %g\n", (double)PetscRealPart(pintd))); 121649ef022SMatthew Knepley } 122649ef022SMatthew Knepley if (*reason > 0) { 123649ef022SMatthew Knepley Mat J; 124649ef022SMatthew Knepley Vec u; 125649ef022SMatthew Knepley MatNullSpace nullspace; 126649ef022SMatthew Knepley PetscInt pfield = 1; 127649ef022SMatthew Knepley 1289566063dSJacob Faibussowitsch PetscCall(SNESGetSolution(snes, &u)); 1299566063dSJacob Faibussowitsch PetscCall(SNESGetJacobian(snes, &J, NULL, NULL, NULL)); 1309566063dSJacob Faibussowitsch PetscCall(MatGetNullSpace(J, &nullspace)); 1319566063dSJacob Faibussowitsch PetscCall(SNESCorrectDiscretePressure_Private(snes, pfield, nullspace, u, ctx)); 132649ef022SMatthew Knepley } 1333ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 134649ef022SMatthew Knepley } 135649ef022SMatthew Knepley 13624cdb843SMatthew G. Knepley /************************** Interpolation *******************************/ 13724cdb843SMatthew G. Knepley 138d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESConvertPlex(DM dm, DM *plex, PetscBool copy) 139d71ae5a4SJacob Faibussowitsch { 1406da023fcSToby Isaac PetscBool isPlex; 1416da023fcSToby Isaac 1426da023fcSToby Isaac PetscFunctionBegin; 1439566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 1446da023fcSToby Isaac if (isPlex) { 1456da023fcSToby Isaac *plex = dm; 1469566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)dm)); 147f7148743SMatthew G. Knepley } else { 1489566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex)); 149f7148743SMatthew G. Knepley if (!*plex) { 1509566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, plex)); 1519566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex)); 1526da023fcSToby Isaac if (copy) { 1539566063dSJacob Faibussowitsch PetscCall(DMCopyDMSNES(dm, *plex)); 1549566063dSJacob Faibussowitsch PetscCall(DMCopyAuxiliaryVec(dm, *plex)); 1556da023fcSToby Isaac } 156f7148743SMatthew G. Knepley } else { 1579566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)*plex)); 158f7148743SMatthew G. Knepley } 1596da023fcSToby Isaac } 1603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1616da023fcSToby Isaac } 1626da023fcSToby Isaac 1634267b1a3SMatthew G. Knepley /*@C 164f6dfbefdSBarry Smith DMInterpolationCreate - Creates a `DMInterpolationInfo` context 1654267b1a3SMatthew G. Knepley 166d083f849SBarry Smith Collective 1674267b1a3SMatthew G. Knepley 1684267b1a3SMatthew G. Knepley Input Parameter: 1694267b1a3SMatthew G. Knepley . comm - the communicator 1704267b1a3SMatthew G. Knepley 1714267b1a3SMatthew G. Knepley Output Parameter: 1724267b1a3SMatthew G. Knepley . ctx - the context 1734267b1a3SMatthew G. Knepley 1744267b1a3SMatthew G. Knepley Level: beginner 1754267b1a3SMatthew G. Knepley 176f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationDestroy()` 1774267b1a3SMatthew G. Knepley @*/ 178d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationCreate(MPI_Comm comm, DMInterpolationInfo *ctx) 179d71ae5a4SJacob Faibussowitsch { 180552f7358SJed Brown PetscFunctionBegin; 1814f572ea9SToby Isaac PetscAssertPointer(ctx, 2); 1829566063dSJacob Faibussowitsch PetscCall(PetscNew(ctx)); 1831aa26658SKarl Rupp 184552f7358SJed Brown (*ctx)->comm = comm; 185552f7358SJed Brown (*ctx)->dim = -1; 186552f7358SJed Brown (*ctx)->nInput = 0; 1870298fd71SBarry Smith (*ctx)->points = NULL; 1880298fd71SBarry Smith (*ctx)->cells = NULL; 189552f7358SJed Brown (*ctx)->n = -1; 1900298fd71SBarry Smith (*ctx)->coords = NULL; 1913ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 192552f7358SJed Brown } 193552f7358SJed Brown 1944267b1a3SMatthew G. Knepley /*@C 1954267b1a3SMatthew G. Knepley DMInterpolationSetDim - Sets the spatial dimension for the interpolation context 1964267b1a3SMatthew G. Knepley 19720f4b53cSBarry Smith Not Collective 1984267b1a3SMatthew G. Knepley 1994267b1a3SMatthew G. Knepley Input Parameters: 2004267b1a3SMatthew G. Knepley + ctx - the context 2014267b1a3SMatthew G. Knepley - dim - the spatial dimension 2024267b1a3SMatthew G. Knepley 2034267b1a3SMatthew G. Knepley Level: intermediate 2044267b1a3SMatthew G. Knepley 205f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()` 2064267b1a3SMatthew G. Knepley @*/ 207d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationSetDim(DMInterpolationInfo ctx, PetscInt dim) 208d71ae5a4SJacob Faibussowitsch { 209552f7358SJed Brown PetscFunctionBegin; 21063a3b9bcSJacob Faibussowitsch PetscCheck(!(dim < 1) && !(dim > 3), ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension for points: %" PetscInt_FMT, dim); 211552f7358SJed Brown ctx->dim = dim; 2123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 213552f7358SJed Brown } 214552f7358SJed Brown 2154267b1a3SMatthew G. Knepley /*@C 2164267b1a3SMatthew G. Knepley DMInterpolationGetDim - Gets the spatial dimension for the interpolation context 2174267b1a3SMatthew G. Knepley 21820f4b53cSBarry Smith Not Collective 2194267b1a3SMatthew G. Knepley 2204267b1a3SMatthew G. Knepley Input Parameter: 2214267b1a3SMatthew G. Knepley . ctx - the context 2224267b1a3SMatthew G. Knepley 2234267b1a3SMatthew G. Knepley Output Parameter: 2244267b1a3SMatthew G. Knepley . dim - the spatial dimension 2254267b1a3SMatthew G. Knepley 2264267b1a3SMatthew G. Knepley Level: intermediate 2274267b1a3SMatthew G. Knepley 228f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationSetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()` 2294267b1a3SMatthew G. Knepley @*/ 230d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetDim(DMInterpolationInfo ctx, PetscInt *dim) 231d71ae5a4SJacob Faibussowitsch { 232552f7358SJed Brown PetscFunctionBegin; 2334f572ea9SToby Isaac PetscAssertPointer(dim, 2); 234552f7358SJed Brown *dim = ctx->dim; 2353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 236552f7358SJed Brown } 237552f7358SJed Brown 2384267b1a3SMatthew G. Knepley /*@C 2394267b1a3SMatthew G. Knepley DMInterpolationSetDof - Sets the number of fields interpolated at a point for the interpolation context 2404267b1a3SMatthew G. Knepley 24120f4b53cSBarry Smith Not Collective 2424267b1a3SMatthew G. Knepley 2434267b1a3SMatthew G. Knepley Input Parameters: 2444267b1a3SMatthew G. Knepley + ctx - the context 2454267b1a3SMatthew G. Knepley - dof - the number of fields 2464267b1a3SMatthew G. Knepley 2474267b1a3SMatthew G. Knepley Level: intermediate 2484267b1a3SMatthew G. Knepley 249f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetDof()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()` 2504267b1a3SMatthew G. Knepley @*/ 251d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationSetDof(DMInterpolationInfo ctx, PetscInt dof) 252d71ae5a4SJacob Faibussowitsch { 253552f7358SJed Brown PetscFunctionBegin; 25463a3b9bcSJacob Faibussowitsch PetscCheck(dof >= 1, ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of components: %" PetscInt_FMT, dof); 255552f7358SJed Brown ctx->dof = dof; 2563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 257552f7358SJed Brown } 258552f7358SJed Brown 2594267b1a3SMatthew G. Knepley /*@C 2604267b1a3SMatthew G. Knepley DMInterpolationGetDof - Gets the number of fields interpolated at a point for the interpolation context 2614267b1a3SMatthew G. Knepley 26220f4b53cSBarry Smith Not Collective 2634267b1a3SMatthew G. Knepley 2644267b1a3SMatthew G. Knepley Input Parameter: 2654267b1a3SMatthew G. Knepley . ctx - the context 2664267b1a3SMatthew G. Knepley 2674267b1a3SMatthew G. Knepley Output Parameter: 2684267b1a3SMatthew G. Knepley . dof - the number of fields 2694267b1a3SMatthew G. Knepley 2704267b1a3SMatthew G. Knepley Level: intermediate 2714267b1a3SMatthew G. Knepley 272e4094ef1SJacob Faibussowitsch .seealso: `DMInterpolationInfo`, `DMInterpolationSetDof()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()` 2734267b1a3SMatthew G. Knepley @*/ 274d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetDof(DMInterpolationInfo ctx, PetscInt *dof) 275d71ae5a4SJacob Faibussowitsch { 276552f7358SJed Brown PetscFunctionBegin; 2774f572ea9SToby Isaac PetscAssertPointer(dof, 2); 278552f7358SJed Brown *dof = ctx->dof; 2793ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 280552f7358SJed Brown } 281552f7358SJed Brown 2824267b1a3SMatthew G. Knepley /*@C 2834267b1a3SMatthew G. Knepley DMInterpolationAddPoints - Add points at which we will interpolate the fields 2844267b1a3SMatthew G. Knepley 28520f4b53cSBarry Smith Not Collective 2864267b1a3SMatthew G. Knepley 2874267b1a3SMatthew G. Knepley Input Parameters: 2884267b1a3SMatthew G. Knepley + ctx - the context 2894267b1a3SMatthew G. Knepley . n - the number of points 2904267b1a3SMatthew G. Knepley - points - the coordinates for each point, an array of size n * dim 2914267b1a3SMatthew G. Knepley 2922fe279fdSBarry Smith Level: intermediate 2932fe279fdSBarry Smith 294f6dfbefdSBarry Smith Note: 295f6dfbefdSBarry Smith The coordinate information is copied. 2964267b1a3SMatthew G. Knepley 297f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationSetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationCreate()` 2984267b1a3SMatthew G. Knepley @*/ 299d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationAddPoints(DMInterpolationInfo ctx, PetscInt n, PetscReal points[]) 300d71ae5a4SJacob Faibussowitsch { 301552f7358SJed Brown PetscFunctionBegin; 30208401ef6SPierre Jolivet PetscCheck(ctx->dim >= 0, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set"); 30328b400f6SJacob Faibussowitsch PetscCheck(!ctx->points, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot add points multiple times yet"); 304552f7358SJed Brown ctx->nInput = n; 3051aa26658SKarl Rupp 3069566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n * ctx->dim, &ctx->points)); 3079566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(ctx->points, points, n * ctx->dim)); 3083ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 309552f7358SJed Brown } 310552f7358SJed Brown 3114267b1a3SMatthew G. Knepley /*@C 31252aa1562SMatthew G. Knepley DMInterpolationSetUp - Compute spatial indices for point location during interpolation 3134267b1a3SMatthew G. Knepley 314c3339decSBarry Smith Collective 3154267b1a3SMatthew G. Knepley 3164267b1a3SMatthew G. Knepley Input Parameters: 3174267b1a3SMatthew G. Knepley + ctx - the context 318f6dfbefdSBarry Smith . dm - the `DM` for the function space used for interpolation 319f6dfbefdSBarry Smith . redundantPoints - If `PETSC_TRUE`, all processes are passing in the same array of points. Otherwise, points need to be communicated among processes. 320f6dfbefdSBarry Smith - ignoreOutsideDomain - If `PETSC_TRUE`, ignore points outside the domain, otherwise return an error 3214267b1a3SMatthew G. Knepley 3224267b1a3SMatthew G. Knepley Level: intermediate 3234267b1a3SMatthew G. Knepley 324e4094ef1SJacob Faibussowitsch .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 3254267b1a3SMatthew G. Knepley @*/ 326d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationSetUp(DMInterpolationInfo ctx, DM dm, PetscBool redundantPoints, PetscBool ignoreOutsideDomain) 327d71ae5a4SJacob Faibussowitsch { 328552f7358SJed Brown MPI_Comm comm = ctx->comm; 329552f7358SJed Brown PetscScalar *a; 330552f7358SJed Brown PetscInt p, q, i; 331552f7358SJed Brown PetscMPIInt rank, size; 332552f7358SJed Brown Vec pointVec; 3333a93e3b7SToby Isaac PetscSF cellSF; 334552f7358SJed Brown PetscLayout layout; 335552f7358SJed Brown PetscReal *globalPoints; 336cb313848SJed Brown PetscScalar *globalPointsScalar; 337552f7358SJed Brown const PetscInt *ranges; 338552f7358SJed Brown PetscMPIInt *counts, *displs; 3393a93e3b7SToby Isaac const PetscSFNode *foundCells; 3403a93e3b7SToby Isaac const PetscInt *foundPoints; 341552f7358SJed Brown PetscMPIInt *foundProcs, *globalProcs; 3423a93e3b7SToby Isaac PetscInt n, N, numFound; 343552f7358SJed Brown 34419436ca2SJed Brown PetscFunctionBegin; 345064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 3469566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(comm, &size)); 3479566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 34808401ef6SPierre Jolivet PetscCheck(ctx->dim >= 0, comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set"); 34919436ca2SJed Brown /* Locate points */ 35019436ca2SJed Brown n = ctx->nInput; 351552f7358SJed Brown if (!redundantPoints) { 3529566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(comm, &layout)); 3539566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(layout, 1)); 3549566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(layout, n)); 3559566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(layout)); 3569566063dSJacob Faibussowitsch PetscCall(PetscLayoutGetSize(layout, &N)); 357552f7358SJed Brown /* Communicate all points to all processes */ 3589566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(N * ctx->dim, &globalPoints, size, &counts, size, &displs)); 3599566063dSJacob Faibussowitsch PetscCall(PetscLayoutGetRanges(layout, &ranges)); 360552f7358SJed Brown for (p = 0; p < size; ++p) { 361552f7358SJed Brown counts[p] = (ranges[p + 1] - ranges[p]) * ctx->dim; 362552f7358SJed Brown displs[p] = ranges[p] * ctx->dim; 363552f7358SJed Brown } 3649566063dSJacob Faibussowitsch PetscCallMPI(MPI_Allgatherv(ctx->points, n * ctx->dim, MPIU_REAL, globalPoints, counts, displs, MPIU_REAL, comm)); 365552f7358SJed Brown } else { 366552f7358SJed Brown N = n; 367552f7358SJed Brown globalPoints = ctx->points; 36838ea73c8SJed Brown counts = displs = NULL; 36938ea73c8SJed Brown layout = NULL; 370552f7358SJed Brown } 371552f7358SJed Brown #if 0 3729566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(N,&foundCells,N,&foundProcs,N,&globalProcs)); 37319436ca2SJed Brown /* foundCells[p] = m->locatePoint(&globalPoints[p*ctx->dim]); */ 374552f7358SJed Brown #else 375cb313848SJed Brown #if defined(PETSC_USE_COMPLEX) 3769566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(N * ctx->dim, &globalPointsScalar)); 37746b3086cSToby Isaac for (i = 0; i < N * ctx->dim; i++) globalPointsScalar[i] = globalPoints[i]; 378cb313848SJed Brown #else 379cb313848SJed Brown globalPointsScalar = globalPoints; 380cb313848SJed Brown #endif 3819566063dSJacob Faibussowitsch PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, ctx->dim, N * ctx->dim, globalPointsScalar, &pointVec)); 3829566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(N, &foundProcs, N, &globalProcs)); 383ad540459SPierre Jolivet for (p = 0; p < N; ++p) foundProcs[p] = size; 3843a93e3b7SToby Isaac cellSF = NULL; 3859566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dm, pointVec, DM_POINTLOCATION_REMOVE, &cellSF)); 3869566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(cellSF, NULL, &numFound, &foundPoints, &foundCells)); 387552f7358SJed Brown #endif 3883a93e3b7SToby Isaac for (p = 0; p < numFound; ++p) { 3893a93e3b7SToby Isaac if (foundCells[p].index >= 0) foundProcs[foundPoints ? foundPoints[p] : p] = rank; 390552f7358SJed Brown } 391552f7358SJed Brown /* Let the lowest rank process own each point */ 3921c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(foundProcs, globalProcs, N, MPI_INT, MPI_MIN, comm)); 393552f7358SJed Brown ctx->n = 0; 394552f7358SJed Brown for (p = 0; p < N; ++p) { 39552aa1562SMatthew G. Knepley if (globalProcs[p] == size) { 3969371c9d4SSatish 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), 3979371c9d4SSatish Balay (double)(ctx->dim > 2 ? globalPoints[p * ctx->dim + 2] : 0.0)); 398f7d195e4SLawrence Mitchell if (rank == 0) ++ctx->n; 39952aa1562SMatthew G. Knepley } else if (globalProcs[p] == rank) ++ctx->n; 400552f7358SJed Brown } 401552f7358SJed Brown /* Create coordinates vector and array of owned cells */ 4029566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(ctx->n, &ctx->cells)); 4039566063dSJacob Faibussowitsch PetscCall(VecCreate(comm, &ctx->coords)); 4049566063dSJacob Faibussowitsch PetscCall(VecSetSizes(ctx->coords, ctx->n * ctx->dim, PETSC_DECIDE)); 4059566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(ctx->coords, ctx->dim)); 4069566063dSJacob Faibussowitsch PetscCall(VecSetType(ctx->coords, VECSTANDARD)); 4079566063dSJacob Faibussowitsch PetscCall(VecGetArray(ctx->coords, &a)); 408552f7358SJed Brown for (p = 0, q = 0, i = 0; p < N; ++p) { 409552f7358SJed Brown if (globalProcs[p] == rank) { 410552f7358SJed Brown PetscInt d; 411552f7358SJed Brown 4121aa26658SKarl Rupp for (d = 0; d < ctx->dim; ++d, ++i) a[i] = globalPoints[p * ctx->dim + d]; 413f317b747SMatthew G. Knepley ctx->cells[q] = foundCells[q].index; 414f317b747SMatthew G. Knepley ++q; 415552f7358SJed Brown } 416dd400576SPatrick Sanan if (globalProcs[p] == size && rank == 0) { 41752aa1562SMatthew G. Knepley PetscInt d; 41852aa1562SMatthew G. Knepley 41952aa1562SMatthew G. Knepley for (d = 0; d < ctx->dim; ++d, ++i) a[i] = 0.; 42052aa1562SMatthew G. Knepley ctx->cells[q] = -1; 42152aa1562SMatthew G. Knepley ++q; 42252aa1562SMatthew G. Knepley } 423552f7358SJed Brown } 4249566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(ctx->coords, &a)); 425552f7358SJed Brown #if 0 4269566063dSJacob Faibussowitsch PetscCall(PetscFree3(foundCells,foundProcs,globalProcs)); 427552f7358SJed Brown #else 4289566063dSJacob Faibussowitsch PetscCall(PetscFree2(foundProcs, globalProcs)); 4299566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&cellSF)); 4309566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 431552f7358SJed Brown #endif 4329566063dSJacob Faibussowitsch if ((void *)globalPointsScalar != (void *)globalPoints) PetscCall(PetscFree(globalPointsScalar)); 4339566063dSJacob Faibussowitsch if (!redundantPoints) PetscCall(PetscFree3(globalPoints, counts, displs)); 4349566063dSJacob Faibussowitsch PetscCall(PetscLayoutDestroy(&layout)); 4353ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 436552f7358SJed Brown } 437552f7358SJed Brown 4384267b1a3SMatthew G. Knepley /*@C 439f6dfbefdSBarry Smith DMInterpolationGetCoordinates - Gets a `Vec` with the coordinates of each interpolation point 4404267b1a3SMatthew G. Knepley 441c3339decSBarry Smith Collective 4424267b1a3SMatthew G. Knepley 4434267b1a3SMatthew G. Knepley Input Parameter: 4444267b1a3SMatthew G. Knepley . ctx - the context 4454267b1a3SMatthew G. Knepley 4464267b1a3SMatthew G. Knepley Output Parameter: 4474267b1a3SMatthew G. Knepley . coordinates - the coordinates of interpolation points 4484267b1a3SMatthew G. Knepley 44920f4b53cSBarry Smith Level: intermediate 45020f4b53cSBarry Smith 451f6dfbefdSBarry Smith Note: 452f6dfbefdSBarry Smith The local vector entries correspond to interpolation points lying on this process, according to the associated `DM`. 453f6dfbefdSBarry Smith This is a borrowed vector that the user should not destroy. 4544267b1a3SMatthew G. Knepley 455f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 4564267b1a3SMatthew G. Knepley @*/ 457d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetCoordinates(DMInterpolationInfo ctx, Vec *coordinates) 458d71ae5a4SJacob Faibussowitsch { 459552f7358SJed Brown PetscFunctionBegin; 4604f572ea9SToby Isaac PetscAssertPointer(coordinates, 2); 46128b400f6SJacob Faibussowitsch PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup."); 462552f7358SJed Brown *coordinates = ctx->coords; 4633ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 464552f7358SJed Brown } 465552f7358SJed Brown 4664267b1a3SMatthew G. Knepley /*@C 467f6dfbefdSBarry Smith DMInterpolationGetVector - Gets a `Vec` which can hold all the interpolated field values 4684267b1a3SMatthew G. Knepley 469c3339decSBarry Smith Collective 4704267b1a3SMatthew G. Knepley 4714267b1a3SMatthew G. Knepley Input Parameter: 4724267b1a3SMatthew G. Knepley . ctx - the context 4734267b1a3SMatthew G. Knepley 4744267b1a3SMatthew G. Knepley Output Parameter: 4754267b1a3SMatthew G. Knepley . v - a vector capable of holding the interpolated field values 4764267b1a3SMatthew G. Knepley 4772fe279fdSBarry Smith Level: intermediate 4782fe279fdSBarry Smith 479f6dfbefdSBarry Smith Note: 480f6dfbefdSBarry Smith This vector should be returned using `DMInterpolationRestoreVector()`. 4814267b1a3SMatthew G. Knepley 482f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationRestoreVector()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 4834267b1a3SMatthew G. Knepley @*/ 484d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetVector(DMInterpolationInfo ctx, Vec *v) 485d71ae5a4SJacob Faibussowitsch { 486552f7358SJed Brown PetscFunctionBegin; 4874f572ea9SToby Isaac PetscAssertPointer(v, 2); 48828b400f6SJacob Faibussowitsch PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup."); 4899566063dSJacob Faibussowitsch PetscCall(VecCreate(ctx->comm, v)); 4909566063dSJacob Faibussowitsch PetscCall(VecSetSizes(*v, ctx->n * ctx->dof, PETSC_DECIDE)); 4919566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(*v, ctx->dof)); 4929566063dSJacob Faibussowitsch PetscCall(VecSetType(*v, VECSTANDARD)); 4933ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 494552f7358SJed Brown } 495552f7358SJed Brown 4964267b1a3SMatthew G. Knepley /*@C 497f6dfbefdSBarry Smith DMInterpolationRestoreVector - Returns a `Vec` which can hold all the interpolated field values 4984267b1a3SMatthew G. Knepley 499c3339decSBarry Smith Collective 5004267b1a3SMatthew G. Knepley 5014267b1a3SMatthew G. Knepley Input Parameters: 5024267b1a3SMatthew G. Knepley + ctx - the context 5034267b1a3SMatthew G. Knepley - v - a vector capable of holding the interpolated field values 5044267b1a3SMatthew G. Knepley 5054267b1a3SMatthew G. Knepley Level: intermediate 5064267b1a3SMatthew G. Knepley 507f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetVector()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 5084267b1a3SMatthew G. Knepley @*/ 509d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationRestoreVector(DMInterpolationInfo ctx, Vec *v) 510d71ae5a4SJacob Faibussowitsch { 511552f7358SJed Brown PetscFunctionBegin; 5124f572ea9SToby Isaac PetscAssertPointer(v, 2); 51328b400f6SJacob Faibussowitsch PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup."); 5149566063dSJacob Faibussowitsch PetscCall(VecDestroy(v)); 5153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 516552f7358SJed Brown } 517552f7358SJed Brown 518d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Segment_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 519d71ae5a4SJacob Faibussowitsch { 520cfe5744fSMatthew G. Knepley PetscReal v0, J, invJ, detJ; 521cfe5744fSMatthew G. Knepley const PetscInt dof = ctx->dof; 522cfe5744fSMatthew G. Knepley const PetscScalar *coords; 523cfe5744fSMatthew G. Knepley PetscScalar *a; 524cfe5744fSMatthew G. Knepley PetscInt p; 525cfe5744fSMatthew G. Knepley 526cfe5744fSMatthew G. Knepley PetscFunctionBegin; 5279566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 5289566063dSJacob Faibussowitsch PetscCall(VecGetArray(v, &a)); 529cfe5744fSMatthew G. Knepley for (p = 0; p < ctx->n; ++p) { 530cfe5744fSMatthew G. Knepley PetscInt c = ctx->cells[p]; 531cfe5744fSMatthew G. Knepley PetscScalar *x = NULL; 532cfe5744fSMatthew G. Knepley PetscReal xir[1]; 533cfe5744fSMatthew G. Knepley PetscInt xSize, comp; 534cfe5744fSMatthew G. Knepley 5359566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, &v0, &J, &invJ, &detJ)); 536cfe5744fSMatthew G. Knepley PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c); 537cfe5744fSMatthew G. Knepley xir[0] = invJ * PetscRealPart(coords[p] - v0); 5389566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x)); 539cfe5744fSMatthew G. Knepley if (2 * dof == xSize) { 540cfe5744fSMatthew 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]; 541cfe5744fSMatthew G. Knepley } else if (dof == xSize) { 542cfe5744fSMatthew G. Knepley for (comp = 0; comp < dof; ++comp) a[p * dof + comp] = x[0 * dof + comp]; 543cfe5744fSMatthew 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); 5449566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x)); 545cfe5744fSMatthew G. Knepley } 5469566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(v, &a)); 5479566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 5483ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 549cfe5744fSMatthew G. Knepley } 550cfe5744fSMatthew G. Knepley 551d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Triangle_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 552d71ae5a4SJacob Faibussowitsch { 553552f7358SJed Brown PetscReal *v0, *J, *invJ, detJ; 55456044e6dSMatthew G. Knepley const PetscScalar *coords; 55556044e6dSMatthew G. Knepley PetscScalar *a; 556552f7358SJed Brown PetscInt p; 557552f7358SJed Brown 558552f7358SJed Brown PetscFunctionBegin; 5599566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(ctx->dim, &v0, ctx->dim * ctx->dim, &J, ctx->dim * ctx->dim, &invJ)); 5609566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 5619566063dSJacob Faibussowitsch PetscCall(VecGetArray(v, &a)); 562552f7358SJed Brown for (p = 0; p < ctx->n; ++p) { 563552f7358SJed Brown PetscInt c = ctx->cells[p]; 564a1e44745SMatthew G. Knepley PetscScalar *x = NULL; 565552f7358SJed Brown PetscReal xi[4]; 566552f7358SJed Brown PetscInt d, f, comp; 567552f7358SJed Brown 5689566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ)); 56963a3b9bcSJacob Faibussowitsch PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c); 5709566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x)); 5711aa26658SKarl Rupp for (comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp]; 5721aa26658SKarl Rupp 573552f7358SJed Brown for (d = 0; d < ctx->dim; ++d) { 574552f7358SJed Brown xi[d] = 0.0; 5751aa26658SKarl 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]); 5761aa26658SKarl 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]; 577552f7358SJed Brown } 5789566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x)); 579552f7358SJed Brown } 5809566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(v, &a)); 5819566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 5829566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 5833ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 584552f7358SJed Brown } 585552f7358SJed Brown 586d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Tetrahedron_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 587d71ae5a4SJacob Faibussowitsch { 5887a1931ceSMatthew G. Knepley PetscReal *v0, *J, *invJ, detJ; 58956044e6dSMatthew G. Knepley const PetscScalar *coords; 59056044e6dSMatthew G. Knepley PetscScalar *a; 5917a1931ceSMatthew G. Knepley PetscInt p; 5927a1931ceSMatthew G. Knepley 5937a1931ceSMatthew G. Knepley PetscFunctionBegin; 5949566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(ctx->dim, &v0, ctx->dim * ctx->dim, &J, ctx->dim * ctx->dim, &invJ)); 5959566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 5969566063dSJacob Faibussowitsch PetscCall(VecGetArray(v, &a)); 5977a1931ceSMatthew G. Knepley for (p = 0; p < ctx->n; ++p) { 5987a1931ceSMatthew G. Knepley PetscInt c = ctx->cells[p]; 5997a1931ceSMatthew G. Knepley const PetscInt order[3] = {2, 1, 3}; 6002584bbe8SMatthew G. Knepley PetscScalar *x = NULL; 6017a1931ceSMatthew G. Knepley PetscReal xi[4]; 6027a1931ceSMatthew G. Knepley PetscInt d, f, comp; 6037a1931ceSMatthew G. Knepley 6049566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ)); 60563a3b9bcSJacob Faibussowitsch PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c); 6069566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x)); 6077a1931ceSMatthew G. Knepley for (comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp]; 6087a1931ceSMatthew G. Knepley 6097a1931ceSMatthew G. Knepley for (d = 0; d < ctx->dim; ++d) { 6107a1931ceSMatthew G. Knepley xi[d] = 0.0; 6117a1931ceSMatthew 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]); 6127a1931ceSMatthew 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]; 6137a1931ceSMatthew G. Knepley } 6149566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x)); 6157a1931ceSMatthew G. Knepley } 6169566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(v, &a)); 6179566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 6189566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 6193ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 6207a1931ceSMatthew G. Knepley } 6217a1931ceSMatthew G. Knepley 622d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode QuadMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx) 623d71ae5a4SJacob Faibussowitsch { 624552f7358SJed Brown const PetscScalar *vertices = (const PetscScalar *)ctx; 625552f7358SJed Brown const PetscScalar x0 = vertices[0]; 626552f7358SJed Brown const PetscScalar y0 = vertices[1]; 627552f7358SJed Brown const PetscScalar x1 = vertices[2]; 628552f7358SJed Brown const PetscScalar y1 = vertices[3]; 629552f7358SJed Brown const PetscScalar x2 = vertices[4]; 630552f7358SJed Brown const PetscScalar y2 = vertices[5]; 631552f7358SJed Brown const PetscScalar x3 = vertices[6]; 632552f7358SJed Brown const PetscScalar y3 = vertices[7]; 633552f7358SJed Brown const PetscScalar f_1 = x1 - x0; 634552f7358SJed Brown const PetscScalar g_1 = y1 - y0; 635552f7358SJed Brown const PetscScalar f_3 = x3 - x0; 636552f7358SJed Brown const PetscScalar g_3 = y3 - y0; 637552f7358SJed Brown const PetscScalar f_01 = x2 - x1 - x3 + x0; 638552f7358SJed Brown const PetscScalar g_01 = y2 - y1 - y3 + y0; 63956044e6dSMatthew G. Knepley const PetscScalar *ref; 64056044e6dSMatthew G. Knepley PetscScalar *real; 641552f7358SJed Brown 642552f7358SJed Brown PetscFunctionBegin; 6439566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(Xref, &ref)); 6449566063dSJacob Faibussowitsch PetscCall(VecGetArray(Xreal, &real)); 645552f7358SJed Brown { 646552f7358SJed Brown const PetscScalar p0 = ref[0]; 647552f7358SJed Brown const PetscScalar p1 = ref[1]; 648552f7358SJed Brown 649552f7358SJed Brown real[0] = x0 + f_1 * p0 + f_3 * p1 + f_01 * p0 * p1; 650552f7358SJed Brown real[1] = y0 + g_1 * p0 + g_3 * p1 + g_01 * p0 * p1; 651552f7358SJed Brown } 6529566063dSJacob Faibussowitsch PetscCall(PetscLogFlops(28)); 6539566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(Xref, &ref)); 6549566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(Xreal, &real)); 6553ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 656552f7358SJed Brown } 657552f7358SJed Brown 658af0996ceSBarry Smith #include <petsc/private/dmimpl.h> 659d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode QuadJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx) 660d71ae5a4SJacob Faibussowitsch { 661552f7358SJed Brown const PetscScalar *vertices = (const PetscScalar *)ctx; 662552f7358SJed Brown const PetscScalar x0 = vertices[0]; 663552f7358SJed Brown const PetscScalar y0 = vertices[1]; 664552f7358SJed Brown const PetscScalar x1 = vertices[2]; 665552f7358SJed Brown const PetscScalar y1 = vertices[3]; 666552f7358SJed Brown const PetscScalar x2 = vertices[4]; 667552f7358SJed Brown const PetscScalar y2 = vertices[5]; 668552f7358SJed Brown const PetscScalar x3 = vertices[6]; 669552f7358SJed Brown const PetscScalar y3 = vertices[7]; 670552f7358SJed Brown const PetscScalar f_01 = x2 - x1 - x3 + x0; 671552f7358SJed Brown const PetscScalar g_01 = y2 - y1 - y3 + y0; 67256044e6dSMatthew G. Knepley const PetscScalar *ref; 673552f7358SJed Brown 674552f7358SJed Brown PetscFunctionBegin; 6759566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(Xref, &ref)); 676552f7358SJed Brown { 677552f7358SJed Brown const PetscScalar x = ref[0]; 678552f7358SJed Brown const PetscScalar y = ref[1]; 679552f7358SJed Brown const PetscInt rows[2] = {0, 1}; 680da80777bSKarl Rupp PetscScalar values[4]; 681da80777bSKarl Rupp 6829371c9d4SSatish Balay values[0] = (x1 - x0 + f_01 * y) * 0.5; 6839371c9d4SSatish Balay values[1] = (x3 - x0 + f_01 * x) * 0.5; 6849371c9d4SSatish Balay values[2] = (y1 - y0 + g_01 * y) * 0.5; 6859371c9d4SSatish Balay values[3] = (y3 - y0 + g_01 * x) * 0.5; 6869566063dSJacob Faibussowitsch PetscCall(MatSetValues(J, 2, rows, 2, rows, values, INSERT_VALUES)); 687552f7358SJed Brown } 6889566063dSJacob Faibussowitsch PetscCall(PetscLogFlops(30)); 6899566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(Xref, &ref)); 6909566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY)); 6919566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY)); 6923ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 693552f7358SJed Brown } 694552f7358SJed Brown 695d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Quad_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 696d71ae5a4SJacob Faibussowitsch { 697fafc0619SMatthew G Knepley DM dmCoord; 698de73a395SMatthew G. Knepley PetscFE fem = NULL; 699552f7358SJed Brown SNES snes; 700552f7358SJed Brown KSP ksp; 701552f7358SJed Brown PC pc; 702552f7358SJed Brown Vec coordsLocal, r, ref, real; 703552f7358SJed Brown Mat J; 704716009bfSMatthew G. Knepley PetscTabulation T = NULL; 70556044e6dSMatthew G. Knepley const PetscScalar *coords; 70656044e6dSMatthew G. Knepley PetscScalar *a; 707716009bfSMatthew G. Knepley PetscReal xir[2] = {0., 0.}; 708de73a395SMatthew G. Knepley PetscInt Nf, p; 7095509d985SMatthew G. Knepley const PetscInt dof = ctx->dof; 710552f7358SJed Brown 711552f7358SJed Brown PetscFunctionBegin; 7129566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 713716009bfSMatthew G. Knepley if (Nf) { 714cfe5744fSMatthew G. Knepley PetscObject obj; 715cfe5744fSMatthew G. Knepley PetscClassId id; 716cfe5744fSMatthew G. Knepley 7179566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, 0, NULL, &obj)); 7189566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 7199371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 7209371c9d4SSatish Balay fem = (PetscFE)obj; 7219371c9d4SSatish Balay PetscCall(PetscFECreateTabulation(fem, 1, 1, xir, 0, &T)); 7229371c9d4SSatish Balay } 723716009bfSMatthew G. Knepley } 7249566063dSJacob Faibussowitsch PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 7259566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDM(dm, &dmCoord)); 7269566063dSJacob Faibussowitsch PetscCall(SNESCreate(PETSC_COMM_SELF, &snes)); 7279566063dSJacob Faibussowitsch PetscCall(SNESSetOptionsPrefix(snes, "quad_interp_")); 7289566063dSJacob Faibussowitsch PetscCall(VecCreate(PETSC_COMM_SELF, &r)); 7299566063dSJacob Faibussowitsch PetscCall(VecSetSizes(r, 2, 2)); 7309566063dSJacob Faibussowitsch PetscCall(VecSetType(r, dm->vectype)); 7319566063dSJacob Faibussowitsch PetscCall(VecDuplicate(r, &ref)); 7329566063dSJacob Faibussowitsch PetscCall(VecDuplicate(r, &real)); 7339566063dSJacob Faibussowitsch PetscCall(MatCreate(PETSC_COMM_SELF, &J)); 7349566063dSJacob Faibussowitsch PetscCall(MatSetSizes(J, 2, 2, 2, 2)); 7359566063dSJacob Faibussowitsch PetscCall(MatSetType(J, MATSEQDENSE)); 7369566063dSJacob Faibussowitsch PetscCall(MatSetUp(J)); 7379566063dSJacob Faibussowitsch PetscCall(SNESSetFunction(snes, r, QuadMap_Private, NULL)); 7389566063dSJacob Faibussowitsch PetscCall(SNESSetJacobian(snes, J, J, QuadJacobian_Private, NULL)); 7399566063dSJacob Faibussowitsch PetscCall(SNESGetKSP(snes, &ksp)); 7409566063dSJacob Faibussowitsch PetscCall(KSPGetPC(ksp, &pc)); 7419566063dSJacob Faibussowitsch PetscCall(PCSetType(pc, PCLU)); 7429566063dSJacob Faibussowitsch PetscCall(SNESSetFromOptions(snes)); 743552f7358SJed Brown 7449566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 7459566063dSJacob Faibussowitsch PetscCall(VecGetArray(v, &a)); 746552f7358SJed Brown for (p = 0; p < ctx->n; ++p) { 747a1e44745SMatthew G. Knepley PetscScalar *x = NULL, *vertices = NULL; 748552f7358SJed Brown PetscScalar *xi; 749552f7358SJed Brown PetscInt c = ctx->cells[p], comp, coordSize, xSize; 750552f7358SJed Brown 751552f7358SJed Brown /* Can make this do all points at once */ 7529566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices)); 75363a3b9bcSJacob Faibussowitsch PetscCheck(4 * 2 == coordSize, ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid closure size %" PetscInt_FMT " should be %d", coordSize, 4 * 2); 7549566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x)); 7559566063dSJacob Faibussowitsch PetscCall(SNESSetFunction(snes, NULL, NULL, vertices)); 7569566063dSJacob Faibussowitsch PetscCall(SNESSetJacobian(snes, NULL, NULL, NULL, vertices)); 7579566063dSJacob Faibussowitsch PetscCall(VecGetArray(real, &xi)); 758552f7358SJed Brown xi[0] = coords[p * ctx->dim + 0]; 759552f7358SJed Brown xi[1] = coords[p * ctx->dim + 1]; 7609566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(real, &xi)); 7619566063dSJacob Faibussowitsch PetscCall(SNESSolve(snes, real, ref)); 7629566063dSJacob Faibussowitsch PetscCall(VecGetArray(ref, &xi)); 763cb313848SJed Brown xir[0] = PetscRealPart(xi[0]); 764cb313848SJed Brown xir[1] = PetscRealPart(xi[1]); 765cfe5744fSMatthew G. Knepley if (4 * dof == xSize) { 7669371c9d4SSatish 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]; 767cfe5744fSMatthew G. Knepley } else if (dof == xSize) { 768cfe5744fSMatthew G. Knepley for (comp = 0; comp < dof; ++comp) a[p * dof + comp] = x[0 * dof + comp]; 769cfe5744fSMatthew G. Knepley } else { 7705509d985SMatthew G. Knepley PetscInt d; 7711aa26658SKarl Rupp 7722c71b3e2SJacob Faibussowitsch PetscCheck(fem, ctx->comm, PETSC_ERR_ARG_WRONG, "Cannot have a higher order interpolant if the discretization is not PetscFE"); 7739371c9d4SSatish Balay xir[0] = 2.0 * xir[0] - 1.0; 7749371c9d4SSatish Balay xir[1] = 2.0 * xir[1] - 1.0; 7759566063dSJacob Faibussowitsch PetscCall(PetscFEComputeTabulation(fem, 1, xir, 0, T)); 7765509d985SMatthew G. Knepley for (comp = 0; comp < dof; ++comp) { 7775509d985SMatthew G. Knepley a[p * dof + comp] = 0.0; 778ad540459SPierre Jolivet for (d = 0; d < xSize / dof; ++d) a[p * dof + comp] += x[d * dof + comp] * T->T[0][d * dof + comp]; 7795509d985SMatthew G. Knepley } 7805509d985SMatthew G. Knepley } 7819566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(ref, &xi)); 7829566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices)); 7839566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x)); 784552f7358SJed Brown } 7859566063dSJacob Faibussowitsch PetscCall(PetscTabulationDestroy(&T)); 7869566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(v, &a)); 7879566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 788552f7358SJed Brown 7899566063dSJacob Faibussowitsch PetscCall(SNESDestroy(&snes)); 7909566063dSJacob Faibussowitsch PetscCall(VecDestroy(&r)); 7919566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ref)); 7929566063dSJacob Faibussowitsch PetscCall(VecDestroy(&real)); 7939566063dSJacob Faibussowitsch PetscCall(MatDestroy(&J)); 7943ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 795552f7358SJed Brown } 796552f7358SJed Brown 797d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode HexMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx) 798d71ae5a4SJacob Faibussowitsch { 799552f7358SJed Brown const PetscScalar *vertices = (const PetscScalar *)ctx; 800552f7358SJed Brown const PetscScalar x0 = vertices[0]; 801552f7358SJed Brown const PetscScalar y0 = vertices[1]; 802552f7358SJed Brown const PetscScalar z0 = vertices[2]; 8037a1931ceSMatthew G. Knepley const PetscScalar x1 = vertices[9]; 8047a1931ceSMatthew G. Knepley const PetscScalar y1 = vertices[10]; 8057a1931ceSMatthew G. Knepley const PetscScalar z1 = vertices[11]; 806552f7358SJed Brown const PetscScalar x2 = vertices[6]; 807552f7358SJed Brown const PetscScalar y2 = vertices[7]; 808552f7358SJed Brown const PetscScalar z2 = vertices[8]; 8097a1931ceSMatthew G. Knepley const PetscScalar x3 = vertices[3]; 8107a1931ceSMatthew G. Knepley const PetscScalar y3 = vertices[4]; 8117a1931ceSMatthew G. Knepley const PetscScalar z3 = vertices[5]; 812552f7358SJed Brown const PetscScalar x4 = vertices[12]; 813552f7358SJed Brown const PetscScalar y4 = vertices[13]; 814552f7358SJed Brown const PetscScalar z4 = vertices[14]; 815552f7358SJed Brown const PetscScalar x5 = vertices[15]; 816552f7358SJed Brown const PetscScalar y5 = vertices[16]; 817552f7358SJed Brown const PetscScalar z5 = vertices[17]; 818552f7358SJed Brown const PetscScalar x6 = vertices[18]; 819552f7358SJed Brown const PetscScalar y6 = vertices[19]; 820552f7358SJed Brown const PetscScalar z6 = vertices[20]; 821552f7358SJed Brown const PetscScalar x7 = vertices[21]; 822552f7358SJed Brown const PetscScalar y7 = vertices[22]; 823552f7358SJed Brown const PetscScalar z7 = vertices[23]; 824552f7358SJed Brown const PetscScalar f_1 = x1 - x0; 825552f7358SJed Brown const PetscScalar g_1 = y1 - y0; 826552f7358SJed Brown const PetscScalar h_1 = z1 - z0; 827552f7358SJed Brown const PetscScalar f_3 = x3 - x0; 828552f7358SJed Brown const PetscScalar g_3 = y3 - y0; 829552f7358SJed Brown const PetscScalar h_3 = z3 - z0; 830552f7358SJed Brown const PetscScalar f_4 = x4 - x0; 831552f7358SJed Brown const PetscScalar g_4 = y4 - y0; 832552f7358SJed Brown const PetscScalar h_4 = z4 - z0; 833552f7358SJed Brown const PetscScalar f_01 = x2 - x1 - x3 + x0; 834552f7358SJed Brown const PetscScalar g_01 = y2 - y1 - y3 + y0; 835552f7358SJed Brown const PetscScalar h_01 = z2 - z1 - z3 + z0; 836552f7358SJed Brown const PetscScalar f_12 = x7 - x3 - x4 + x0; 837552f7358SJed Brown const PetscScalar g_12 = y7 - y3 - y4 + y0; 838552f7358SJed Brown const PetscScalar h_12 = z7 - z3 - z4 + z0; 839552f7358SJed Brown const PetscScalar f_02 = x5 - x1 - x4 + x0; 840552f7358SJed Brown const PetscScalar g_02 = y5 - y1 - y4 + y0; 841552f7358SJed Brown const PetscScalar h_02 = z5 - z1 - z4 + z0; 842552f7358SJed Brown const PetscScalar f_012 = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7; 843552f7358SJed Brown const PetscScalar g_012 = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7; 844552f7358SJed Brown const PetscScalar h_012 = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7; 84556044e6dSMatthew G. Knepley const PetscScalar *ref; 84656044e6dSMatthew G. Knepley PetscScalar *real; 847552f7358SJed Brown 848552f7358SJed Brown PetscFunctionBegin; 8499566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(Xref, &ref)); 8509566063dSJacob Faibussowitsch PetscCall(VecGetArray(Xreal, &real)); 851552f7358SJed Brown { 852552f7358SJed Brown const PetscScalar p0 = ref[0]; 853552f7358SJed Brown const PetscScalar p1 = ref[1]; 854552f7358SJed Brown const PetscScalar p2 = ref[2]; 855552f7358SJed Brown 856552f7358SJed 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; 857552f7358SJed 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; 858552f7358SJed 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; 859552f7358SJed Brown } 8609566063dSJacob Faibussowitsch PetscCall(PetscLogFlops(114)); 8619566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(Xref, &ref)); 8629566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(Xreal, &real)); 8633ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 864552f7358SJed Brown } 865552f7358SJed Brown 866d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode HexJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx) 867d71ae5a4SJacob Faibussowitsch { 868552f7358SJed Brown const PetscScalar *vertices = (const PetscScalar *)ctx; 869552f7358SJed Brown const PetscScalar x0 = vertices[0]; 870552f7358SJed Brown const PetscScalar y0 = vertices[1]; 871552f7358SJed Brown const PetscScalar z0 = vertices[2]; 8727a1931ceSMatthew G. Knepley const PetscScalar x1 = vertices[9]; 8737a1931ceSMatthew G. Knepley const PetscScalar y1 = vertices[10]; 8747a1931ceSMatthew G. Knepley const PetscScalar z1 = vertices[11]; 875552f7358SJed Brown const PetscScalar x2 = vertices[6]; 876552f7358SJed Brown const PetscScalar y2 = vertices[7]; 877552f7358SJed Brown const PetscScalar z2 = vertices[8]; 8787a1931ceSMatthew G. Knepley const PetscScalar x3 = vertices[3]; 8797a1931ceSMatthew G. Knepley const PetscScalar y3 = vertices[4]; 8807a1931ceSMatthew G. Knepley const PetscScalar z3 = vertices[5]; 881552f7358SJed Brown const PetscScalar x4 = vertices[12]; 882552f7358SJed Brown const PetscScalar y4 = vertices[13]; 883552f7358SJed Brown const PetscScalar z4 = vertices[14]; 884552f7358SJed Brown const PetscScalar x5 = vertices[15]; 885552f7358SJed Brown const PetscScalar y5 = vertices[16]; 886552f7358SJed Brown const PetscScalar z5 = vertices[17]; 887552f7358SJed Brown const PetscScalar x6 = vertices[18]; 888552f7358SJed Brown const PetscScalar y6 = vertices[19]; 889552f7358SJed Brown const PetscScalar z6 = vertices[20]; 890552f7358SJed Brown const PetscScalar x7 = vertices[21]; 891552f7358SJed Brown const PetscScalar y7 = vertices[22]; 892552f7358SJed Brown const PetscScalar z7 = vertices[23]; 893552f7358SJed Brown const PetscScalar f_xy = x2 - x1 - x3 + x0; 894552f7358SJed Brown const PetscScalar g_xy = y2 - y1 - y3 + y0; 895552f7358SJed Brown const PetscScalar h_xy = z2 - z1 - z3 + z0; 896552f7358SJed Brown const PetscScalar f_yz = x7 - x3 - x4 + x0; 897552f7358SJed Brown const PetscScalar g_yz = y7 - y3 - y4 + y0; 898552f7358SJed Brown const PetscScalar h_yz = z7 - z3 - z4 + z0; 899552f7358SJed Brown const PetscScalar f_xz = x5 - x1 - x4 + x0; 900552f7358SJed Brown const PetscScalar g_xz = y5 - y1 - y4 + y0; 901552f7358SJed Brown const PetscScalar h_xz = z5 - z1 - z4 + z0; 902552f7358SJed Brown const PetscScalar f_xyz = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7; 903552f7358SJed Brown const PetscScalar g_xyz = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7; 904552f7358SJed Brown const PetscScalar h_xyz = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7; 90556044e6dSMatthew G. Knepley const PetscScalar *ref; 906552f7358SJed Brown 907552f7358SJed Brown PetscFunctionBegin; 9089566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(Xref, &ref)); 909552f7358SJed Brown { 910552f7358SJed Brown const PetscScalar x = ref[0]; 911552f7358SJed Brown const PetscScalar y = ref[1]; 912552f7358SJed Brown const PetscScalar z = ref[2]; 913552f7358SJed Brown const PetscInt rows[3] = {0, 1, 2}; 914da80777bSKarl Rupp PetscScalar values[9]; 915da80777bSKarl Rupp 916da80777bSKarl Rupp values[0] = (x1 - x0 + f_xy * y + f_xz * z + f_xyz * y * z) / 2.0; 917da80777bSKarl Rupp values[1] = (x3 - x0 + f_xy * x + f_yz * z + f_xyz * x * z) / 2.0; 918da80777bSKarl Rupp values[2] = (x4 - x0 + f_yz * y + f_xz * x + f_xyz * x * y) / 2.0; 919da80777bSKarl Rupp values[3] = (y1 - y0 + g_xy * y + g_xz * z + g_xyz * y * z) / 2.0; 920da80777bSKarl Rupp values[4] = (y3 - y0 + g_xy * x + g_yz * z + g_xyz * x * z) / 2.0; 921da80777bSKarl Rupp values[5] = (y4 - y0 + g_yz * y + g_xz * x + g_xyz * x * y) / 2.0; 922da80777bSKarl Rupp values[6] = (z1 - z0 + h_xy * y + h_xz * z + h_xyz * y * z) / 2.0; 923da80777bSKarl Rupp values[7] = (z3 - z0 + h_xy * x + h_yz * z + h_xyz * x * z) / 2.0; 924da80777bSKarl Rupp values[8] = (z4 - z0 + h_yz * y + h_xz * x + h_xyz * x * y) / 2.0; 9251aa26658SKarl Rupp 9269566063dSJacob Faibussowitsch PetscCall(MatSetValues(J, 3, rows, 3, rows, values, INSERT_VALUES)); 927552f7358SJed Brown } 9289566063dSJacob Faibussowitsch PetscCall(PetscLogFlops(152)); 9299566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(Xref, &ref)); 9309566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY)); 9319566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY)); 9323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 933552f7358SJed Brown } 934552f7358SJed Brown 935d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Hex_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 936d71ae5a4SJacob Faibussowitsch { 937fafc0619SMatthew G Knepley DM dmCoord; 938552f7358SJed Brown SNES snes; 939552f7358SJed Brown KSP ksp; 940552f7358SJed Brown PC pc; 941552f7358SJed Brown Vec coordsLocal, r, ref, real; 942552f7358SJed Brown Mat J; 94356044e6dSMatthew G. Knepley const PetscScalar *coords; 94456044e6dSMatthew G. Knepley PetscScalar *a; 945552f7358SJed Brown PetscInt p; 946552f7358SJed Brown 947552f7358SJed Brown PetscFunctionBegin; 9489566063dSJacob Faibussowitsch PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9499566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDM(dm, &dmCoord)); 9509566063dSJacob Faibussowitsch PetscCall(SNESCreate(PETSC_COMM_SELF, &snes)); 9519566063dSJacob Faibussowitsch PetscCall(SNESSetOptionsPrefix(snes, "hex_interp_")); 9529566063dSJacob Faibussowitsch PetscCall(VecCreate(PETSC_COMM_SELF, &r)); 9539566063dSJacob Faibussowitsch PetscCall(VecSetSizes(r, 3, 3)); 9549566063dSJacob Faibussowitsch PetscCall(VecSetType(r, dm->vectype)); 9559566063dSJacob Faibussowitsch PetscCall(VecDuplicate(r, &ref)); 9569566063dSJacob Faibussowitsch PetscCall(VecDuplicate(r, &real)); 9579566063dSJacob Faibussowitsch PetscCall(MatCreate(PETSC_COMM_SELF, &J)); 9589566063dSJacob Faibussowitsch PetscCall(MatSetSizes(J, 3, 3, 3, 3)); 9599566063dSJacob Faibussowitsch PetscCall(MatSetType(J, MATSEQDENSE)); 9609566063dSJacob Faibussowitsch PetscCall(MatSetUp(J)); 9619566063dSJacob Faibussowitsch PetscCall(SNESSetFunction(snes, r, HexMap_Private, NULL)); 9629566063dSJacob Faibussowitsch PetscCall(SNESSetJacobian(snes, J, J, HexJacobian_Private, NULL)); 9639566063dSJacob Faibussowitsch PetscCall(SNESGetKSP(snes, &ksp)); 9649566063dSJacob Faibussowitsch PetscCall(KSPGetPC(ksp, &pc)); 9659566063dSJacob Faibussowitsch PetscCall(PCSetType(pc, PCLU)); 9669566063dSJacob Faibussowitsch PetscCall(SNESSetFromOptions(snes)); 967552f7358SJed Brown 9689566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 9699566063dSJacob Faibussowitsch PetscCall(VecGetArray(v, &a)); 970552f7358SJed Brown for (p = 0; p < ctx->n; ++p) { 971a1e44745SMatthew G. Knepley PetscScalar *x = NULL, *vertices = NULL; 972552f7358SJed Brown PetscScalar *xi; 973cb313848SJed Brown PetscReal xir[3]; 974552f7358SJed Brown PetscInt c = ctx->cells[p], comp, coordSize, xSize; 975552f7358SJed Brown 976552f7358SJed Brown /* Can make this do all points at once */ 9779566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices)); 978cfe5744fSMatthew G. Knepley PetscCheck(8 * 3 == coordSize, ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid coordinate closure size %" PetscInt_FMT " should be %d", coordSize, 8 * 3); 9799566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x)); 980cfe5744fSMatthew 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); 9819566063dSJacob Faibussowitsch PetscCall(SNESSetFunction(snes, NULL, NULL, vertices)); 9829566063dSJacob Faibussowitsch PetscCall(SNESSetJacobian(snes, NULL, NULL, NULL, vertices)); 9839566063dSJacob Faibussowitsch PetscCall(VecGetArray(real, &xi)); 984552f7358SJed Brown xi[0] = coords[p * ctx->dim + 0]; 985552f7358SJed Brown xi[1] = coords[p * ctx->dim + 1]; 986552f7358SJed Brown xi[2] = coords[p * ctx->dim + 2]; 9879566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(real, &xi)); 9889566063dSJacob Faibussowitsch PetscCall(SNESSolve(snes, real, ref)); 9899566063dSJacob Faibussowitsch PetscCall(VecGetArray(ref, &xi)); 990cb313848SJed Brown xir[0] = PetscRealPart(xi[0]); 991cb313848SJed Brown xir[1] = PetscRealPart(xi[1]); 992cb313848SJed Brown xir[2] = PetscRealPart(xi[2]); 993cfe5744fSMatthew G. Knepley if (8 * ctx->dof == xSize) { 994552f7358SJed Brown for (comp = 0; comp < ctx->dof; ++comp) { 9959371c9d4SSatish 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]) + 9969371c9d4SSatish 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]; 997552f7358SJed Brown } 998cfe5744fSMatthew G. Knepley } else { 999cfe5744fSMatthew G. Knepley for (comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp]; 1000cfe5744fSMatthew G. Knepley } 10019566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(ref, &xi)); 10029566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices)); 10039566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x)); 1004552f7358SJed Brown } 10059566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(v, &a)); 10069566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 1007552f7358SJed Brown 10089566063dSJacob Faibussowitsch PetscCall(SNESDestroy(&snes)); 10099566063dSJacob Faibussowitsch PetscCall(VecDestroy(&r)); 10109566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ref)); 10119566063dSJacob Faibussowitsch PetscCall(VecDestroy(&real)); 10129566063dSJacob Faibussowitsch PetscCall(MatDestroy(&J)); 10133ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1014552f7358SJed Brown } 1015552f7358SJed Brown 10164267b1a3SMatthew G. Knepley /*@C 10174267b1a3SMatthew G. Knepley DMInterpolationEvaluate - Using the input from dm and x, calculates interpolated field values at the interpolation points. 10184267b1a3SMatthew G. Knepley 1019552f7358SJed Brown Input Parameters: 1020f6dfbefdSBarry Smith + ctx - The `DMInterpolationInfo` context 1021f6dfbefdSBarry Smith . dm - The `DM` 1022552f7358SJed Brown - x - The local vector containing the field to be interpolated 1023552f7358SJed Brown 10242fe279fdSBarry Smith Output Parameter: 1025552f7358SJed Brown . v - The vector containing the interpolated values 10264267b1a3SMatthew G. Knepley 10274267b1a3SMatthew G. Knepley Level: beginner 10284267b1a3SMatthew G. Knepley 10292fe279fdSBarry Smith Note: 10302fe279fdSBarry Smith A suitable `v` can be obtained using `DMInterpolationGetVector()`. 10312fe279fdSBarry Smith 1032f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetVector()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 10334267b1a3SMatthew G. Knepley @*/ 1034d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationEvaluate(DMInterpolationInfo ctx, DM dm, Vec x, Vec v) 1035d71ae5a4SJacob Faibussowitsch { 103666a0a883SMatthew G. Knepley PetscDS ds; 103766a0a883SMatthew G. Knepley PetscInt n, p, Nf, field; 103866a0a883SMatthew G. Knepley PetscBool useDS = PETSC_FALSE; 1039552f7358SJed Brown 1040552f7358SJed Brown PetscFunctionBegin; 1041552f7358SJed Brown PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 1042552f7358SJed Brown PetscValidHeaderSpecific(x, VEC_CLASSID, 3); 1043552f7358SJed Brown PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 10449566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(v, &n)); 104563a3b9bcSJacob 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); 10463ba16761SJacob Faibussowitsch if (!n) PetscFunctionReturn(PETSC_SUCCESS); 10479566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &ds)); 1048680d18d5SMatthew G. Knepley if (ds) { 104966a0a883SMatthew G. Knepley useDS = PETSC_TRUE; 10509566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 1051680d18d5SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 105266a0a883SMatthew G. Knepley PetscObject obj; 1053680d18d5SMatthew G. Knepley PetscClassId id; 1054680d18d5SMatthew G. Knepley 10559566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, field, &obj)); 10569566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 10579371c9d4SSatish Balay if (id != PETSCFE_CLASSID) { 10589371c9d4SSatish Balay useDS = PETSC_FALSE; 10599371c9d4SSatish Balay break; 10609371c9d4SSatish Balay } 106166a0a883SMatthew G. Knepley } 106266a0a883SMatthew G. Knepley } 106366a0a883SMatthew G. Knepley if (useDS) { 106466a0a883SMatthew G. Knepley const PetscScalar *coords; 106566a0a883SMatthew G. Knepley PetscScalar *interpolant; 106666a0a883SMatthew G. Knepley PetscInt cdim, d; 106766a0a883SMatthew G. Knepley 10689566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &cdim)); 10699566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 10709566063dSJacob Faibussowitsch PetscCall(VecGetArrayWrite(v, &interpolant)); 1071680d18d5SMatthew G. Knepley for (p = 0; p < ctx->n; ++p) { 107266a0a883SMatthew G. Knepley PetscReal pcoords[3], xi[3]; 1073680d18d5SMatthew G. Knepley PetscScalar *xa = NULL; 107466a0a883SMatthew G. Knepley PetscInt coff = 0, foff = 0, clSize; 1075680d18d5SMatthew G. Knepley 107652aa1562SMatthew G. Knepley if (ctx->cells[p] < 0) continue; 1077680d18d5SMatthew G. Knepley for (d = 0; d < cdim; ++d) pcoords[d] = PetscRealPart(coords[p * cdim + d]); 10789566063dSJacob Faibussowitsch PetscCall(DMPlexCoordinatesToReference(dm, ctx->cells[p], 1, pcoords, xi)); 10799566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa)); 108066a0a883SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 108166a0a883SMatthew G. Knepley PetscTabulation T; 108266a0a883SMatthew G. Knepley PetscFE fe; 108366a0a883SMatthew G. Knepley 10849566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *)&fe)); 10859566063dSJacob Faibussowitsch PetscCall(PetscFECreateTabulation(fe, 1, 1, xi, 0, &T)); 1086680d18d5SMatthew G. Knepley { 1087680d18d5SMatthew G. Knepley const PetscReal *basis = T->T[0]; 1088680d18d5SMatthew G. Knepley const PetscInt Nb = T->Nb; 1089680d18d5SMatthew G. Knepley const PetscInt Nc = T->Nc; 109066a0a883SMatthew G. Knepley PetscInt f, fc; 109166a0a883SMatthew G. Knepley 1092680d18d5SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 109366a0a883SMatthew G. Knepley interpolant[p * ctx->dof + coff + fc] = 0.0; 1094ad540459SPierre Jolivet for (f = 0; f < Nb; ++f) interpolant[p * ctx->dof + coff + fc] += xa[foff + f] * basis[(0 * Nb + f) * Nc + fc]; 1095680d18d5SMatthew G. Knepley } 109666a0a883SMatthew G. Knepley coff += Nc; 109766a0a883SMatthew G. Knepley foff += Nb; 1098680d18d5SMatthew G. Knepley } 10999566063dSJacob Faibussowitsch PetscCall(PetscTabulationDestroy(&T)); 1100680d18d5SMatthew G. Knepley } 11019566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa)); 110263a3b9bcSJacob Faibussowitsch PetscCheck(coff == ctx->dof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total components %" PetscInt_FMT " != %" PetscInt_FMT " dof specified for interpolation", coff, ctx->dof); 110363a3b9bcSJacob Faibussowitsch PetscCheck(foff == clSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total FE space size %" PetscInt_FMT " != %" PetscInt_FMT " closure size", foff, clSize); 110466a0a883SMatthew G. Knepley } 11059566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 11069566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayWrite(v, &interpolant)); 110766a0a883SMatthew G. Knepley } else { 110866a0a883SMatthew G. Knepley DMPolytopeType ct; 110966a0a883SMatthew G. Knepley 1110680d18d5SMatthew G. Knepley /* TODO Check each cell individually */ 11119566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellType(dm, ctx->cells[0], &ct)); 1112680d18d5SMatthew G. Knepley switch (ct) { 1113d71ae5a4SJacob Faibussowitsch case DM_POLYTOPE_SEGMENT: 1114d71ae5a4SJacob Faibussowitsch PetscCall(DMInterpolate_Segment_Private(ctx, dm, x, v)); 1115d71ae5a4SJacob Faibussowitsch break; 1116d71ae5a4SJacob Faibussowitsch case DM_POLYTOPE_TRIANGLE: 1117d71ae5a4SJacob Faibussowitsch PetscCall(DMInterpolate_Triangle_Private(ctx, dm, x, v)); 1118d71ae5a4SJacob Faibussowitsch break; 1119d71ae5a4SJacob Faibussowitsch case DM_POLYTOPE_QUADRILATERAL: 1120d71ae5a4SJacob Faibussowitsch PetscCall(DMInterpolate_Quad_Private(ctx, dm, x, v)); 1121d71ae5a4SJacob Faibussowitsch break; 1122d71ae5a4SJacob Faibussowitsch case DM_POLYTOPE_TETRAHEDRON: 1123d71ae5a4SJacob Faibussowitsch PetscCall(DMInterpolate_Tetrahedron_Private(ctx, dm, x, v)); 1124d71ae5a4SJacob Faibussowitsch break; 1125d71ae5a4SJacob Faibussowitsch case DM_POLYTOPE_HEXAHEDRON: 1126d71ae5a4SJacob Faibussowitsch PetscCall(DMInterpolate_Hex_Private(ctx, dm, x, v)); 1127d71ae5a4SJacob Faibussowitsch break; 1128d71ae5a4SJacob Faibussowitsch default: 1129d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for cell type %s", DMPolytopeTypes[PetscMax(0, PetscMin(ct, DM_NUM_POLYTOPES))]); 1130680d18d5SMatthew G. Knepley } 1131552f7358SJed Brown } 11323ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1133552f7358SJed Brown } 1134552f7358SJed Brown 11354267b1a3SMatthew G. Knepley /*@C 1136f6dfbefdSBarry Smith DMInterpolationDestroy - Destroys a `DMInterpolationInfo` context 11374267b1a3SMatthew G. Knepley 1138c3339decSBarry Smith Collective 11394267b1a3SMatthew G. Knepley 11404267b1a3SMatthew G. Knepley Input Parameter: 11414267b1a3SMatthew G. Knepley . ctx - the context 11424267b1a3SMatthew G. Knepley 11434267b1a3SMatthew G. Knepley Level: beginner 11444267b1a3SMatthew G. Knepley 1145f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 11464267b1a3SMatthew G. Knepley @*/ 1147d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationDestroy(DMInterpolationInfo *ctx) 1148d71ae5a4SJacob Faibussowitsch { 1149552f7358SJed Brown PetscFunctionBegin; 11504f572ea9SToby Isaac PetscAssertPointer(ctx, 1); 11519566063dSJacob Faibussowitsch PetscCall(VecDestroy(&(*ctx)->coords)); 11529566063dSJacob Faibussowitsch PetscCall(PetscFree((*ctx)->points)); 11539566063dSJacob Faibussowitsch PetscCall(PetscFree((*ctx)->cells)); 11549566063dSJacob Faibussowitsch PetscCall(PetscFree(*ctx)); 11550298fd71SBarry Smith *ctx = NULL; 11563ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1157552f7358SJed Brown } 1158cc0c4584SMatthew G. Knepley 1159cc0c4584SMatthew G. Knepley /*@C 1160cc0c4584SMatthew G. Knepley SNESMonitorFields - Monitors the residual for each field separately 1161cc0c4584SMatthew G. Knepley 1162c3339decSBarry Smith Collective 1163cc0c4584SMatthew G. Knepley 1164cc0c4584SMatthew G. Knepley Input Parameters: 1165f6dfbefdSBarry Smith + snes - the `SNES` context 1166cc0c4584SMatthew G. Knepley . its - iteration number 1167cc0c4584SMatthew G. Knepley . fgnorm - 2-norm of residual 1168f6dfbefdSBarry Smith - vf - `PetscViewerAndFormat` of `PetscViewerType` `PETSCVIEWERASCII` 1169cc0c4584SMatthew G. Knepley 11702fe279fdSBarry Smith Level: intermediate 11712fe279fdSBarry Smith 1172f6dfbefdSBarry Smith Note: 1173cc0c4584SMatthew G. Knepley This routine prints the residual norm at each iteration. 1174cc0c4584SMatthew G. Knepley 1175f6dfbefdSBarry Smith .seealso: `SNES`, `SNESMonitorSet()`, `SNESMonitorDefault()` 1176cc0c4584SMatthew G. Knepley @*/ 1177d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESMonitorFields(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf) 1178d71ae5a4SJacob Faibussowitsch { 1179d43b4f6eSBarry Smith PetscViewer viewer = vf->viewer; 1180cc0c4584SMatthew G. Knepley Vec res; 1181cc0c4584SMatthew G. Knepley DM dm; 1182cc0c4584SMatthew G. Knepley PetscSection s; 1183cc0c4584SMatthew G. Knepley const PetscScalar *r; 1184cc0c4584SMatthew G. Knepley PetscReal *lnorms, *norms; 1185cc0c4584SMatthew G. Knepley PetscInt numFields, f, pStart, pEnd, p; 1186cc0c4584SMatthew G. Knepley 1187cc0c4584SMatthew G. Knepley PetscFunctionBegin; 11884d4332d5SBarry Smith PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4); 11899566063dSJacob Faibussowitsch PetscCall(SNESGetFunction(snes, &res, NULL, NULL)); 11909566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &dm)); 11919566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 11929566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(s, &numFields)); 11939566063dSJacob Faibussowitsch PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 11949566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFields, &lnorms, numFields, &norms)); 11959566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(res, &r)); 1196cc0c4584SMatthew G. Knepley for (p = pStart; p < pEnd; ++p) { 1197cc0c4584SMatthew G. Knepley for (f = 0; f < numFields; ++f) { 1198cc0c4584SMatthew G. Knepley PetscInt fdof, foff, d; 1199cc0c4584SMatthew G. Knepley 12009566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, p, f, &fdof)); 12019566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldOffset(s, p, f, &foff)); 1202cc0c4584SMatthew G. Knepley for (d = 0; d < fdof; ++d) lnorms[f] += PetscRealPart(PetscSqr(r[foff + d])); 1203cc0c4584SMatthew G. Knepley } 1204cc0c4584SMatthew G. Knepley } 12059566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(res, &r)); 12061c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(lnorms, norms, numFields, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 12079566063dSJacob Faibussowitsch PetscCall(PetscViewerPushFormat(viewer, vf->format)); 12089566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)snes)->tablevel)); 120963a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %14.12e [", its, (double)fgnorm)); 1210cc0c4584SMatthew G. Knepley for (f = 0; f < numFields; ++f) { 12119566063dSJacob Faibussowitsch if (f > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 12129566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "%14.12e", (double)PetscSqrtReal(norms[f]))); 1213cc0c4584SMatthew G. Knepley } 12149566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "]\n")); 12159566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)snes)->tablevel)); 12169566063dSJacob Faibussowitsch PetscCall(PetscViewerPopFormat(viewer)); 12179566063dSJacob Faibussowitsch PetscCall(PetscFree2(lnorms, norms)); 12183ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1219cc0c4584SMatthew G. Knepley } 122024cdb843SMatthew G. Knepley 122124cdb843SMatthew G. Knepley /********************* Residual Computation **************************/ 122224cdb843SMatthew G. Knepley 1223d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 1224d71ae5a4SJacob Faibussowitsch { 12256528b96dSMatthew G. Knepley PetscInt depth; 12266528b96dSMatthew G. Knepley 12276528b96dSMatthew G. Knepley PetscFunctionBegin; 12289566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepth(plex, &depth)); 12299566063dSJacob Faibussowitsch PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 12309566063dSJacob Faibussowitsch if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 12313ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 12326528b96dSMatthew G. Knepley } 12336528b96dSMatthew G. Knepley 123424cdb843SMatthew G. Knepley /*@ 12358db23a53SJed Brown DMPlexSNESComputeResidualFEM - Sums the local residual into vector F from the local input X using pointwise functions specified by the user 123624cdb843SMatthew G. Knepley 123724cdb843SMatthew G. Knepley Input Parameters: 123824cdb843SMatthew G. Knepley + dm - The mesh 123924cdb843SMatthew G. Knepley . X - Local solution 124024cdb843SMatthew G. Knepley - user - The user context 124124cdb843SMatthew G. Knepley 124224cdb843SMatthew G. Knepley Output Parameter: 124324cdb843SMatthew G. Knepley . F - Local output vector 124424cdb843SMatthew G. Knepley 12452fe279fdSBarry Smith Level: developer 12462fe279fdSBarry Smith 1247f6dfbefdSBarry Smith Note: 1248f6dfbefdSBarry Smith The residual is summed into F; the caller is responsible for using `VecZeroEntries()` or otherwise ensuring that any data in F is intentional. 12498db23a53SJed Brown 1250f6dfbefdSBarry Smith .seealso: `DM`, `DMPlexComputeJacobianAction()` 125124cdb843SMatthew G. Knepley @*/ 1252d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSNESComputeResidualFEM(DM dm, Vec X, Vec F, void *user) 1253d71ae5a4SJacob Faibussowitsch { 12546da023fcSToby Isaac DM plex; 1255083401c6SMatthew G. Knepley IS allcellIS; 12566528b96dSMatthew G. Knepley PetscInt Nds, s; 125724cdb843SMatthew G. Knepley 125824cdb843SMatthew G. Knepley PetscFunctionBegin; 12599566063dSJacob Faibussowitsch PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 12609566063dSJacob Faibussowitsch PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS)); 12619566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 12626528b96dSMatthew G. Knepley for (s = 0; s < Nds; ++s) { 12636528b96dSMatthew G. Knepley PetscDS ds; 12646528b96dSMatthew G. Knepley IS cellIS; 126506ad1575SMatthew G. Knepley PetscFormKey key; 12666528b96dSMatthew G. Knepley 126707218a29SMatthew G. Knepley PetscCall(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds, NULL)); 12686528b96dSMatthew G. Knepley key.value = 0; 12696528b96dSMatthew G. Knepley key.field = 0; 127006ad1575SMatthew G. Knepley key.part = 0; 12716528b96dSMatthew G. Knepley if (!key.label) { 12729566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)allcellIS)); 12736528b96dSMatthew G. Knepley cellIS = allcellIS; 12746528b96dSMatthew G. Knepley } else { 12756528b96dSMatthew G. Knepley IS pointIS; 12766528b96dSMatthew G. Knepley 12776528b96dSMatthew G. Knepley key.value = 1; 12789566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 12799566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS)); 12809566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 12816528b96dSMatthew G. Knepley } 12829566063dSJacob Faibussowitsch PetscCall(DMPlexComputeResidual_Internal(plex, key, cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user)); 12839566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 12846528b96dSMatthew G. Knepley } 12859566063dSJacob Faibussowitsch PetscCall(ISDestroy(&allcellIS)); 12869566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 12873ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 12886528b96dSMatthew G. Knepley } 12896528b96dSMatthew G. Knepley 1290d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESComputeResidual(DM dm, Vec X, Vec F, void *user) 1291d71ae5a4SJacob Faibussowitsch { 12926528b96dSMatthew G. Knepley DM plex; 12936528b96dSMatthew G. Knepley IS allcellIS; 12946528b96dSMatthew G. Knepley PetscInt Nds, s; 12956528b96dSMatthew G. Knepley 12966528b96dSMatthew G. Knepley PetscFunctionBegin; 12979566063dSJacob Faibussowitsch PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 12989566063dSJacob Faibussowitsch PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS)); 12999566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 1300083401c6SMatthew G. Knepley for (s = 0; s < Nds; ++s) { 1301083401c6SMatthew G. Knepley PetscDS ds; 1302083401c6SMatthew G. Knepley DMLabel label; 1303083401c6SMatthew G. Knepley IS cellIS; 1304083401c6SMatthew G. Knepley 130507218a29SMatthew G. Knepley PetscCall(DMGetRegionNumDS(dm, s, &label, NULL, &ds, NULL)); 13066528b96dSMatthew G. Knepley { 130706ad1575SMatthew G. Knepley PetscWeakFormKind resmap[2] = {PETSC_WF_F0, PETSC_WF_F1}; 13086528b96dSMatthew G. Knepley PetscWeakForm wf; 13096528b96dSMatthew G. Knepley PetscInt Nm = 2, m, Nk = 0, k, kp, off = 0; 131006ad1575SMatthew G. Knepley PetscFormKey *reskeys; 13116528b96dSMatthew G. Knepley 13126528b96dSMatthew G. Knepley /* Get unique residual keys */ 13136528b96dSMatthew G. Knepley for (m = 0; m < Nm; ++m) { 13146528b96dSMatthew G. Knepley PetscInt Nkm; 13159566063dSJacob Faibussowitsch PetscCall(PetscHMapFormGetSize(ds->wf->form[resmap[m]], &Nkm)); 13166528b96dSMatthew G. Knepley Nk += Nkm; 13176528b96dSMatthew G. Knepley } 13189566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nk, &reskeys)); 131948a46eb9SPierre Jolivet for (m = 0; m < Nm; ++m) PetscCall(PetscHMapFormGetKeys(ds->wf->form[resmap[m]], &off, reskeys)); 132063a3b9bcSJacob Faibussowitsch PetscCheck(off == Nk, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %" PetscInt_FMT " should be %" PetscInt_FMT, off, Nk); 13219566063dSJacob Faibussowitsch PetscCall(PetscFormKeySort(Nk, reskeys)); 13226528b96dSMatthew G. Knepley for (k = 0, kp = 1; kp < Nk; ++kp) { 13236528b96dSMatthew G. Knepley if ((reskeys[k].label != reskeys[kp].label) || (reskeys[k].value != reskeys[kp].value)) { 13246528b96dSMatthew G. Knepley ++k; 13256528b96dSMatthew G. Knepley if (kp != k) reskeys[k] = reskeys[kp]; 13266528b96dSMatthew G. Knepley } 13276528b96dSMatthew G. Knepley } 13286528b96dSMatthew G. Knepley Nk = k; 13296528b96dSMatthew G. Knepley 13309566063dSJacob Faibussowitsch PetscCall(PetscDSGetWeakForm(ds, &wf)); 13316528b96dSMatthew G. Knepley for (k = 0; k < Nk; ++k) { 13326528b96dSMatthew G. Knepley DMLabel label = reskeys[k].label; 13336528b96dSMatthew G. Knepley PetscInt val = reskeys[k].value; 13346528b96dSMatthew G. Knepley 1335083401c6SMatthew G. Knepley if (!label) { 13369566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)allcellIS)); 1337083401c6SMatthew G. Knepley cellIS = allcellIS; 1338083401c6SMatthew G. Knepley } else { 1339083401c6SMatthew G. Knepley IS pointIS; 1340083401c6SMatthew G. Knepley 13419566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, val, &pointIS)); 13429566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS)); 13439566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 13444a3e9fdbSToby Isaac } 13459566063dSJacob Faibussowitsch PetscCall(DMPlexComputeResidual_Internal(plex, reskeys[k], cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user)); 13469566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 1347083401c6SMatthew G. Knepley } 13489566063dSJacob Faibussowitsch PetscCall(PetscFree(reskeys)); 13496528b96dSMatthew G. Knepley } 13506528b96dSMatthew G. Knepley } 13519566063dSJacob Faibussowitsch PetscCall(ISDestroy(&allcellIS)); 13529566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 13533ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 135424cdb843SMatthew G. Knepley } 135524cdb843SMatthew G. Knepley 1356bdd6f66aSToby Isaac /*@ 1357bdd6f66aSToby Isaac DMPlexSNESComputeBoundaryFEM - Form the boundary values for the local input X 1358bdd6f66aSToby Isaac 1359bdd6f66aSToby Isaac Input Parameters: 1360bdd6f66aSToby Isaac + dm - The mesh 1361bdd6f66aSToby Isaac - user - The user context 1362bdd6f66aSToby Isaac 1363bdd6f66aSToby Isaac Output Parameter: 1364bdd6f66aSToby Isaac . X - Local solution 1365bdd6f66aSToby Isaac 1366bdd6f66aSToby Isaac Level: developer 1367bdd6f66aSToby Isaac 1368f6dfbefdSBarry Smith .seealso: `DMPLEX`, `DMPlexComputeJacobianAction()` 1369bdd6f66aSToby Isaac @*/ 1370d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSNESComputeBoundaryFEM(DM dm, Vec X, void *user) 1371d71ae5a4SJacob Faibussowitsch { 1372bdd6f66aSToby Isaac DM plex; 1373bdd6f66aSToby Isaac 1374bdd6f66aSToby Isaac PetscFunctionBegin; 13759566063dSJacob Faibussowitsch PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 13769566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, X, PETSC_MIN_REAL, NULL, NULL, NULL)); 13779566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 13783ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1379bdd6f66aSToby Isaac } 1380bdd6f66aSToby Isaac 13817a73cf09SMatthew G. Knepley /*@ 13828e3a2eefSMatthew G. Knepley DMSNESComputeJacobianAction - Compute the action of the Jacobian J(X) on Y 13837a73cf09SMatthew G. Knepley 13847a73cf09SMatthew G. Knepley Input Parameters: 1385f6dfbefdSBarry Smith + dm - The `DM` 13867a73cf09SMatthew G. Knepley . X - Local solution vector 13877a73cf09SMatthew G. Knepley . Y - Local input vector 13887a73cf09SMatthew G. Knepley - user - The user context 13897a73cf09SMatthew G. Knepley 13907a73cf09SMatthew G. Knepley Output Parameter: 139169d47153SPierre Jolivet . F - local output vector 13927a73cf09SMatthew G. Knepley 13937a73cf09SMatthew G. Knepley Level: developer 13947a73cf09SMatthew G. Knepley 13958e3a2eefSMatthew G. Knepley Notes: 1396f6dfbefdSBarry Smith Users will typically use `DMSNESCreateJacobianMF()` followed by `MatMult()` instead of calling this routine directly. 13978e3a2eefSMatthew G. Knepley 1398f6dfbefdSBarry Smith .seealso: `DM`, ``DMSNESCreateJacobianMF()`, `DMPlexSNESComputeResidualFEM()` 13997a73cf09SMatthew G. Knepley @*/ 1400d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESComputeJacobianAction(DM dm, Vec X, Vec Y, Vec F, void *user) 1401d71ae5a4SJacob Faibussowitsch { 14028e3a2eefSMatthew G. Knepley DM plex; 14038e3a2eefSMatthew G. Knepley IS allcellIS; 14048e3a2eefSMatthew G. Knepley PetscInt Nds, s; 1405a925c78cSMatthew G. Knepley 1406a925c78cSMatthew G. Knepley PetscFunctionBegin; 14079566063dSJacob Faibussowitsch PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 14089566063dSJacob Faibussowitsch PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS)); 14099566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 14108e3a2eefSMatthew G. Knepley for (s = 0; s < Nds; ++s) { 14118e3a2eefSMatthew G. Knepley PetscDS ds; 14128e3a2eefSMatthew G. Knepley DMLabel label; 14138e3a2eefSMatthew G. Knepley IS cellIS; 14147a73cf09SMatthew G. Knepley 141507218a29SMatthew G. Knepley PetscCall(DMGetRegionNumDS(dm, s, &label, NULL, &ds, NULL)); 14168e3a2eefSMatthew G. Knepley { 141706ad1575SMatthew G. Knepley PetscWeakFormKind jacmap[4] = {PETSC_WF_G0, PETSC_WF_G1, PETSC_WF_G2, PETSC_WF_G3}; 14188e3a2eefSMatthew G. Knepley PetscWeakForm wf; 14198e3a2eefSMatthew G. Knepley PetscInt Nm = 4, m, Nk = 0, k, kp, off = 0; 142006ad1575SMatthew G. Knepley PetscFormKey *jackeys; 14218e3a2eefSMatthew G. Knepley 14228e3a2eefSMatthew G. Knepley /* Get unique Jacobian keys */ 14238e3a2eefSMatthew G. Knepley for (m = 0; m < Nm; ++m) { 14248e3a2eefSMatthew G. Knepley PetscInt Nkm; 14259566063dSJacob Faibussowitsch PetscCall(PetscHMapFormGetSize(ds->wf->form[jacmap[m]], &Nkm)); 14268e3a2eefSMatthew G. Knepley Nk += Nkm; 14278e3a2eefSMatthew G. Knepley } 14289566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nk, &jackeys)); 142948a46eb9SPierre Jolivet for (m = 0; m < Nm; ++m) PetscCall(PetscHMapFormGetKeys(ds->wf->form[jacmap[m]], &off, jackeys)); 143063a3b9bcSJacob Faibussowitsch PetscCheck(off == Nk, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %" PetscInt_FMT " should be %" PetscInt_FMT, off, Nk); 14319566063dSJacob Faibussowitsch PetscCall(PetscFormKeySort(Nk, jackeys)); 14328e3a2eefSMatthew G. Knepley for (k = 0, kp = 1; kp < Nk; ++kp) { 14338e3a2eefSMatthew G. Knepley if ((jackeys[k].label != jackeys[kp].label) || (jackeys[k].value != jackeys[kp].value)) { 14348e3a2eefSMatthew G. Knepley ++k; 14358e3a2eefSMatthew G. Knepley if (kp != k) jackeys[k] = jackeys[kp]; 14368e3a2eefSMatthew G. Knepley } 14378e3a2eefSMatthew G. Knepley } 14388e3a2eefSMatthew G. Knepley Nk = k; 14398e3a2eefSMatthew G. Knepley 14409566063dSJacob Faibussowitsch PetscCall(PetscDSGetWeakForm(ds, &wf)); 14418e3a2eefSMatthew G. Knepley for (k = 0; k < Nk; ++k) { 14428e3a2eefSMatthew G. Knepley DMLabel label = jackeys[k].label; 14438e3a2eefSMatthew G. Knepley PetscInt val = jackeys[k].value; 14448e3a2eefSMatthew G. Knepley 14458e3a2eefSMatthew G. Knepley if (!label) { 14469566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)allcellIS)); 14478e3a2eefSMatthew G. Knepley cellIS = allcellIS; 14487a73cf09SMatthew G. Knepley } else { 14498e3a2eefSMatthew G. Knepley IS pointIS; 1450a925c78cSMatthew G. Knepley 14519566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, val, &pointIS)); 14529566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS)); 14539566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 1454a925c78cSMatthew G. Knepley } 14559566063dSJacob Faibussowitsch PetscCall(DMPlexComputeJacobian_Action_Internal(plex, jackeys[k], cellIS, 0.0, 0.0, X, NULL, Y, F, user)); 14569566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 14578e3a2eefSMatthew G. Knepley } 14589566063dSJacob Faibussowitsch PetscCall(PetscFree(jackeys)); 14598e3a2eefSMatthew G. Knepley } 14608e3a2eefSMatthew G. Knepley } 14619566063dSJacob Faibussowitsch PetscCall(ISDestroy(&allcellIS)); 14629566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 14633ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1464a925c78cSMatthew G. Knepley } 1465a925c78cSMatthew G. Knepley 146624cdb843SMatthew G. Knepley /*@ 14672fe279fdSBarry Smith DMPlexSNESComputeJacobianFEM - Form the local portion of the Jacobian matrix `Jac` at the local solution `X` using pointwise functions specified by the user. 146824cdb843SMatthew G. Knepley 146924cdb843SMatthew G. Knepley Input Parameters: 14702fe279fdSBarry Smith + dm - The `DM` 147124cdb843SMatthew G. Knepley . X - Local input vector 147224cdb843SMatthew G. Knepley - user - The user context 147324cdb843SMatthew G. Knepley 14742fe279fdSBarry Smith Output Parameters: 14752fe279fdSBarry Smith + Jac - Jacobian matrix 14762fe279fdSBarry Smith - JacP - approximate Jacobian from which the preconditioner will be built, often `Jac` 14772fe279fdSBarry Smith 14782fe279fdSBarry Smith Level: developer 147924cdb843SMatthew G. Knepley 148024cdb843SMatthew G. Knepley Note: 148124cdb843SMatthew G. Knepley We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator, 148224cdb843SMatthew G. Knepley like a GPU, or vectorize on a multicore machine. 148324cdb843SMatthew G. Knepley 1484f6dfbefdSBarry Smith .seealso: `DMPLEX`, `Mat` 148524cdb843SMatthew G. Knepley @*/ 1486d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSNESComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, void *user) 1487d71ae5a4SJacob Faibussowitsch { 14886da023fcSToby Isaac DM plex; 1489083401c6SMatthew G. Knepley IS allcellIS; 1490f04eb4edSMatthew G. Knepley PetscBool hasJac, hasPrec; 14916528b96dSMatthew G. Knepley PetscInt Nds, s; 149224cdb843SMatthew G. Knepley 149324cdb843SMatthew G. Knepley PetscFunctionBegin; 14949566063dSJacob Faibussowitsch PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 14959566063dSJacob Faibussowitsch PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS)); 14969566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 1497083401c6SMatthew G. Knepley for (s = 0; s < Nds; ++s) { 1498083401c6SMatthew G. Knepley PetscDS ds; 1499083401c6SMatthew G. Knepley IS cellIS; 150006ad1575SMatthew G. Knepley PetscFormKey key; 1501083401c6SMatthew G. Knepley 150207218a29SMatthew G. Knepley PetscCall(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds, NULL)); 15036528b96dSMatthew G. Knepley key.value = 0; 15046528b96dSMatthew G. Knepley key.field = 0; 150506ad1575SMatthew G. Knepley key.part = 0; 15066528b96dSMatthew G. Knepley if (!key.label) { 15079566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)allcellIS)); 1508083401c6SMatthew G. Knepley cellIS = allcellIS; 1509083401c6SMatthew G. Knepley } else { 1510083401c6SMatthew G. Knepley IS pointIS; 1511083401c6SMatthew G. Knepley 15126528b96dSMatthew G. Knepley key.value = 1; 15139566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 15149566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS)); 15159566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 1516083401c6SMatthew G. Knepley } 1517083401c6SMatthew G. Knepley if (!s) { 15189566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(ds, &hasJac)); 15199566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(ds, &hasPrec)); 15209566063dSJacob Faibussowitsch if (hasJac && hasPrec) PetscCall(MatZeroEntries(Jac)); 15219566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(JacP)); 1522083401c6SMatthew G. Knepley } 15239566063dSJacob Faibussowitsch PetscCall(DMPlexComputeJacobian_Internal(plex, key, cellIS, 0.0, 0.0, X, NULL, Jac, JacP, user)); 15249566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 1525083401c6SMatthew G. Knepley } 15269566063dSJacob Faibussowitsch PetscCall(ISDestroy(&allcellIS)); 15279566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 15283ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 152924cdb843SMatthew G. Knepley } 15301878804aSMatthew G. Knepley 15319371c9d4SSatish Balay struct _DMSNESJacobianMFCtx { 15328e3a2eefSMatthew G. Knepley DM dm; 15338e3a2eefSMatthew G. Knepley Vec X; 15348e3a2eefSMatthew G. Knepley void *ctx; 15358e3a2eefSMatthew G. Knepley }; 15368e3a2eefSMatthew G. Knepley 1537d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESJacobianMF_Destroy_Private(Mat A) 1538d71ae5a4SJacob Faibussowitsch { 15398e3a2eefSMatthew G. Knepley struct _DMSNESJacobianMFCtx *ctx; 15408e3a2eefSMatthew G. Knepley 15418e3a2eefSMatthew G. Knepley PetscFunctionBegin; 15429566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &ctx)); 15439566063dSJacob Faibussowitsch PetscCall(MatShellSetContext(A, NULL)); 15449566063dSJacob Faibussowitsch PetscCall(DMDestroy(&ctx->dm)); 15459566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ctx->X)); 15469566063dSJacob Faibussowitsch PetscCall(PetscFree(ctx)); 15473ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15488e3a2eefSMatthew G. Knepley } 15498e3a2eefSMatthew G. Knepley 1550d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESJacobianMF_Mult_Private(Mat A, Vec Y, Vec Z) 1551d71ae5a4SJacob Faibussowitsch { 15528e3a2eefSMatthew G. Knepley struct _DMSNESJacobianMFCtx *ctx; 15538e3a2eefSMatthew G. Knepley 15548e3a2eefSMatthew G. Knepley PetscFunctionBegin; 15559566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &ctx)); 15569566063dSJacob Faibussowitsch PetscCall(DMSNESComputeJacobianAction(ctx->dm, ctx->X, Y, Z, ctx->ctx)); 15573ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 15588e3a2eefSMatthew G. Knepley } 15598e3a2eefSMatthew G. Knepley 15608e3a2eefSMatthew G. Knepley /*@ 1561f6dfbefdSBarry Smith DMSNESCreateJacobianMF - Create a `Mat` which computes the action of the Jacobian matrix-free 15628e3a2eefSMatthew G. Knepley 1563c3339decSBarry Smith Collective 15648e3a2eefSMatthew G. Knepley 15658e3a2eefSMatthew G. Knepley Input Parameters: 1566f6dfbefdSBarry Smith + dm - The `DM` 15678e3a2eefSMatthew G. Knepley . X - The evaluation point for the Jacobian 15682fe279fdSBarry Smith - user - A user context, or `NULL` 15698e3a2eefSMatthew G. Knepley 15708e3a2eefSMatthew G. Knepley Output Parameter: 1571f6dfbefdSBarry Smith . J - The `Mat` 15728e3a2eefSMatthew G. Knepley 15738e3a2eefSMatthew G. Knepley Level: advanced 15748e3a2eefSMatthew G. Knepley 1575f6dfbefdSBarry Smith Note: 15762fe279fdSBarry Smith Vec `X` is kept in `J`, so updating `X` then updates the evaluation point. 15778e3a2eefSMatthew G. Knepley 1578f6dfbefdSBarry Smith .seealso: `DM`, `DMSNESComputeJacobianAction()` 15798e3a2eefSMatthew G. Knepley @*/ 1580d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCreateJacobianMF(DM dm, Vec X, void *user, Mat *J) 1581d71ae5a4SJacob Faibussowitsch { 15828e3a2eefSMatthew G. Knepley struct _DMSNESJacobianMFCtx *ctx; 15838e3a2eefSMatthew G. Knepley PetscInt n, N; 15848e3a2eefSMatthew G. Knepley 15858e3a2eefSMatthew G. Knepley PetscFunctionBegin; 15869566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 15879566063dSJacob Faibussowitsch PetscCall(MatSetType(*J, MATSHELL)); 15889566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(X, &n)); 15899566063dSJacob Faibussowitsch PetscCall(VecGetSize(X, &N)); 15909566063dSJacob Faibussowitsch PetscCall(MatSetSizes(*J, n, n, N, N)); 15919566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)dm)); 15929566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)X)); 15939566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(1, &ctx)); 15948e3a2eefSMatthew G. Knepley ctx->dm = dm; 15958e3a2eefSMatthew G. Knepley ctx->X = X; 15968e3a2eefSMatthew G. Knepley ctx->ctx = user; 15979566063dSJacob Faibussowitsch PetscCall(MatShellSetContext(*J, ctx)); 15989566063dSJacob Faibussowitsch PetscCall(MatShellSetOperation(*J, MATOP_DESTROY, (void (*)(void))DMSNESJacobianMF_Destroy_Private)); 15999566063dSJacob Faibussowitsch PetscCall(MatShellSetOperation(*J, MATOP_MULT, (void (*)(void))DMSNESJacobianMF_Mult_Private)); 16003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 16018e3a2eefSMatthew G. Knepley } 16028e3a2eefSMatthew G. Knepley 160338cfc46eSPierre Jolivet /* 160438cfc46eSPierre Jolivet MatComputeNeumannOverlap - Computes an unassembled (Neumann) local overlapping Mat in nonlinear context. 160538cfc46eSPierre Jolivet 160638cfc46eSPierre Jolivet Input Parameters: 16072fe279fdSBarry Smith + X - `SNES` linearization point 160838cfc46eSPierre Jolivet . ovl - index set of overlapping subdomains 160938cfc46eSPierre Jolivet 161038cfc46eSPierre Jolivet Output Parameter: 161138cfc46eSPierre Jolivet . J - unassembled (Neumann) local matrix 161238cfc46eSPierre Jolivet 161338cfc46eSPierre Jolivet Level: intermediate 161438cfc46eSPierre Jolivet 1615db781477SPatrick Sanan .seealso: `DMCreateNeumannOverlap()`, `MATIS`, `PCHPDDMSetAuxiliaryMat()` 161638cfc46eSPierre Jolivet */ 1617d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatComputeNeumannOverlap_Plex(Mat J, PetscReal t, Vec X, Vec X_t, PetscReal s, IS ovl, void *ctx) 1618d71ae5a4SJacob Faibussowitsch { 161938cfc46eSPierre Jolivet SNES snes; 162038cfc46eSPierre Jolivet Mat pJ; 162138cfc46eSPierre Jolivet DM ovldm, origdm; 162238cfc46eSPierre Jolivet DMSNES sdm; 162338cfc46eSPierre Jolivet PetscErrorCode (*bfun)(DM, Vec, void *); 162438cfc46eSPierre Jolivet PetscErrorCode (*jfun)(DM, Vec, Mat, Mat, void *); 162538cfc46eSPierre Jolivet void *bctx, *jctx; 162638cfc46eSPierre Jolivet 162738cfc46eSPierre Jolivet PetscFunctionBegin; 16289566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Overlap_HPDDM_MATIS", (PetscObject *)&pJ)); 162928b400f6SJacob Faibussowitsch PetscCheck(pJ, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing overlapping Mat"); 16309566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Original_HPDDM", (PetscObject *)&origdm)); 163128b400f6SJacob Faibussowitsch PetscCheck(origdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing original DM"); 16329566063dSJacob Faibussowitsch PetscCall(MatGetDM(pJ, &ovldm)); 16339566063dSJacob Faibussowitsch PetscCall(DMSNESGetBoundaryLocal(origdm, &bfun, &bctx)); 16349566063dSJacob Faibussowitsch PetscCall(DMSNESSetBoundaryLocal(ovldm, bfun, bctx)); 16359566063dSJacob Faibussowitsch PetscCall(DMSNESGetJacobianLocal(origdm, &jfun, &jctx)); 16369566063dSJacob Faibussowitsch PetscCall(DMSNESSetJacobianLocal(ovldm, jfun, jctx)); 16379566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Overlap_HPDDM_SNES", (PetscObject *)&snes)); 163838cfc46eSPierre Jolivet if (!snes) { 16399566063dSJacob Faibussowitsch PetscCall(SNESCreate(PetscObjectComm((PetscObject)ovl), &snes)); 16409566063dSJacob Faibussowitsch PetscCall(SNESSetDM(snes, ovldm)); 16419566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)ovl, "_DM_Overlap_HPDDM_SNES", (PetscObject)snes)); 16429566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)snes)); 164338cfc46eSPierre Jolivet } 16449566063dSJacob Faibussowitsch PetscCall(DMGetDMSNES(ovldm, &sdm)); 16459566063dSJacob Faibussowitsch PetscCall(VecLockReadPush(X)); 1646800f99ffSJeremy L Thompson { 1647800f99ffSJeremy L Thompson void *ctx; 1648800f99ffSJeremy L Thompson PetscErrorCode (*J)(SNES, Vec, Mat, Mat, void *); 1649800f99ffSJeremy L Thompson PetscCall(DMSNESGetJacobian(ovldm, &J, &ctx)); 1650800f99ffSJeremy L Thompson PetscCallBack("SNES callback Jacobian", (*J)(snes, X, pJ, pJ, ctx)); 1651800f99ffSJeremy L Thompson } 16529566063dSJacob Faibussowitsch PetscCall(VecLockReadPop(X)); 165338cfc46eSPierre Jolivet /* this is a no-hop, just in case we decide to change the placeholder for the local Neumann matrix */ 165438cfc46eSPierre Jolivet { 165538cfc46eSPierre Jolivet Mat locpJ; 165638cfc46eSPierre Jolivet 16579566063dSJacob Faibussowitsch PetscCall(MatISGetLocalMat(pJ, &locpJ)); 16589566063dSJacob Faibussowitsch PetscCall(MatCopy(locpJ, J, SAME_NONZERO_PATTERN)); 165938cfc46eSPierre Jolivet } 16603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 166138cfc46eSPierre Jolivet } 166238cfc46eSPierre Jolivet 1663a925c78cSMatthew G. Knepley /*@ 1664f6dfbefdSBarry Smith DMPlexSetSNESLocalFEM - Use `DMPLEX`'s internal FEM routines to compute `SNES` boundary values, residual, and Jacobian. 16659f520fc2SToby Isaac 16669f520fc2SToby Isaac Input Parameters: 1667f6dfbefdSBarry Smith + dm - The `DM` object 1668f6dfbefdSBarry Smith . boundaryctx - the user context that will be passed to pointwise evaluation of boundary values (see `PetscDSAddBoundary()`) 1669f6dfbefdSBarry Smith . residualctx - the user context that will be passed to pointwise evaluation of finite element residual computations (see `PetscDSSetResidual()`) 1670f6dfbefdSBarry Smith - jacobianctx - the user context that will be passed to pointwise evaluation of finite element Jacobian construction (see `PetscDSSetJacobian()`) 16711a244344SSatish Balay 16721a244344SSatish Balay Level: developer 1673f6dfbefdSBarry Smith 1674f6dfbefdSBarry Smith .seealso: `DMPLEX`, `SNES` 16759f520fc2SToby Isaac @*/ 1676d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSNESLocalFEM(DM dm, void *boundaryctx, void *residualctx, void *jacobianctx) 1677d71ae5a4SJacob Faibussowitsch { 16789f520fc2SToby Isaac PetscFunctionBegin; 16799566063dSJacob Faibussowitsch PetscCall(DMSNESSetBoundaryLocal(dm, DMPlexSNESComputeBoundaryFEM, boundaryctx)); 16809566063dSJacob Faibussowitsch PetscCall(DMSNESSetFunctionLocal(dm, DMPlexSNESComputeResidualFEM, residualctx)); 16819566063dSJacob Faibussowitsch PetscCall(DMSNESSetJacobianLocal(dm, DMPlexSNESComputeJacobianFEM, jacobianctx)); 16829566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", MatComputeNeumannOverlap_Plex)); 16833ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 16849f520fc2SToby Isaac } 16859f520fc2SToby Isaac 1686f017bcb6SMatthew G. Knepley /*@C 1687f017bcb6SMatthew G. Knepley DMSNESCheckDiscretization - Check the discretization error of the exact solution 1688f017bcb6SMatthew G. Knepley 1689f017bcb6SMatthew G. Knepley Input Parameters: 1690f6dfbefdSBarry Smith + snes - the `SNES` object 1691f6dfbefdSBarry Smith . dm - the `DM` 1692f2cacb80SMatthew G. Knepley . t - the time 1693f6dfbefdSBarry Smith . u - a `DM` vector 1694f0fc11ceSJed Brown - tol - A tolerance for the check, or -1 to print the results instead 1695f017bcb6SMatthew G. Knepley 16962fe279fdSBarry Smith Output Parameter: 16972fe279fdSBarry Smith . error - An array which holds the discretization error in each field, or `NULL` 16982fe279fdSBarry Smith 16992fe279fdSBarry Smith Level: developer 1700f3c94560SMatthew G. Knepley 1701f6dfbefdSBarry Smith Note: 1702f6dfbefdSBarry Smith The user must call `PetscDSSetExactSolution()` beforehand 17037f96f943SMatthew G. Knepley 1704e4094ef1SJacob Faibussowitsch .seealso: `PetscDSSetExactSolution()`, `DNSNESCheckFromOptions()`, `DMSNESCheckResidual()`, `DMSNESCheckJacobian()` 1705f017bcb6SMatthew G. Knepley @*/ 1706d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckDiscretization(SNES snes, DM dm, PetscReal t, Vec u, PetscReal tol, PetscReal error[]) 1707d71ae5a4SJacob Faibussowitsch { 1708f017bcb6SMatthew G. Knepley PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx); 1709f017bcb6SMatthew G. Knepley void **ectxs; 1710f3c94560SMatthew G. Knepley PetscReal *err; 17117f96f943SMatthew G. Knepley MPI_Comm comm; 17127f96f943SMatthew G. Knepley PetscInt Nf, f; 17131878804aSMatthew G. Knepley 17141878804aSMatthew G. Knepley PetscFunctionBegin; 1715f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 1716f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 1717064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(u, VEC_CLASSID, 4); 17184f572ea9SToby Isaac if (error) PetscAssertPointer(error, 6); 17197f96f943SMatthew G. Knepley 17209566063dSJacob Faibussowitsch PetscCall(DMComputeExactSolution(dm, t, u, NULL)); 17219566063dSJacob Faibussowitsch PetscCall(VecViewFromOptions(u, NULL, "-vec_view")); 17227f96f943SMatthew G. Knepley 17239566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)snes, &comm)); 17249566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 17259566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(Nf, &exacts, Nf, &ectxs, PetscMax(1, Nf), &err)); 17267f96f943SMatthew G. Knepley { 17277f96f943SMatthew G. Knepley PetscInt Nds, s; 17287f96f943SMatthew G. Knepley 17299566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 1730083401c6SMatthew G. Knepley for (s = 0; s < Nds; ++s) { 17317f96f943SMatthew G. Knepley PetscDS ds; 1732083401c6SMatthew G. Knepley DMLabel label; 1733083401c6SMatthew G. Knepley IS fieldIS; 17347f96f943SMatthew G. Knepley const PetscInt *fields; 17357f96f943SMatthew G. Knepley PetscInt dsNf, f; 1736083401c6SMatthew G. Knepley 173707218a29SMatthew G. Knepley PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 17389566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &dsNf)); 17399566063dSJacob Faibussowitsch PetscCall(ISGetIndices(fieldIS, &fields)); 1740083401c6SMatthew G. Knepley for (f = 0; f < dsNf; ++f) { 1741083401c6SMatthew G. Knepley const PetscInt field = fields[f]; 17429566063dSJacob Faibussowitsch PetscCall(PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field])); 1743083401c6SMatthew G. Knepley } 17449566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(fieldIS, &fields)); 1745083401c6SMatthew G. Knepley } 1746083401c6SMatthew G. Knepley } 1747f017bcb6SMatthew G. Knepley if (Nf > 1) { 17489566063dSJacob Faibussowitsch PetscCall(DMComputeL2FieldDiff(dm, t, exacts, ectxs, u, err)); 1749f017bcb6SMatthew G. Knepley if (tol >= 0.0) { 1750ad540459SPierre 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); 1751b878532fSMatthew G. Knepley } else if (error) { 1752b878532fSMatthew G. Knepley for (f = 0; f < Nf; ++f) error[f] = err[f]; 17531878804aSMatthew G. Knepley } else { 17549566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "L_2 Error: [")); 1755f017bcb6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 17569566063dSJacob Faibussowitsch if (f) PetscCall(PetscPrintf(comm, ", ")); 17579566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "%g", (double)err[f])); 17581878804aSMatthew G. Knepley } 17599566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "]\n")); 1760f017bcb6SMatthew G. Knepley } 1761f017bcb6SMatthew G. Knepley } else { 17629566063dSJacob Faibussowitsch PetscCall(DMComputeL2Diff(dm, t, exacts, ectxs, u, &err[0])); 1763f017bcb6SMatthew G. Knepley if (tol >= 0.0) { 176408401ef6SPierre Jolivet PetscCheck(err[0] <= tol, comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g exceeds tolerance %g", (double)err[0], (double)tol); 1765b878532fSMatthew G. Knepley } else if (error) { 1766b878532fSMatthew G. Knepley error[0] = err[0]; 1767f017bcb6SMatthew G. Knepley } else { 17689566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "L_2 Error: %g\n", (double)err[0])); 1769f017bcb6SMatthew G. Knepley } 1770f017bcb6SMatthew G. Knepley } 17719566063dSJacob Faibussowitsch PetscCall(PetscFree3(exacts, ectxs, err)); 17723ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1773f017bcb6SMatthew G. Knepley } 1774f017bcb6SMatthew G. Knepley 1775f017bcb6SMatthew G. Knepley /*@C 1776f017bcb6SMatthew G. Knepley DMSNESCheckResidual - Check the residual of the exact solution 1777f017bcb6SMatthew G. Knepley 1778f017bcb6SMatthew G. Knepley Input Parameters: 1779f6dfbefdSBarry Smith + snes - the `SNES` object 1780f6dfbefdSBarry Smith . dm - the `DM` 1781f6dfbefdSBarry Smith . u - a `DM` vector 1782f0fc11ceSJed Brown - tol - A tolerance for the check, or -1 to print the results instead 1783f017bcb6SMatthew G. Knepley 1784f6dfbefdSBarry Smith Output Parameter: 17852fe279fdSBarry Smith . residual - The residual norm of the exact solution, or `NULL` 1786f3c94560SMatthew G. Knepley 1787f017bcb6SMatthew G. Knepley Level: developer 1788f017bcb6SMatthew G. Knepley 1789db781477SPatrick Sanan .seealso: `DNSNESCheckFromOptions()`, `DMSNESCheckDiscretization()`, `DMSNESCheckJacobian()` 1790f017bcb6SMatthew G. Knepley @*/ 1791d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckResidual(SNES snes, DM dm, Vec u, PetscReal tol, PetscReal *residual) 1792d71ae5a4SJacob Faibussowitsch { 1793f017bcb6SMatthew G. Knepley MPI_Comm comm; 1794f017bcb6SMatthew G. Knepley Vec r; 1795f017bcb6SMatthew G. Knepley PetscReal res; 1796f017bcb6SMatthew G. Knepley 1797f017bcb6SMatthew G. Knepley PetscFunctionBegin; 1798f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 1799f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 1800f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(u, VEC_CLASSID, 3); 18014f572ea9SToby Isaac if (residual) PetscAssertPointer(residual, 5); 18029566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)snes, &comm)); 18039566063dSJacob Faibussowitsch PetscCall(DMComputeExactSolution(dm, 0.0, u, NULL)); 18049566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &r)); 18059566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes, u, r)); 18069566063dSJacob Faibussowitsch PetscCall(VecNorm(r, NORM_2, &res)); 1807f017bcb6SMatthew G. Knepley if (tol >= 0.0) { 180808401ef6SPierre Jolivet PetscCheck(res <= tol, comm, PETSC_ERR_ARG_WRONG, "L_2 Residual %g exceeds tolerance %g", (double)res, (double)tol); 1809b878532fSMatthew G. Knepley } else if (residual) { 1810b878532fSMatthew G. Knepley *residual = res; 1811f017bcb6SMatthew G. Knepley } else { 18129566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "L_2 Residual: %g\n", (double)res)); 181393ec0da9SPierre Jolivet PetscCall(VecFilter(r, 1.0e-10)); 18149566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)r, "Initial Residual")); 18159566063dSJacob Faibussowitsch PetscCall(PetscObjectSetOptionsPrefix((PetscObject)r, "res_")); 18169566063dSJacob Faibussowitsch PetscCall(VecViewFromOptions(r, NULL, "-vec_view")); 1817f017bcb6SMatthew G. Knepley } 18189566063dSJacob Faibussowitsch PetscCall(VecDestroy(&r)); 18193ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1820f017bcb6SMatthew G. Knepley } 1821f017bcb6SMatthew G. Knepley 1822f017bcb6SMatthew G. Knepley /*@C 1823f3c94560SMatthew G. Knepley DMSNESCheckJacobian - Check the Jacobian of the exact solution against the residual using the Taylor Test 1824f017bcb6SMatthew G. Knepley 1825f017bcb6SMatthew G. Knepley Input Parameters: 1826f6dfbefdSBarry Smith + snes - the `SNES` object 1827f6dfbefdSBarry Smith . dm - the `DM` 1828f6dfbefdSBarry Smith . u - a `DM` vector 1829f0fc11ceSJed Brown - tol - A tolerance for the check, or -1 to print the results instead 1830f017bcb6SMatthew G. Knepley 1831f3c94560SMatthew G. Knepley Output Parameters: 18322fe279fdSBarry Smith + isLinear - Flag indicaing that the function looks linear, or `NULL` 18332fe279fdSBarry Smith - convRate - The rate of convergence of the linear model, or `NULL` 1834f3c94560SMatthew G. Knepley 1835f017bcb6SMatthew G. Knepley Level: developer 1836f017bcb6SMatthew G. Knepley 1837db781477SPatrick Sanan .seealso: `DNSNESCheckFromOptions()`, `DMSNESCheckDiscretization()`, `DMSNESCheckResidual()` 1838f017bcb6SMatthew G. Knepley @*/ 1839d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckJacobian(SNES snes, DM dm, Vec u, PetscReal tol, PetscBool *isLinear, PetscReal *convRate) 1840d71ae5a4SJacob Faibussowitsch { 1841f017bcb6SMatthew G. Knepley MPI_Comm comm; 1842f017bcb6SMatthew G. Knepley PetscDS ds; 1843f017bcb6SMatthew G. Knepley Mat J, M; 1844f017bcb6SMatthew G. Knepley MatNullSpace nullspace; 1845f3c94560SMatthew G. Knepley PetscReal slope, intercept; 18467f96f943SMatthew G. Knepley PetscBool hasJac, hasPrec, isLin = PETSC_FALSE; 1847f017bcb6SMatthew G. Knepley 1848f017bcb6SMatthew G. Knepley PetscFunctionBegin; 1849f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 1850f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 1851f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(u, VEC_CLASSID, 3); 18524f572ea9SToby Isaac if (isLinear) PetscAssertPointer(isLinear, 5); 18534f572ea9SToby Isaac if (convRate) PetscAssertPointer(convRate, 6); 18549566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)snes, &comm)); 18559566063dSJacob Faibussowitsch PetscCall(DMComputeExactSolution(dm, 0.0, u, NULL)); 1856f017bcb6SMatthew G. Knepley /* Create and view matrices */ 18579566063dSJacob Faibussowitsch PetscCall(DMCreateMatrix(dm, &J)); 18589566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &ds)); 18599566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(ds, &hasJac)); 18609566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(ds, &hasPrec)); 1861282e7bb4SMatthew G. Knepley if (hasJac && hasPrec) { 18629566063dSJacob Faibussowitsch PetscCall(DMCreateMatrix(dm, &M)); 18639566063dSJacob Faibussowitsch PetscCall(SNESComputeJacobian(snes, u, J, M)); 18649566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)M, "Preconditioning Matrix")); 18659566063dSJacob Faibussowitsch PetscCall(PetscObjectSetOptionsPrefix((PetscObject)M, "jacpre_")); 18669566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(M, NULL, "-mat_view")); 18679566063dSJacob Faibussowitsch PetscCall(MatDestroy(&M)); 1868282e7bb4SMatthew G. Knepley } else { 18699566063dSJacob Faibussowitsch PetscCall(SNESComputeJacobian(snes, u, J, J)); 1870282e7bb4SMatthew G. Knepley } 18719566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)J, "Jacobian")); 18729566063dSJacob Faibussowitsch PetscCall(PetscObjectSetOptionsPrefix((PetscObject)J, "jac_")); 18739566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(J, NULL, "-mat_view")); 1874f017bcb6SMatthew G. Knepley /* Check nullspace */ 18759566063dSJacob Faibussowitsch PetscCall(MatGetNullSpace(J, &nullspace)); 1876f017bcb6SMatthew G. Knepley if (nullspace) { 18771878804aSMatthew G. Knepley PetscBool isNull; 18789566063dSJacob Faibussowitsch PetscCall(MatNullSpaceTest(nullspace, J, &isNull)); 187928b400f6SJacob Faibussowitsch PetscCheck(isNull, comm, PETSC_ERR_PLIB, "The null space calculated for the system operator is invalid."); 18801878804aSMatthew G. Knepley } 1881f017bcb6SMatthew G. Knepley /* Taylor test */ 1882f017bcb6SMatthew G. Knepley { 1883f017bcb6SMatthew G. Knepley PetscRandom rand; 1884f017bcb6SMatthew G. Knepley Vec du, uhat, r, rhat, df; 1885f3c94560SMatthew G. Knepley PetscReal h; 1886f017bcb6SMatthew G. Knepley PetscReal *es, *hs, *errors; 1887f017bcb6SMatthew G. Knepley PetscReal hMax = 1.0, hMin = 1e-6, hMult = 0.1; 1888f017bcb6SMatthew G. Knepley PetscInt Nv, v; 1889f017bcb6SMatthew G. Knepley 1890f017bcb6SMatthew G. Knepley /* Choose a perturbation direction */ 18919566063dSJacob Faibussowitsch PetscCall(PetscRandomCreate(comm, &rand)); 18929566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &du)); 18939566063dSJacob Faibussowitsch PetscCall(VecSetRandom(du, rand)); 18949566063dSJacob Faibussowitsch PetscCall(PetscRandomDestroy(&rand)); 18959566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &df)); 18969566063dSJacob Faibussowitsch PetscCall(MatMult(J, du, df)); 1897f017bcb6SMatthew G. Knepley /* Evaluate residual at u, F(u), save in vector r */ 18989566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &r)); 18999566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes, u, r)); 1900f017bcb6SMatthew G. Knepley /* Look at the convergence of our Taylor approximation as we approach u */ 19019371c9d4SSatish Balay for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv) 19029371c9d4SSatish Balay ; 19039566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(Nv, &es, Nv, &hs, Nv, &errors)); 19049566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &uhat)); 19059566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &rhat)); 1906f017bcb6SMatthew G. Knepley for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv) { 19079566063dSJacob Faibussowitsch PetscCall(VecWAXPY(uhat, h, du, u)); 1908f017bcb6SMatthew G. Knepley /* F(\hat u) \approx F(u) + J(u) (uhat - u) = F(u) + h * J(u) du */ 19099566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes, uhat, rhat)); 19109566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(rhat, -1.0, -h, 1.0, r, df)); 19119566063dSJacob Faibussowitsch PetscCall(VecNorm(rhat, NORM_2, &errors[Nv])); 1912f017bcb6SMatthew G. Knepley 191338d69901SMatthew G. Knepley es[Nv] = errors[Nv] == 0 ? -16.0 : PetscLog10Real(errors[Nv]); 1914f017bcb6SMatthew G. Knepley hs[Nv] = PetscLog10Real(h); 1915f017bcb6SMatthew G. Knepley } 19169566063dSJacob Faibussowitsch PetscCall(VecDestroy(&uhat)); 19179566063dSJacob Faibussowitsch PetscCall(VecDestroy(&rhat)); 19189566063dSJacob Faibussowitsch PetscCall(VecDestroy(&df)); 19199566063dSJacob Faibussowitsch PetscCall(VecDestroy(&r)); 19209566063dSJacob Faibussowitsch PetscCall(VecDestroy(&du)); 1921f017bcb6SMatthew G. Knepley for (v = 0; v < Nv; ++v) { 1922f017bcb6SMatthew G. Knepley if ((tol >= 0) && (errors[v] > tol)) break; 1923f017bcb6SMatthew G. Knepley else if (errors[v] > PETSC_SMALL) break; 1924f017bcb6SMatthew G. Knepley } 1925f3c94560SMatthew G. Knepley if (v == Nv) isLin = PETSC_TRUE; 19269566063dSJacob Faibussowitsch PetscCall(PetscLinearRegression(Nv, hs, es, &slope, &intercept)); 19279566063dSJacob Faibussowitsch PetscCall(PetscFree3(es, hs, errors)); 1928f017bcb6SMatthew G. Knepley /* Slope should be about 2 */ 1929f017bcb6SMatthew G. Knepley if (tol >= 0) { 19300b121fc5SBarry Smith PetscCheck(isLin || PetscAbsReal(2 - slope) <= tol, comm, PETSC_ERR_ARG_WRONG, "Taylor approximation convergence rate should be 2, not %0.2f", (double)slope); 1931b878532fSMatthew G. Knepley } else if (isLinear || convRate) { 1932b878532fSMatthew G. Knepley if (isLinear) *isLinear = isLin; 1933b878532fSMatthew G. Knepley if (convRate) *convRate = slope; 1934f017bcb6SMatthew G. Knepley } else { 19359566063dSJacob Faibussowitsch if (!isLin) PetscCall(PetscPrintf(comm, "Taylor approximation converging at order %3.2f\n", (double)slope)); 19369566063dSJacob Faibussowitsch else PetscCall(PetscPrintf(comm, "Function appears to be linear\n")); 1937f017bcb6SMatthew G. Knepley } 1938f017bcb6SMatthew G. Knepley } 19399566063dSJacob Faibussowitsch PetscCall(MatDestroy(&J)); 19403ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 19411878804aSMatthew G. Knepley } 19421878804aSMatthew G. Knepley 1943d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheck_Internal(SNES snes, DM dm, Vec u) 1944d71ae5a4SJacob Faibussowitsch { 1945f017bcb6SMatthew G. Knepley PetscFunctionBegin; 19469566063dSJacob Faibussowitsch PetscCall(DMSNESCheckDiscretization(snes, dm, 0.0, u, -1.0, NULL)); 19479566063dSJacob Faibussowitsch PetscCall(DMSNESCheckResidual(snes, dm, u, -1.0, NULL)); 19489566063dSJacob Faibussowitsch PetscCall(DMSNESCheckJacobian(snes, dm, u, -1.0, NULL, NULL)); 19493ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1950f017bcb6SMatthew G. Knepley } 1951f017bcb6SMatthew G. Knepley 1952bee9a294SMatthew G. Knepley /*@C 1953bee9a294SMatthew G. Knepley DMSNESCheckFromOptions - Check the residual and Jacobian functions using the exact solution by outputting some diagnostic information 1954bee9a294SMatthew G. Knepley 1955bee9a294SMatthew G. Knepley Input Parameters: 1956f6dfbefdSBarry Smith + snes - the `SNES` object 1957f6dfbefdSBarry Smith - u - representative `SNES` vector 19587f96f943SMatthew G. Knepley 19592fe279fdSBarry Smith Level: developer 19602fe279fdSBarry Smith 1961f6dfbefdSBarry Smith Note: 1962f6dfbefdSBarry Smith The user must call `PetscDSSetExactSolution()` beforehand 1963bee9a294SMatthew G. Knepley 19642fe279fdSBarry Smith .seealso: `SNES`, `DM` 1965bee9a294SMatthew G. Knepley @*/ 1966d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckFromOptions(SNES snes, Vec u) 1967d71ae5a4SJacob Faibussowitsch { 19681878804aSMatthew G. Knepley DM dm; 19691878804aSMatthew G. Knepley Vec sol; 19701878804aSMatthew G. Knepley PetscBool check; 19711878804aSMatthew G. Knepley 19721878804aSMatthew G. Knepley PetscFunctionBegin; 19739566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-dmsnes_check", &check)); 19743ba16761SJacob Faibussowitsch if (!check) PetscFunctionReturn(PETSC_SUCCESS); 19759566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &dm)); 19769566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &sol)); 19779566063dSJacob Faibussowitsch PetscCall(SNESSetSolution(snes, sol)); 19789566063dSJacob Faibussowitsch PetscCall(DMSNESCheck_Internal(snes, dm, sol)); 19799566063dSJacob Faibussowitsch PetscCall(VecDestroy(&sol)); 19803ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 1981552f7358SJed Brown } 1982