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 /* 13649ef022SMatthew Knepley SNESCorrectDiscretePressure_Private - Add a vector in the nullspace to make the continuum integral of the pressure field equal to zero. This is normally used only to evaluate convergence rates for the pressure accurately. 14649ef022SMatthew Knepley 15*c3339decSBarry Smith Collective 16649ef022SMatthew Knepley 17649ef022SMatthew Knepley Input Parameters: 18649ef022SMatthew Knepley + snes - The SNES 19649ef022SMatthew Knepley . pfield - The field number for pressure 20649ef022SMatthew Knepley . nullspace - The pressure nullspace 21649ef022SMatthew Knepley . u - The solution vector 22649ef022SMatthew Knepley - ctx - An optional user context 23649ef022SMatthew Knepley 24649ef022SMatthew Knepley Output Parameter: 25649ef022SMatthew Knepley . u - The solution with a continuum pressure integral of zero 26649ef022SMatthew Knepley 27649ef022SMatthew Knepley Notes: 28649ef022SMatthew 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. 29649ef022SMatthew Knepley 30649ef022SMatthew Knepley Level: developer 31649ef022SMatthew Knepley 32db781477SPatrick Sanan .seealso: `SNESConvergedCorrectPressure()` 33649ef022SMatthew Knepley */ 34d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESCorrectDiscretePressure_Private(SNES snes, PetscInt pfield, MatNullSpace nullspace, Vec u, void *ctx) 35d71ae5a4SJacob Faibussowitsch { 36649ef022SMatthew Knepley DM dm; 37649ef022SMatthew Knepley PetscDS ds; 38649ef022SMatthew Knepley const Vec *nullvecs; 39649ef022SMatthew Knepley PetscScalar pintd, *intc, *intn; 40649ef022SMatthew Knepley MPI_Comm comm; 41649ef022SMatthew Knepley PetscInt Nf, Nv; 42649ef022SMatthew Knepley 43649ef022SMatthew Knepley PetscFunctionBegin; 449566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)snes, &comm)); 459566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &dm)); 4628b400f6SJacob Faibussowitsch PetscCheck(dm, comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a SNES DM"); 4728b400f6SJacob Faibussowitsch PetscCheck(nullspace, comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a Jacobian nullspace"); 489566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &ds)); 499566063dSJacob Faibussowitsch PetscCall(PetscDSSetObjective(ds, pfield, pressure_Private)); 509566063dSJacob Faibussowitsch PetscCall(MatNullSpaceGetVecs(nullspace, NULL, &Nv, &nullvecs)); 5163a3b9bcSJacob Faibussowitsch PetscCheck(Nv == 1, comm, PETSC_ERR_ARG_OUTOFRANGE, "Can only handle a single null vector for pressure, not %" PetscInt_FMT, Nv); 529566063dSJacob Faibussowitsch PetscCall(VecDot(nullvecs[0], u, &pintd)); 5308401ef6SPierre Jolivet PetscCheck(PetscAbsScalar(pintd) <= PETSC_SMALL, comm, PETSC_ERR_ARG_WRONG, "Discrete integral of pressure: %g", (double)PetscRealPart(pintd)); 549566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 559566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(Nf, &intc, Nf, &intn)); 569566063dSJacob Faibussowitsch PetscCall(DMPlexComputeIntegralFEM(dm, nullvecs[0], intn, ctx)); 579566063dSJacob Faibussowitsch PetscCall(DMPlexComputeIntegralFEM(dm, u, intc, ctx)); 589566063dSJacob Faibussowitsch PetscCall(VecAXPY(u, -intc[pfield] / intn[pfield], nullvecs[0])); 59649ef022SMatthew Knepley #if defined(PETSC_USE_DEBUG) 609566063dSJacob Faibussowitsch PetscCall(DMPlexComputeIntegralFEM(dm, u, intc, ctx)); 6108401ef6SPierre Jolivet PetscCheck(PetscAbsScalar(intc[pfield]) <= PETSC_SMALL, comm, PETSC_ERR_ARG_WRONG, "Continuum integral of pressure after correction: %g", (double)PetscRealPart(intc[pfield])); 62649ef022SMatthew Knepley #endif 639566063dSJacob Faibussowitsch PetscCall(PetscFree2(intc, intn)); 64649ef022SMatthew Knepley PetscFunctionReturn(0); 65649ef022SMatthew Knepley } 66649ef022SMatthew Knepley 67649ef022SMatthew Knepley /*@C 68f6dfbefdSBarry Smith SNESConvergedCorrectPressure - Convergence test that adds a vector in the nullspace to make the continuum integral of the pressure field equal to zero. 69f6dfbefdSBarry Smith This is normally used only to evaluate convergence rates for the pressure accurately. The convergence test itself just mimics `SNESConvergedDefault()`. 70649ef022SMatthew Knepley 71*c3339decSBarry Smith Logically Collective 72649ef022SMatthew Knepley 73649ef022SMatthew Knepley Input Parameters: 74f6dfbefdSBarry Smith + snes - the `SNES` context 75649ef022SMatthew Knepley . it - the iteration (0 indicates before any Newton steps) 76649ef022SMatthew Knepley . xnorm - 2-norm of current iterate 77649ef022SMatthew Knepley . snorm - 2-norm of current step 78649ef022SMatthew Knepley . fnorm - 2-norm of function at current iterate 79649ef022SMatthew Knepley - ctx - Optional user context 80649ef022SMatthew Knepley 81649ef022SMatthew Knepley Output Parameter: 82f6dfbefdSBarry Smith . reason - `SNES_CONVERGED_ITERATING`, `SNES_CONVERGED_ITS`, or `SNES_DIVERGED_FNORM_NAN` 83649ef022SMatthew Knepley 84649ef022SMatthew Knepley Notes: 85f6dfbefdSBarry 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` 86f6dfbefdSBarry Smith must be created with discretizations of those fields. We currently assume that the pressure field has index 1. 87f6dfbefdSBarry Smith The pressure field must have a nullspace, likely created using the `DMSetNullSpaceConstructor()` interface. 88f6dfbefdSBarry 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. 89f362779dSJed Brown 90f6dfbefdSBarry Smith Options Database Key: 91f6dfbefdSBarry Smith . -snes_convergence_test correct_pressure - see `SNESSetFromOptions()` 92649ef022SMatthew Knepley 93649ef022SMatthew Knepley Level: advanced 94649ef022SMatthew Knepley 95f6dfbefdSBarry Smith .seealso: `SNES`, `DM`, `SNESConvergedDefault()`, `SNESSetConvergenceTest()`, `DMSetNullSpaceConstructor()`, `DMSetNullSpaceConstructor()` 96649ef022SMatthew Knepley @*/ 97d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESConvergedCorrectPressure(SNES snes, PetscInt it, PetscReal xnorm, PetscReal gnorm, PetscReal f, SNESConvergedReason *reason, void *ctx) 98d71ae5a4SJacob Faibussowitsch { 99649ef022SMatthew Knepley PetscBool monitorIntegral = PETSC_FALSE; 100649ef022SMatthew Knepley 101649ef022SMatthew Knepley PetscFunctionBegin; 1029566063dSJacob Faibussowitsch PetscCall(SNESConvergedDefault(snes, it, xnorm, gnorm, f, reason, ctx)); 103649ef022SMatthew Knepley if (monitorIntegral) { 104649ef022SMatthew Knepley Mat J; 105649ef022SMatthew Knepley Vec u; 106649ef022SMatthew Knepley MatNullSpace nullspace; 107649ef022SMatthew Knepley const Vec *nullvecs; 108649ef022SMatthew Knepley PetscScalar pintd; 109649ef022SMatthew Knepley 1109566063dSJacob Faibussowitsch PetscCall(SNESGetSolution(snes, &u)); 1119566063dSJacob Faibussowitsch PetscCall(SNESGetJacobian(snes, &J, NULL, NULL, NULL)); 1129566063dSJacob Faibussowitsch PetscCall(MatGetNullSpace(J, &nullspace)); 1139566063dSJacob Faibussowitsch PetscCall(MatNullSpaceGetVecs(nullspace, NULL, NULL, &nullvecs)); 1149566063dSJacob Faibussowitsch PetscCall(VecDot(nullvecs[0], u, &pintd)); 1159566063dSJacob Faibussowitsch PetscCall(PetscInfo(snes, "SNES: Discrete integral of pressure: %g\n", (double)PetscRealPart(pintd))); 116649ef022SMatthew Knepley } 117649ef022SMatthew Knepley if (*reason > 0) { 118649ef022SMatthew Knepley Mat J; 119649ef022SMatthew Knepley Vec u; 120649ef022SMatthew Knepley MatNullSpace nullspace; 121649ef022SMatthew Knepley PetscInt pfield = 1; 122649ef022SMatthew Knepley 1239566063dSJacob Faibussowitsch PetscCall(SNESGetSolution(snes, &u)); 1249566063dSJacob Faibussowitsch PetscCall(SNESGetJacobian(snes, &J, NULL, NULL, NULL)); 1259566063dSJacob Faibussowitsch PetscCall(MatGetNullSpace(J, &nullspace)); 1269566063dSJacob Faibussowitsch PetscCall(SNESCorrectDiscretePressure_Private(snes, pfield, nullspace, u, ctx)); 127649ef022SMatthew Knepley } 128649ef022SMatthew Knepley PetscFunctionReturn(0); 129649ef022SMatthew Knepley } 130649ef022SMatthew Knepley 13124cdb843SMatthew G. Knepley /************************** Interpolation *******************************/ 13224cdb843SMatthew G. Knepley 133d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESConvertPlex(DM dm, DM *plex, PetscBool copy) 134d71ae5a4SJacob Faibussowitsch { 1356da023fcSToby Isaac PetscBool isPlex; 1366da023fcSToby Isaac 1376da023fcSToby Isaac PetscFunctionBegin; 1389566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 1396da023fcSToby Isaac if (isPlex) { 1406da023fcSToby Isaac *plex = dm; 1419566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)dm)); 142f7148743SMatthew G. Knepley } else { 1439566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex)); 144f7148743SMatthew G. Knepley if (!*plex) { 1459566063dSJacob Faibussowitsch PetscCall(DMConvert(dm, DMPLEX, plex)); 1469566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex)); 1476da023fcSToby Isaac if (copy) { 1489566063dSJacob Faibussowitsch PetscCall(DMCopyDMSNES(dm, *plex)); 1499566063dSJacob Faibussowitsch PetscCall(DMCopyAuxiliaryVec(dm, *plex)); 1506da023fcSToby Isaac } 151f7148743SMatthew G. Knepley } else { 1529566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)*plex)); 153f7148743SMatthew G. Knepley } 1546da023fcSToby Isaac } 1556da023fcSToby Isaac PetscFunctionReturn(0); 1566da023fcSToby Isaac } 1576da023fcSToby Isaac 1584267b1a3SMatthew G. Knepley /*@C 159f6dfbefdSBarry Smith DMInterpolationCreate - Creates a `DMInterpolationInfo` context 1604267b1a3SMatthew G. Knepley 161d083f849SBarry Smith Collective 1624267b1a3SMatthew G. Knepley 1634267b1a3SMatthew G. Knepley Input Parameter: 1644267b1a3SMatthew G. Knepley . comm - the communicator 1654267b1a3SMatthew G. Knepley 1664267b1a3SMatthew G. Knepley Output Parameter: 1674267b1a3SMatthew G. Knepley . ctx - the context 1684267b1a3SMatthew G. Knepley 1694267b1a3SMatthew G. Knepley Level: beginner 1704267b1a3SMatthew G. Knepley 171f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationDestroy()` 1724267b1a3SMatthew G. Knepley @*/ 173d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationCreate(MPI_Comm comm, DMInterpolationInfo *ctx) 174d71ae5a4SJacob Faibussowitsch { 175552f7358SJed Brown PetscFunctionBegin; 176552f7358SJed Brown PetscValidPointer(ctx, 2); 1779566063dSJacob Faibussowitsch PetscCall(PetscNew(ctx)); 1781aa26658SKarl Rupp 179552f7358SJed Brown (*ctx)->comm = comm; 180552f7358SJed Brown (*ctx)->dim = -1; 181552f7358SJed Brown (*ctx)->nInput = 0; 1820298fd71SBarry Smith (*ctx)->points = NULL; 1830298fd71SBarry Smith (*ctx)->cells = NULL; 184552f7358SJed Brown (*ctx)->n = -1; 1850298fd71SBarry Smith (*ctx)->coords = NULL; 186552f7358SJed Brown PetscFunctionReturn(0); 187552f7358SJed Brown } 188552f7358SJed Brown 1894267b1a3SMatthew G. Knepley /*@C 1904267b1a3SMatthew G. Knepley DMInterpolationSetDim - Sets the spatial dimension for the interpolation context 1914267b1a3SMatthew G. Knepley 1924267b1a3SMatthew G. Knepley Not collective 1934267b1a3SMatthew G. Knepley 1944267b1a3SMatthew G. Knepley Input Parameters: 1954267b1a3SMatthew G. Knepley + ctx - the context 1964267b1a3SMatthew G. Knepley - dim - the spatial dimension 1974267b1a3SMatthew G. Knepley 1984267b1a3SMatthew G. Knepley Level: intermediate 1994267b1a3SMatthew G. Knepley 200f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()` 2014267b1a3SMatthew G. Knepley @*/ 202d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationSetDim(DMInterpolationInfo ctx, PetscInt dim) 203d71ae5a4SJacob Faibussowitsch { 204552f7358SJed Brown PetscFunctionBegin; 20563a3b9bcSJacob Faibussowitsch PetscCheck(!(dim < 1) && !(dim > 3), ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension for points: %" PetscInt_FMT, dim); 206552f7358SJed Brown ctx->dim = dim; 207552f7358SJed Brown PetscFunctionReturn(0); 208552f7358SJed Brown } 209552f7358SJed Brown 2104267b1a3SMatthew G. Knepley /*@C 2114267b1a3SMatthew G. Knepley DMInterpolationGetDim - Gets the spatial dimension for the interpolation context 2124267b1a3SMatthew G. Knepley 2134267b1a3SMatthew G. Knepley Not collective 2144267b1a3SMatthew G. Knepley 2154267b1a3SMatthew G. Knepley Input Parameter: 2164267b1a3SMatthew G. Knepley . ctx - the context 2174267b1a3SMatthew G. Knepley 2184267b1a3SMatthew G. Knepley Output Parameter: 2194267b1a3SMatthew G. Knepley . dim - the spatial dimension 2204267b1a3SMatthew G. Knepley 2214267b1a3SMatthew G. Knepley Level: intermediate 2224267b1a3SMatthew G. Knepley 223f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationSetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()` 2244267b1a3SMatthew G. Knepley @*/ 225d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetDim(DMInterpolationInfo ctx, PetscInt *dim) 226d71ae5a4SJacob Faibussowitsch { 227552f7358SJed Brown PetscFunctionBegin; 228552f7358SJed Brown PetscValidIntPointer(dim, 2); 229552f7358SJed Brown *dim = ctx->dim; 230552f7358SJed Brown PetscFunctionReturn(0); 231552f7358SJed Brown } 232552f7358SJed Brown 2334267b1a3SMatthew G. Knepley /*@C 2344267b1a3SMatthew G. Knepley DMInterpolationSetDof - Sets the number of fields interpolated at a point for the interpolation context 2354267b1a3SMatthew G. Knepley 2364267b1a3SMatthew G. Knepley Not collective 2374267b1a3SMatthew G. Knepley 2384267b1a3SMatthew G. Knepley Input Parameters: 2394267b1a3SMatthew G. Knepley + ctx - the context 2404267b1a3SMatthew G. Knepley - dof - the number of fields 2414267b1a3SMatthew G. Knepley 2424267b1a3SMatthew G. Knepley Level: intermediate 2434267b1a3SMatthew G. Knepley 244f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetDof()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()` 2454267b1a3SMatthew G. Knepley @*/ 246d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationSetDof(DMInterpolationInfo ctx, PetscInt dof) 247d71ae5a4SJacob Faibussowitsch { 248552f7358SJed Brown PetscFunctionBegin; 24963a3b9bcSJacob Faibussowitsch PetscCheck(dof >= 1, ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of components: %" PetscInt_FMT, dof); 250552f7358SJed Brown ctx->dof = dof; 251552f7358SJed Brown PetscFunctionReturn(0); 252552f7358SJed Brown } 253552f7358SJed Brown 2544267b1a3SMatthew G. Knepley /*@C 2554267b1a3SMatthew G. Knepley DMInterpolationGetDof - Gets the number of fields interpolated at a point for the interpolation context 2564267b1a3SMatthew G. Knepley 2574267b1a3SMatthew G. Knepley Not collective 2584267b1a3SMatthew G. Knepley 2594267b1a3SMatthew G. Knepley Input Parameter: 2604267b1a3SMatthew G. Knepley . ctx - the context 2614267b1a3SMatthew G. Knepley 2624267b1a3SMatthew G. Knepley Output Parameter: 2634267b1a3SMatthew G. Knepley . dof - the number of fields 2644267b1a3SMatthew G. Knepley 2654267b1a3SMatthew G. Knepley Level: intermediate 2664267b1a3SMatthew G. Knepley 267f6dfbefdSBarry Smith .seealso: DMInterpolationInfo, `DMInterpolationSetDof()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()` 2684267b1a3SMatthew G. Knepley @*/ 269d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetDof(DMInterpolationInfo ctx, PetscInt *dof) 270d71ae5a4SJacob Faibussowitsch { 271552f7358SJed Brown PetscFunctionBegin; 272552f7358SJed Brown PetscValidIntPointer(dof, 2); 273552f7358SJed Brown *dof = ctx->dof; 274552f7358SJed Brown PetscFunctionReturn(0); 275552f7358SJed Brown } 276552f7358SJed Brown 2774267b1a3SMatthew G. Knepley /*@C 2784267b1a3SMatthew G. Knepley DMInterpolationAddPoints - Add points at which we will interpolate the fields 2794267b1a3SMatthew G. Knepley 2804267b1a3SMatthew G. Knepley Not collective 2814267b1a3SMatthew G. Knepley 2824267b1a3SMatthew G. Knepley Input Parameters: 2834267b1a3SMatthew G. Knepley + ctx - the context 2844267b1a3SMatthew G. Knepley . n - the number of points 2854267b1a3SMatthew G. Knepley - points - the coordinates for each point, an array of size n * dim 2864267b1a3SMatthew G. Knepley 287f6dfbefdSBarry Smith Note: 288f6dfbefdSBarry Smith The coordinate information is copied. 2894267b1a3SMatthew G. Knepley 2904267b1a3SMatthew G. Knepley Level: intermediate 2914267b1a3SMatthew G. Knepley 292f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationSetDim()`, `DMInterpolationEvaluate()`, `DMInterpolationCreate()` 2934267b1a3SMatthew G. Knepley @*/ 294d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationAddPoints(DMInterpolationInfo ctx, PetscInt n, PetscReal points[]) 295d71ae5a4SJacob Faibussowitsch { 296552f7358SJed Brown PetscFunctionBegin; 29708401ef6SPierre Jolivet PetscCheck(ctx->dim >= 0, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set"); 29828b400f6SJacob Faibussowitsch PetscCheck(!ctx->points, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot add points multiple times yet"); 299552f7358SJed Brown ctx->nInput = n; 3001aa26658SKarl Rupp 3019566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n * ctx->dim, &ctx->points)); 3029566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(ctx->points, points, n * ctx->dim)); 303552f7358SJed Brown PetscFunctionReturn(0); 304552f7358SJed Brown } 305552f7358SJed Brown 3064267b1a3SMatthew G. Knepley /*@C 30752aa1562SMatthew G. Knepley DMInterpolationSetUp - Compute spatial indices for point location during interpolation 3084267b1a3SMatthew G. Knepley 309*c3339decSBarry Smith Collective 3104267b1a3SMatthew G. Knepley 3114267b1a3SMatthew G. Knepley Input Parameters: 3124267b1a3SMatthew G. Knepley + ctx - the context 313f6dfbefdSBarry Smith . dm - the `DM` for the function space used for interpolation 314f6dfbefdSBarry Smith . redundantPoints - If `PETSC_TRUE`, all processes are passing in the same array of points. Otherwise, points need to be communicated among processes. 315f6dfbefdSBarry Smith - ignoreOutsideDomain - If `PETSC_TRUE`, ignore points outside the domain, otherwise return an error 3164267b1a3SMatthew G. Knepley 3174267b1a3SMatthew G. Knepley Level: intermediate 3184267b1a3SMatthew G. Knepley 319f6dfbefdSBarry Smith .seealso: DMInterpolationInfo, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 3204267b1a3SMatthew G. Knepley @*/ 321d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationSetUp(DMInterpolationInfo ctx, DM dm, PetscBool redundantPoints, PetscBool ignoreOutsideDomain) 322d71ae5a4SJacob Faibussowitsch { 323552f7358SJed Brown MPI_Comm comm = ctx->comm; 324552f7358SJed Brown PetscScalar *a; 325552f7358SJed Brown PetscInt p, q, i; 326552f7358SJed Brown PetscMPIInt rank, size; 327552f7358SJed Brown Vec pointVec; 3283a93e3b7SToby Isaac PetscSF cellSF; 329552f7358SJed Brown PetscLayout layout; 330552f7358SJed Brown PetscReal *globalPoints; 331cb313848SJed Brown PetscScalar *globalPointsScalar; 332552f7358SJed Brown const PetscInt *ranges; 333552f7358SJed Brown PetscMPIInt *counts, *displs; 3343a93e3b7SToby Isaac const PetscSFNode *foundCells; 3353a93e3b7SToby Isaac const PetscInt *foundPoints; 336552f7358SJed Brown PetscMPIInt *foundProcs, *globalProcs; 3373a93e3b7SToby Isaac PetscInt n, N, numFound; 338552f7358SJed Brown 33919436ca2SJed Brown PetscFunctionBegin; 340064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 3419566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(comm, &size)); 3429566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_rank(comm, &rank)); 34308401ef6SPierre Jolivet PetscCheck(ctx->dim >= 0, comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set"); 34419436ca2SJed Brown /* Locate points */ 34519436ca2SJed Brown n = ctx->nInput; 346552f7358SJed Brown if (!redundantPoints) { 3479566063dSJacob Faibussowitsch PetscCall(PetscLayoutCreate(comm, &layout)); 3489566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetBlockSize(layout, 1)); 3499566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetLocalSize(layout, n)); 3509566063dSJacob Faibussowitsch PetscCall(PetscLayoutSetUp(layout)); 3519566063dSJacob Faibussowitsch PetscCall(PetscLayoutGetSize(layout, &N)); 352552f7358SJed Brown /* Communicate all points to all processes */ 3539566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(N * ctx->dim, &globalPoints, size, &counts, size, &displs)); 3549566063dSJacob Faibussowitsch PetscCall(PetscLayoutGetRanges(layout, &ranges)); 355552f7358SJed Brown for (p = 0; p < size; ++p) { 356552f7358SJed Brown counts[p] = (ranges[p + 1] - ranges[p]) * ctx->dim; 357552f7358SJed Brown displs[p] = ranges[p] * ctx->dim; 358552f7358SJed Brown } 3599566063dSJacob Faibussowitsch PetscCallMPI(MPI_Allgatherv(ctx->points, n * ctx->dim, MPIU_REAL, globalPoints, counts, displs, MPIU_REAL, comm)); 360552f7358SJed Brown } else { 361552f7358SJed Brown N = n; 362552f7358SJed Brown globalPoints = ctx->points; 36338ea73c8SJed Brown counts = displs = NULL; 36438ea73c8SJed Brown layout = NULL; 365552f7358SJed Brown } 366552f7358SJed Brown #if 0 3679566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(N,&foundCells,N,&foundProcs,N,&globalProcs)); 36819436ca2SJed Brown /* foundCells[p] = m->locatePoint(&globalPoints[p*ctx->dim]); */ 369552f7358SJed Brown #else 370cb313848SJed Brown #if defined(PETSC_USE_COMPLEX) 3719566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(N * ctx->dim, &globalPointsScalar)); 37246b3086cSToby Isaac for (i = 0; i < N * ctx->dim; i++) globalPointsScalar[i] = globalPoints[i]; 373cb313848SJed Brown #else 374cb313848SJed Brown globalPointsScalar = globalPoints; 375cb313848SJed Brown #endif 3769566063dSJacob Faibussowitsch PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, ctx->dim, N * ctx->dim, globalPointsScalar, &pointVec)); 3779566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(N, &foundProcs, N, &globalProcs)); 378ad540459SPierre Jolivet for (p = 0; p < N; ++p) foundProcs[p] = size; 3793a93e3b7SToby Isaac cellSF = NULL; 3809566063dSJacob Faibussowitsch PetscCall(DMLocatePoints(dm, pointVec, DM_POINTLOCATION_REMOVE, &cellSF)); 3819566063dSJacob Faibussowitsch PetscCall(PetscSFGetGraph(cellSF, NULL, &numFound, &foundPoints, &foundCells)); 382552f7358SJed Brown #endif 3833a93e3b7SToby Isaac for (p = 0; p < numFound; ++p) { 3843a93e3b7SToby Isaac if (foundCells[p].index >= 0) foundProcs[foundPoints ? foundPoints[p] : p] = rank; 385552f7358SJed Brown } 386552f7358SJed Brown /* Let the lowest rank process own each point */ 3871c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(foundProcs, globalProcs, N, MPI_INT, MPI_MIN, comm)); 388552f7358SJed Brown ctx->n = 0; 389552f7358SJed Brown for (p = 0; p < N; ++p) { 39052aa1562SMatthew G. Knepley if (globalProcs[p] == size) { 3919371c9d4SSatish 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), 3929371c9d4SSatish Balay (double)(ctx->dim > 2 ? globalPoints[p * ctx->dim + 2] : 0.0)); 393f7d195e4SLawrence Mitchell if (rank == 0) ++ctx->n; 39452aa1562SMatthew G. Knepley } else if (globalProcs[p] == rank) ++ctx->n; 395552f7358SJed Brown } 396552f7358SJed Brown /* Create coordinates vector and array of owned cells */ 3979566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(ctx->n, &ctx->cells)); 3989566063dSJacob Faibussowitsch PetscCall(VecCreate(comm, &ctx->coords)); 3999566063dSJacob Faibussowitsch PetscCall(VecSetSizes(ctx->coords, ctx->n * ctx->dim, PETSC_DECIDE)); 4009566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(ctx->coords, ctx->dim)); 4019566063dSJacob Faibussowitsch PetscCall(VecSetType(ctx->coords, VECSTANDARD)); 4029566063dSJacob Faibussowitsch PetscCall(VecGetArray(ctx->coords, &a)); 403552f7358SJed Brown for (p = 0, q = 0, i = 0; p < N; ++p) { 404552f7358SJed Brown if (globalProcs[p] == rank) { 405552f7358SJed Brown PetscInt d; 406552f7358SJed Brown 4071aa26658SKarl Rupp for (d = 0; d < ctx->dim; ++d, ++i) a[i] = globalPoints[p * ctx->dim + d]; 408f317b747SMatthew G. Knepley ctx->cells[q] = foundCells[q].index; 409f317b747SMatthew G. Knepley ++q; 410552f7358SJed Brown } 411dd400576SPatrick Sanan if (globalProcs[p] == size && rank == 0) { 41252aa1562SMatthew G. Knepley PetscInt d; 41352aa1562SMatthew G. Knepley 41452aa1562SMatthew G. Knepley for (d = 0; d < ctx->dim; ++d, ++i) a[i] = 0.; 41552aa1562SMatthew G. Knepley ctx->cells[q] = -1; 41652aa1562SMatthew G. Knepley ++q; 41752aa1562SMatthew G. Knepley } 418552f7358SJed Brown } 4199566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(ctx->coords, &a)); 420552f7358SJed Brown #if 0 4219566063dSJacob Faibussowitsch PetscCall(PetscFree3(foundCells,foundProcs,globalProcs)); 422552f7358SJed Brown #else 4239566063dSJacob Faibussowitsch PetscCall(PetscFree2(foundProcs, globalProcs)); 4249566063dSJacob Faibussowitsch PetscCall(PetscSFDestroy(&cellSF)); 4259566063dSJacob Faibussowitsch PetscCall(VecDestroy(&pointVec)); 426552f7358SJed Brown #endif 4279566063dSJacob Faibussowitsch if ((void *)globalPointsScalar != (void *)globalPoints) PetscCall(PetscFree(globalPointsScalar)); 4289566063dSJacob Faibussowitsch if (!redundantPoints) PetscCall(PetscFree3(globalPoints, counts, displs)); 4299566063dSJacob Faibussowitsch PetscCall(PetscLayoutDestroy(&layout)); 430552f7358SJed Brown PetscFunctionReturn(0); 431552f7358SJed Brown } 432552f7358SJed Brown 4334267b1a3SMatthew G. Knepley /*@C 434f6dfbefdSBarry Smith DMInterpolationGetCoordinates - Gets a `Vec` with the coordinates of each interpolation point 4354267b1a3SMatthew G. Knepley 436*c3339decSBarry Smith Collective 4374267b1a3SMatthew G. Knepley 4384267b1a3SMatthew G. Knepley Input Parameter: 4394267b1a3SMatthew G. Knepley . ctx - the context 4404267b1a3SMatthew G. Knepley 4414267b1a3SMatthew G. Knepley Output Parameter: 4424267b1a3SMatthew G. Knepley . coordinates - the coordinates of interpolation points 4434267b1a3SMatthew G. Knepley 444f6dfbefdSBarry Smith Note: 445f6dfbefdSBarry Smith The local vector entries correspond to interpolation points lying on this process, according to the associated `DM`. 446f6dfbefdSBarry Smith This is a borrowed vector that the user should not destroy. 4474267b1a3SMatthew G. Knepley 4484267b1a3SMatthew G. Knepley Level: intermediate 4494267b1a3SMatthew G. Knepley 450f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 4514267b1a3SMatthew G. Knepley @*/ 452d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetCoordinates(DMInterpolationInfo ctx, Vec *coordinates) 453d71ae5a4SJacob Faibussowitsch { 454552f7358SJed Brown PetscFunctionBegin; 455552f7358SJed Brown PetscValidPointer(coordinates, 2); 45628b400f6SJacob Faibussowitsch PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup."); 457552f7358SJed Brown *coordinates = ctx->coords; 458552f7358SJed Brown PetscFunctionReturn(0); 459552f7358SJed Brown } 460552f7358SJed Brown 4614267b1a3SMatthew G. Knepley /*@C 462f6dfbefdSBarry Smith DMInterpolationGetVector - Gets a `Vec` which can hold all the interpolated field values 4634267b1a3SMatthew G. Knepley 464*c3339decSBarry Smith Collective 4654267b1a3SMatthew G. Knepley 4664267b1a3SMatthew G. Knepley Input Parameter: 4674267b1a3SMatthew G. Knepley . ctx - the context 4684267b1a3SMatthew G. Knepley 4694267b1a3SMatthew G. Knepley Output Parameter: 4704267b1a3SMatthew G. Knepley . v - a vector capable of holding the interpolated field values 4714267b1a3SMatthew G. Knepley 472f6dfbefdSBarry Smith Note: 473f6dfbefdSBarry Smith This vector should be returned using `DMInterpolationRestoreVector()`. 4744267b1a3SMatthew G. Knepley 4754267b1a3SMatthew G. Knepley Level: intermediate 4764267b1a3SMatthew G. Knepley 477f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationRestoreVector()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 4784267b1a3SMatthew G. Knepley @*/ 479d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationGetVector(DMInterpolationInfo ctx, Vec *v) 480d71ae5a4SJacob Faibussowitsch { 481552f7358SJed Brown PetscFunctionBegin; 482552f7358SJed Brown PetscValidPointer(v, 2); 48328b400f6SJacob Faibussowitsch PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup."); 4849566063dSJacob Faibussowitsch PetscCall(VecCreate(ctx->comm, v)); 4859566063dSJacob Faibussowitsch PetscCall(VecSetSizes(*v, ctx->n * ctx->dof, PETSC_DECIDE)); 4869566063dSJacob Faibussowitsch PetscCall(VecSetBlockSize(*v, ctx->dof)); 4879566063dSJacob Faibussowitsch PetscCall(VecSetType(*v, VECSTANDARD)); 488552f7358SJed Brown PetscFunctionReturn(0); 489552f7358SJed Brown } 490552f7358SJed Brown 4914267b1a3SMatthew G. Knepley /*@C 492f6dfbefdSBarry Smith DMInterpolationRestoreVector - Returns a `Vec` which can hold all the interpolated field values 4934267b1a3SMatthew G. Knepley 494*c3339decSBarry Smith Collective 4954267b1a3SMatthew G. Knepley 4964267b1a3SMatthew G. Knepley Input Parameters: 4974267b1a3SMatthew G. Knepley + ctx - the context 4984267b1a3SMatthew G. Knepley - v - a vector capable of holding the interpolated field values 4994267b1a3SMatthew G. Knepley 5004267b1a3SMatthew G. Knepley Level: intermediate 5014267b1a3SMatthew G. Knepley 502f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetVector()`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 5034267b1a3SMatthew G. Knepley @*/ 504d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationRestoreVector(DMInterpolationInfo ctx, Vec *v) 505d71ae5a4SJacob Faibussowitsch { 506552f7358SJed Brown PetscFunctionBegin; 507552f7358SJed Brown PetscValidPointer(v, 2); 50828b400f6SJacob Faibussowitsch PetscCheck(ctx->coords, ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup."); 5099566063dSJacob Faibussowitsch PetscCall(VecDestroy(v)); 510552f7358SJed Brown PetscFunctionReturn(0); 511552f7358SJed Brown } 512552f7358SJed Brown 513d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Segment_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 514d71ae5a4SJacob Faibussowitsch { 515cfe5744fSMatthew G. Knepley PetscReal v0, J, invJ, detJ; 516cfe5744fSMatthew G. Knepley const PetscInt dof = ctx->dof; 517cfe5744fSMatthew G. Knepley const PetscScalar *coords; 518cfe5744fSMatthew G. Knepley PetscScalar *a; 519cfe5744fSMatthew G. Knepley PetscInt p; 520cfe5744fSMatthew G. Knepley 521cfe5744fSMatthew G. Knepley PetscFunctionBegin; 5229566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 5239566063dSJacob Faibussowitsch PetscCall(VecGetArray(v, &a)); 524cfe5744fSMatthew G. Knepley for (p = 0; p < ctx->n; ++p) { 525cfe5744fSMatthew G. Knepley PetscInt c = ctx->cells[p]; 526cfe5744fSMatthew G. Knepley PetscScalar *x = NULL; 527cfe5744fSMatthew G. Knepley PetscReal xir[1]; 528cfe5744fSMatthew G. Knepley PetscInt xSize, comp; 529cfe5744fSMatthew G. Knepley 5309566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, &v0, &J, &invJ, &detJ)); 531cfe5744fSMatthew G. Knepley PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c); 532cfe5744fSMatthew G. Knepley xir[0] = invJ * PetscRealPart(coords[p] - v0); 5339566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x)); 534cfe5744fSMatthew G. Knepley if (2 * dof == xSize) { 535cfe5744fSMatthew 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]; 536cfe5744fSMatthew G. Knepley } else if (dof == xSize) { 537cfe5744fSMatthew G. Knepley for (comp = 0; comp < dof; ++comp) a[p * dof + comp] = x[0 * dof + comp]; 538cfe5744fSMatthew 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); 5399566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x)); 540cfe5744fSMatthew G. Knepley } 5419566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(v, &a)); 5429566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 543cfe5744fSMatthew G. Knepley PetscFunctionReturn(0); 544cfe5744fSMatthew G. Knepley } 545cfe5744fSMatthew G. Knepley 546d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Triangle_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 547d71ae5a4SJacob Faibussowitsch { 548552f7358SJed Brown PetscReal *v0, *J, *invJ, detJ; 54956044e6dSMatthew G. Knepley const PetscScalar *coords; 55056044e6dSMatthew G. Knepley PetscScalar *a; 551552f7358SJed Brown PetscInt p; 552552f7358SJed Brown 553552f7358SJed Brown PetscFunctionBegin; 5549566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(ctx->dim, &v0, ctx->dim * ctx->dim, &J, ctx->dim * ctx->dim, &invJ)); 5559566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 5569566063dSJacob Faibussowitsch PetscCall(VecGetArray(v, &a)); 557552f7358SJed Brown for (p = 0; p < ctx->n; ++p) { 558552f7358SJed Brown PetscInt c = ctx->cells[p]; 559a1e44745SMatthew G. Knepley PetscScalar *x = NULL; 560552f7358SJed Brown PetscReal xi[4]; 561552f7358SJed Brown PetscInt d, f, comp; 562552f7358SJed Brown 5639566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ)); 56463a3b9bcSJacob Faibussowitsch PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c); 5659566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x)); 5661aa26658SKarl Rupp for (comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp]; 5671aa26658SKarl Rupp 568552f7358SJed Brown for (d = 0; d < ctx->dim; ++d) { 569552f7358SJed Brown xi[d] = 0.0; 5701aa26658SKarl 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]); 5711aa26658SKarl 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]; 572552f7358SJed Brown } 5739566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x)); 574552f7358SJed Brown } 5759566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(v, &a)); 5769566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 5779566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 578552f7358SJed Brown PetscFunctionReturn(0); 579552f7358SJed Brown } 580552f7358SJed Brown 581d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Tetrahedron_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 582d71ae5a4SJacob Faibussowitsch { 5837a1931ceSMatthew G. Knepley PetscReal *v0, *J, *invJ, detJ; 58456044e6dSMatthew G. Knepley const PetscScalar *coords; 58556044e6dSMatthew G. Knepley PetscScalar *a; 5867a1931ceSMatthew G. Knepley PetscInt p; 5877a1931ceSMatthew G. Knepley 5887a1931ceSMatthew G. Knepley PetscFunctionBegin; 5899566063dSJacob Faibussowitsch PetscCall(PetscMalloc3(ctx->dim, &v0, ctx->dim * ctx->dim, &J, ctx->dim * ctx->dim, &invJ)); 5909566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 5919566063dSJacob Faibussowitsch PetscCall(VecGetArray(v, &a)); 5927a1931ceSMatthew G. Knepley for (p = 0; p < ctx->n; ++p) { 5937a1931ceSMatthew G. Knepley PetscInt c = ctx->cells[p]; 5947a1931ceSMatthew G. Knepley const PetscInt order[3] = {2, 1, 3}; 5952584bbe8SMatthew G. Knepley PetscScalar *x = NULL; 5967a1931ceSMatthew G. Knepley PetscReal xi[4]; 5977a1931ceSMatthew G. Knepley PetscInt d, f, comp; 5987a1931ceSMatthew G. Knepley 5999566063dSJacob Faibussowitsch PetscCall(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ)); 60063a3b9bcSJacob Faibussowitsch PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double)detJ, c); 6019566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x)); 6027a1931ceSMatthew G. Knepley for (comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp]; 6037a1931ceSMatthew G. Knepley 6047a1931ceSMatthew G. Knepley for (d = 0; d < ctx->dim; ++d) { 6057a1931ceSMatthew G. Knepley xi[d] = 0.0; 6067a1931ceSMatthew 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]); 6077a1931ceSMatthew 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]; 6087a1931ceSMatthew G. Knepley } 6099566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x)); 6107a1931ceSMatthew G. Knepley } 6119566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(v, &a)); 6129566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 6139566063dSJacob Faibussowitsch PetscCall(PetscFree3(v0, J, invJ)); 6147a1931ceSMatthew G. Knepley PetscFunctionReturn(0); 6157a1931ceSMatthew G. Knepley } 6167a1931ceSMatthew G. Knepley 617d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode QuadMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx) 618d71ae5a4SJacob Faibussowitsch { 619552f7358SJed Brown const PetscScalar *vertices = (const PetscScalar *)ctx; 620552f7358SJed Brown const PetscScalar x0 = vertices[0]; 621552f7358SJed Brown const PetscScalar y0 = vertices[1]; 622552f7358SJed Brown const PetscScalar x1 = vertices[2]; 623552f7358SJed Brown const PetscScalar y1 = vertices[3]; 624552f7358SJed Brown const PetscScalar x2 = vertices[4]; 625552f7358SJed Brown const PetscScalar y2 = vertices[5]; 626552f7358SJed Brown const PetscScalar x3 = vertices[6]; 627552f7358SJed Brown const PetscScalar y3 = vertices[7]; 628552f7358SJed Brown const PetscScalar f_1 = x1 - x0; 629552f7358SJed Brown const PetscScalar g_1 = y1 - y0; 630552f7358SJed Brown const PetscScalar f_3 = x3 - x0; 631552f7358SJed Brown const PetscScalar g_3 = y3 - y0; 632552f7358SJed Brown const PetscScalar f_01 = x2 - x1 - x3 + x0; 633552f7358SJed Brown const PetscScalar g_01 = y2 - y1 - y3 + y0; 63456044e6dSMatthew G. Knepley const PetscScalar *ref; 63556044e6dSMatthew G. Knepley PetscScalar *real; 636552f7358SJed Brown 637552f7358SJed Brown PetscFunctionBegin; 6389566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(Xref, &ref)); 6399566063dSJacob Faibussowitsch PetscCall(VecGetArray(Xreal, &real)); 640552f7358SJed Brown { 641552f7358SJed Brown const PetscScalar p0 = ref[0]; 642552f7358SJed Brown const PetscScalar p1 = ref[1]; 643552f7358SJed Brown 644552f7358SJed Brown real[0] = x0 + f_1 * p0 + f_3 * p1 + f_01 * p0 * p1; 645552f7358SJed Brown real[1] = y0 + g_1 * p0 + g_3 * p1 + g_01 * p0 * p1; 646552f7358SJed Brown } 6479566063dSJacob Faibussowitsch PetscCall(PetscLogFlops(28)); 6489566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(Xref, &ref)); 6499566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(Xreal, &real)); 650552f7358SJed Brown PetscFunctionReturn(0); 651552f7358SJed Brown } 652552f7358SJed Brown 653af0996ceSBarry Smith #include <petsc/private/dmimpl.h> 654d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode QuadJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx) 655d71ae5a4SJacob Faibussowitsch { 656552f7358SJed Brown const PetscScalar *vertices = (const PetscScalar *)ctx; 657552f7358SJed Brown const PetscScalar x0 = vertices[0]; 658552f7358SJed Brown const PetscScalar y0 = vertices[1]; 659552f7358SJed Brown const PetscScalar x1 = vertices[2]; 660552f7358SJed Brown const PetscScalar y1 = vertices[3]; 661552f7358SJed Brown const PetscScalar x2 = vertices[4]; 662552f7358SJed Brown const PetscScalar y2 = vertices[5]; 663552f7358SJed Brown const PetscScalar x3 = vertices[6]; 664552f7358SJed Brown const PetscScalar y3 = vertices[7]; 665552f7358SJed Brown const PetscScalar f_01 = x2 - x1 - x3 + x0; 666552f7358SJed Brown const PetscScalar g_01 = y2 - y1 - y3 + y0; 66756044e6dSMatthew G. Knepley const PetscScalar *ref; 668552f7358SJed Brown 669552f7358SJed Brown PetscFunctionBegin; 6709566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(Xref, &ref)); 671552f7358SJed Brown { 672552f7358SJed Brown const PetscScalar x = ref[0]; 673552f7358SJed Brown const PetscScalar y = ref[1]; 674552f7358SJed Brown const PetscInt rows[2] = {0, 1}; 675da80777bSKarl Rupp PetscScalar values[4]; 676da80777bSKarl Rupp 6779371c9d4SSatish Balay values[0] = (x1 - x0 + f_01 * y) * 0.5; 6789371c9d4SSatish Balay values[1] = (x3 - x0 + f_01 * x) * 0.5; 6799371c9d4SSatish Balay values[2] = (y1 - y0 + g_01 * y) * 0.5; 6809371c9d4SSatish Balay values[3] = (y3 - y0 + g_01 * x) * 0.5; 6819566063dSJacob Faibussowitsch PetscCall(MatSetValues(J, 2, rows, 2, rows, values, INSERT_VALUES)); 682552f7358SJed Brown } 6839566063dSJacob Faibussowitsch PetscCall(PetscLogFlops(30)); 6849566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(Xref, &ref)); 6859566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY)); 6869566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY)); 687552f7358SJed Brown PetscFunctionReturn(0); 688552f7358SJed Brown } 689552f7358SJed Brown 690d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Quad_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 691d71ae5a4SJacob Faibussowitsch { 692fafc0619SMatthew G Knepley DM dmCoord; 693de73a395SMatthew G. Knepley PetscFE fem = NULL; 694552f7358SJed Brown SNES snes; 695552f7358SJed Brown KSP ksp; 696552f7358SJed Brown PC pc; 697552f7358SJed Brown Vec coordsLocal, r, ref, real; 698552f7358SJed Brown Mat J; 699716009bfSMatthew G. Knepley PetscTabulation T = NULL; 70056044e6dSMatthew G. Knepley const PetscScalar *coords; 70156044e6dSMatthew G. Knepley PetscScalar *a; 702716009bfSMatthew G. Knepley PetscReal xir[2] = {0., 0.}; 703de73a395SMatthew G. Knepley PetscInt Nf, p; 7045509d985SMatthew G. Knepley const PetscInt dof = ctx->dof; 705552f7358SJed Brown 706552f7358SJed Brown PetscFunctionBegin; 7079566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 708716009bfSMatthew G. Knepley if (Nf) { 709cfe5744fSMatthew G. Knepley PetscObject obj; 710cfe5744fSMatthew G. Knepley PetscClassId id; 711cfe5744fSMatthew G. Knepley 7129566063dSJacob Faibussowitsch PetscCall(DMGetField(dm, 0, NULL, &obj)); 7139566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 7149371c9d4SSatish Balay if (id == PETSCFE_CLASSID) { 7159371c9d4SSatish Balay fem = (PetscFE)obj; 7169371c9d4SSatish Balay PetscCall(PetscFECreateTabulation(fem, 1, 1, xir, 0, &T)); 7179371c9d4SSatish Balay } 718716009bfSMatthew G. Knepley } 7199566063dSJacob Faibussowitsch PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 7209566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDM(dm, &dmCoord)); 7219566063dSJacob Faibussowitsch PetscCall(SNESCreate(PETSC_COMM_SELF, &snes)); 7229566063dSJacob Faibussowitsch PetscCall(SNESSetOptionsPrefix(snes, "quad_interp_")); 7239566063dSJacob Faibussowitsch PetscCall(VecCreate(PETSC_COMM_SELF, &r)); 7249566063dSJacob Faibussowitsch PetscCall(VecSetSizes(r, 2, 2)); 7259566063dSJacob Faibussowitsch PetscCall(VecSetType(r, dm->vectype)); 7269566063dSJacob Faibussowitsch PetscCall(VecDuplicate(r, &ref)); 7279566063dSJacob Faibussowitsch PetscCall(VecDuplicate(r, &real)); 7289566063dSJacob Faibussowitsch PetscCall(MatCreate(PETSC_COMM_SELF, &J)); 7299566063dSJacob Faibussowitsch PetscCall(MatSetSizes(J, 2, 2, 2, 2)); 7309566063dSJacob Faibussowitsch PetscCall(MatSetType(J, MATSEQDENSE)); 7319566063dSJacob Faibussowitsch PetscCall(MatSetUp(J)); 7329566063dSJacob Faibussowitsch PetscCall(SNESSetFunction(snes, r, QuadMap_Private, NULL)); 7339566063dSJacob Faibussowitsch PetscCall(SNESSetJacobian(snes, J, J, QuadJacobian_Private, NULL)); 7349566063dSJacob Faibussowitsch PetscCall(SNESGetKSP(snes, &ksp)); 7359566063dSJacob Faibussowitsch PetscCall(KSPGetPC(ksp, &pc)); 7369566063dSJacob Faibussowitsch PetscCall(PCSetType(pc, PCLU)); 7379566063dSJacob Faibussowitsch PetscCall(SNESSetFromOptions(snes)); 738552f7358SJed Brown 7399566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 7409566063dSJacob Faibussowitsch PetscCall(VecGetArray(v, &a)); 741552f7358SJed Brown for (p = 0; p < ctx->n; ++p) { 742a1e44745SMatthew G. Knepley PetscScalar *x = NULL, *vertices = NULL; 743552f7358SJed Brown PetscScalar *xi; 744552f7358SJed Brown PetscInt c = ctx->cells[p], comp, coordSize, xSize; 745552f7358SJed Brown 746552f7358SJed Brown /* Can make this do all points at once */ 7479566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices)); 74863a3b9bcSJacob Faibussowitsch PetscCheck(4 * 2 == coordSize, ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid closure size %" PetscInt_FMT " should be %d", coordSize, 4 * 2); 7499566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x)); 7509566063dSJacob Faibussowitsch PetscCall(SNESSetFunction(snes, NULL, NULL, vertices)); 7519566063dSJacob Faibussowitsch PetscCall(SNESSetJacobian(snes, NULL, NULL, NULL, vertices)); 7529566063dSJacob Faibussowitsch PetscCall(VecGetArray(real, &xi)); 753552f7358SJed Brown xi[0] = coords[p * ctx->dim + 0]; 754552f7358SJed Brown xi[1] = coords[p * ctx->dim + 1]; 7559566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(real, &xi)); 7569566063dSJacob Faibussowitsch PetscCall(SNESSolve(snes, real, ref)); 7579566063dSJacob Faibussowitsch PetscCall(VecGetArray(ref, &xi)); 758cb313848SJed Brown xir[0] = PetscRealPart(xi[0]); 759cb313848SJed Brown xir[1] = PetscRealPart(xi[1]); 760cfe5744fSMatthew G. Knepley if (4 * dof == xSize) { 7619371c9d4SSatish 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]; 762cfe5744fSMatthew G. Knepley } else if (dof == xSize) { 763cfe5744fSMatthew G. Knepley for (comp = 0; comp < dof; ++comp) a[p * dof + comp] = x[0 * dof + comp]; 764cfe5744fSMatthew G. Knepley } else { 7655509d985SMatthew G. Knepley PetscInt d; 7661aa26658SKarl Rupp 7672c71b3e2SJacob Faibussowitsch PetscCheck(fem, ctx->comm, PETSC_ERR_ARG_WRONG, "Cannot have a higher order interpolant if the discretization is not PetscFE"); 7689371c9d4SSatish Balay xir[0] = 2.0 * xir[0] - 1.0; 7699371c9d4SSatish Balay xir[1] = 2.0 * xir[1] - 1.0; 7709566063dSJacob Faibussowitsch PetscCall(PetscFEComputeTabulation(fem, 1, xir, 0, T)); 7715509d985SMatthew G. Knepley for (comp = 0; comp < dof; ++comp) { 7725509d985SMatthew G. Knepley a[p * dof + comp] = 0.0; 773ad540459SPierre Jolivet for (d = 0; d < xSize / dof; ++d) a[p * dof + comp] += x[d * dof + comp] * T->T[0][d * dof + comp]; 7745509d985SMatthew G. Knepley } 7755509d985SMatthew G. Knepley } 7769566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(ref, &xi)); 7779566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices)); 7789566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x)); 779552f7358SJed Brown } 7809566063dSJacob Faibussowitsch PetscCall(PetscTabulationDestroy(&T)); 7819566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(v, &a)); 7829566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 783552f7358SJed Brown 7849566063dSJacob Faibussowitsch PetscCall(SNESDestroy(&snes)); 7859566063dSJacob Faibussowitsch PetscCall(VecDestroy(&r)); 7869566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ref)); 7879566063dSJacob Faibussowitsch PetscCall(VecDestroy(&real)); 7889566063dSJacob Faibussowitsch PetscCall(MatDestroy(&J)); 789552f7358SJed Brown PetscFunctionReturn(0); 790552f7358SJed Brown } 791552f7358SJed Brown 792d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode HexMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx) 793d71ae5a4SJacob Faibussowitsch { 794552f7358SJed Brown const PetscScalar *vertices = (const PetscScalar *)ctx; 795552f7358SJed Brown const PetscScalar x0 = vertices[0]; 796552f7358SJed Brown const PetscScalar y0 = vertices[1]; 797552f7358SJed Brown const PetscScalar z0 = vertices[2]; 7987a1931ceSMatthew G. Knepley const PetscScalar x1 = vertices[9]; 7997a1931ceSMatthew G. Knepley const PetscScalar y1 = vertices[10]; 8007a1931ceSMatthew G. Knepley const PetscScalar z1 = vertices[11]; 801552f7358SJed Brown const PetscScalar x2 = vertices[6]; 802552f7358SJed Brown const PetscScalar y2 = vertices[7]; 803552f7358SJed Brown const PetscScalar z2 = vertices[8]; 8047a1931ceSMatthew G. Knepley const PetscScalar x3 = vertices[3]; 8057a1931ceSMatthew G. Knepley const PetscScalar y3 = vertices[4]; 8067a1931ceSMatthew G. Knepley const PetscScalar z3 = vertices[5]; 807552f7358SJed Brown const PetscScalar x4 = vertices[12]; 808552f7358SJed Brown const PetscScalar y4 = vertices[13]; 809552f7358SJed Brown const PetscScalar z4 = vertices[14]; 810552f7358SJed Brown const PetscScalar x5 = vertices[15]; 811552f7358SJed Brown const PetscScalar y5 = vertices[16]; 812552f7358SJed Brown const PetscScalar z5 = vertices[17]; 813552f7358SJed Brown const PetscScalar x6 = vertices[18]; 814552f7358SJed Brown const PetscScalar y6 = vertices[19]; 815552f7358SJed Brown const PetscScalar z6 = vertices[20]; 816552f7358SJed Brown const PetscScalar x7 = vertices[21]; 817552f7358SJed Brown const PetscScalar y7 = vertices[22]; 818552f7358SJed Brown const PetscScalar z7 = vertices[23]; 819552f7358SJed Brown const PetscScalar f_1 = x1 - x0; 820552f7358SJed Brown const PetscScalar g_1 = y1 - y0; 821552f7358SJed Brown const PetscScalar h_1 = z1 - z0; 822552f7358SJed Brown const PetscScalar f_3 = x3 - x0; 823552f7358SJed Brown const PetscScalar g_3 = y3 - y0; 824552f7358SJed Brown const PetscScalar h_3 = z3 - z0; 825552f7358SJed Brown const PetscScalar f_4 = x4 - x0; 826552f7358SJed Brown const PetscScalar g_4 = y4 - y0; 827552f7358SJed Brown const PetscScalar h_4 = z4 - z0; 828552f7358SJed Brown const PetscScalar f_01 = x2 - x1 - x3 + x0; 829552f7358SJed Brown const PetscScalar g_01 = y2 - y1 - y3 + y0; 830552f7358SJed Brown const PetscScalar h_01 = z2 - z1 - z3 + z0; 831552f7358SJed Brown const PetscScalar f_12 = x7 - x3 - x4 + x0; 832552f7358SJed Brown const PetscScalar g_12 = y7 - y3 - y4 + y0; 833552f7358SJed Brown const PetscScalar h_12 = z7 - z3 - z4 + z0; 834552f7358SJed Brown const PetscScalar f_02 = x5 - x1 - x4 + x0; 835552f7358SJed Brown const PetscScalar g_02 = y5 - y1 - y4 + y0; 836552f7358SJed Brown const PetscScalar h_02 = z5 - z1 - z4 + z0; 837552f7358SJed Brown const PetscScalar f_012 = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7; 838552f7358SJed Brown const PetscScalar g_012 = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7; 839552f7358SJed Brown const PetscScalar h_012 = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7; 84056044e6dSMatthew G. Knepley const PetscScalar *ref; 84156044e6dSMatthew G. Knepley PetscScalar *real; 842552f7358SJed Brown 843552f7358SJed Brown PetscFunctionBegin; 8449566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(Xref, &ref)); 8459566063dSJacob Faibussowitsch PetscCall(VecGetArray(Xreal, &real)); 846552f7358SJed Brown { 847552f7358SJed Brown const PetscScalar p0 = ref[0]; 848552f7358SJed Brown const PetscScalar p1 = ref[1]; 849552f7358SJed Brown const PetscScalar p2 = ref[2]; 850552f7358SJed Brown 851552f7358SJed 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; 852552f7358SJed 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; 853552f7358SJed 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; 854552f7358SJed Brown } 8559566063dSJacob Faibussowitsch PetscCall(PetscLogFlops(114)); 8569566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(Xref, &ref)); 8579566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(Xreal, &real)); 858552f7358SJed Brown PetscFunctionReturn(0); 859552f7358SJed Brown } 860552f7358SJed Brown 861d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode HexJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx) 862d71ae5a4SJacob Faibussowitsch { 863552f7358SJed Brown const PetscScalar *vertices = (const PetscScalar *)ctx; 864552f7358SJed Brown const PetscScalar x0 = vertices[0]; 865552f7358SJed Brown const PetscScalar y0 = vertices[1]; 866552f7358SJed Brown const PetscScalar z0 = vertices[2]; 8677a1931ceSMatthew G. Knepley const PetscScalar x1 = vertices[9]; 8687a1931ceSMatthew G. Knepley const PetscScalar y1 = vertices[10]; 8697a1931ceSMatthew G. Knepley const PetscScalar z1 = vertices[11]; 870552f7358SJed Brown const PetscScalar x2 = vertices[6]; 871552f7358SJed Brown const PetscScalar y2 = vertices[7]; 872552f7358SJed Brown const PetscScalar z2 = vertices[8]; 8737a1931ceSMatthew G. Knepley const PetscScalar x3 = vertices[3]; 8747a1931ceSMatthew G. Knepley const PetscScalar y3 = vertices[4]; 8757a1931ceSMatthew G. Knepley const PetscScalar z3 = vertices[5]; 876552f7358SJed Brown const PetscScalar x4 = vertices[12]; 877552f7358SJed Brown const PetscScalar y4 = vertices[13]; 878552f7358SJed Brown const PetscScalar z4 = vertices[14]; 879552f7358SJed Brown const PetscScalar x5 = vertices[15]; 880552f7358SJed Brown const PetscScalar y5 = vertices[16]; 881552f7358SJed Brown const PetscScalar z5 = vertices[17]; 882552f7358SJed Brown const PetscScalar x6 = vertices[18]; 883552f7358SJed Brown const PetscScalar y6 = vertices[19]; 884552f7358SJed Brown const PetscScalar z6 = vertices[20]; 885552f7358SJed Brown const PetscScalar x7 = vertices[21]; 886552f7358SJed Brown const PetscScalar y7 = vertices[22]; 887552f7358SJed Brown const PetscScalar z7 = vertices[23]; 888552f7358SJed Brown const PetscScalar f_xy = x2 - x1 - x3 + x0; 889552f7358SJed Brown const PetscScalar g_xy = y2 - y1 - y3 + y0; 890552f7358SJed Brown const PetscScalar h_xy = z2 - z1 - z3 + z0; 891552f7358SJed Brown const PetscScalar f_yz = x7 - x3 - x4 + x0; 892552f7358SJed Brown const PetscScalar g_yz = y7 - y3 - y4 + y0; 893552f7358SJed Brown const PetscScalar h_yz = z7 - z3 - z4 + z0; 894552f7358SJed Brown const PetscScalar f_xz = x5 - x1 - x4 + x0; 895552f7358SJed Brown const PetscScalar g_xz = y5 - y1 - y4 + y0; 896552f7358SJed Brown const PetscScalar h_xz = z5 - z1 - z4 + z0; 897552f7358SJed Brown const PetscScalar f_xyz = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7; 898552f7358SJed Brown const PetscScalar g_xyz = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7; 899552f7358SJed Brown const PetscScalar h_xyz = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7; 90056044e6dSMatthew G. Knepley const PetscScalar *ref; 901552f7358SJed Brown 902552f7358SJed Brown PetscFunctionBegin; 9039566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(Xref, &ref)); 904552f7358SJed Brown { 905552f7358SJed Brown const PetscScalar x = ref[0]; 906552f7358SJed Brown const PetscScalar y = ref[1]; 907552f7358SJed Brown const PetscScalar z = ref[2]; 908552f7358SJed Brown const PetscInt rows[3] = {0, 1, 2}; 909da80777bSKarl Rupp PetscScalar values[9]; 910da80777bSKarl Rupp 911da80777bSKarl Rupp values[0] = (x1 - x0 + f_xy * y + f_xz * z + f_xyz * y * z) / 2.0; 912da80777bSKarl Rupp values[1] = (x3 - x0 + f_xy * x + f_yz * z + f_xyz * x * z) / 2.0; 913da80777bSKarl Rupp values[2] = (x4 - x0 + f_yz * y + f_xz * x + f_xyz * x * y) / 2.0; 914da80777bSKarl Rupp values[3] = (y1 - y0 + g_xy * y + g_xz * z + g_xyz * y * z) / 2.0; 915da80777bSKarl Rupp values[4] = (y3 - y0 + g_xy * x + g_yz * z + g_xyz * x * z) / 2.0; 916da80777bSKarl Rupp values[5] = (y4 - y0 + g_yz * y + g_xz * x + g_xyz * x * y) / 2.0; 917da80777bSKarl Rupp values[6] = (z1 - z0 + h_xy * y + h_xz * z + h_xyz * y * z) / 2.0; 918da80777bSKarl Rupp values[7] = (z3 - z0 + h_xy * x + h_yz * z + h_xyz * x * z) / 2.0; 919da80777bSKarl Rupp values[8] = (z4 - z0 + h_yz * y + h_xz * x + h_xyz * x * y) / 2.0; 9201aa26658SKarl Rupp 9219566063dSJacob Faibussowitsch PetscCall(MatSetValues(J, 3, rows, 3, rows, values, INSERT_VALUES)); 922552f7358SJed Brown } 9239566063dSJacob Faibussowitsch PetscCall(PetscLogFlops(152)); 9249566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(Xref, &ref)); 9259566063dSJacob Faibussowitsch PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY)); 9269566063dSJacob Faibussowitsch PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY)); 927552f7358SJed Brown PetscFunctionReturn(0); 928552f7358SJed Brown } 929552f7358SJed Brown 930d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode DMInterpolate_Hex_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 931d71ae5a4SJacob Faibussowitsch { 932fafc0619SMatthew G Knepley DM dmCoord; 933552f7358SJed Brown SNES snes; 934552f7358SJed Brown KSP ksp; 935552f7358SJed Brown PC pc; 936552f7358SJed Brown Vec coordsLocal, r, ref, real; 937552f7358SJed Brown Mat J; 93856044e6dSMatthew G. Knepley const PetscScalar *coords; 93956044e6dSMatthew G. Knepley PetscScalar *a; 940552f7358SJed Brown PetscInt p; 941552f7358SJed Brown 942552f7358SJed Brown PetscFunctionBegin; 9439566063dSJacob Faibussowitsch PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 9449566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDM(dm, &dmCoord)); 9459566063dSJacob Faibussowitsch PetscCall(SNESCreate(PETSC_COMM_SELF, &snes)); 9469566063dSJacob Faibussowitsch PetscCall(SNESSetOptionsPrefix(snes, "hex_interp_")); 9479566063dSJacob Faibussowitsch PetscCall(VecCreate(PETSC_COMM_SELF, &r)); 9489566063dSJacob Faibussowitsch PetscCall(VecSetSizes(r, 3, 3)); 9499566063dSJacob Faibussowitsch PetscCall(VecSetType(r, dm->vectype)); 9509566063dSJacob Faibussowitsch PetscCall(VecDuplicate(r, &ref)); 9519566063dSJacob Faibussowitsch PetscCall(VecDuplicate(r, &real)); 9529566063dSJacob Faibussowitsch PetscCall(MatCreate(PETSC_COMM_SELF, &J)); 9539566063dSJacob Faibussowitsch PetscCall(MatSetSizes(J, 3, 3, 3, 3)); 9549566063dSJacob Faibussowitsch PetscCall(MatSetType(J, MATSEQDENSE)); 9559566063dSJacob Faibussowitsch PetscCall(MatSetUp(J)); 9569566063dSJacob Faibussowitsch PetscCall(SNESSetFunction(snes, r, HexMap_Private, NULL)); 9579566063dSJacob Faibussowitsch PetscCall(SNESSetJacobian(snes, J, J, HexJacobian_Private, NULL)); 9589566063dSJacob Faibussowitsch PetscCall(SNESGetKSP(snes, &ksp)); 9599566063dSJacob Faibussowitsch PetscCall(KSPGetPC(ksp, &pc)); 9609566063dSJacob Faibussowitsch PetscCall(PCSetType(pc, PCLU)); 9619566063dSJacob Faibussowitsch PetscCall(SNESSetFromOptions(snes)); 962552f7358SJed Brown 9639566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 9649566063dSJacob Faibussowitsch PetscCall(VecGetArray(v, &a)); 965552f7358SJed Brown for (p = 0; p < ctx->n; ++p) { 966a1e44745SMatthew G. Knepley PetscScalar *x = NULL, *vertices = NULL; 967552f7358SJed Brown PetscScalar *xi; 968cb313848SJed Brown PetscReal xir[3]; 969552f7358SJed Brown PetscInt c = ctx->cells[p], comp, coordSize, xSize; 970552f7358SJed Brown 971552f7358SJed Brown /* Can make this do all points at once */ 9729566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices)); 973cfe5744fSMatthew G. Knepley PetscCheck(8 * 3 == coordSize, ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid coordinate closure size %" PetscInt_FMT " should be %d", coordSize, 8 * 3); 9749566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x)); 975cfe5744fSMatthew 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); 9769566063dSJacob Faibussowitsch PetscCall(SNESSetFunction(snes, NULL, NULL, vertices)); 9779566063dSJacob Faibussowitsch PetscCall(SNESSetJacobian(snes, NULL, NULL, NULL, vertices)); 9789566063dSJacob Faibussowitsch PetscCall(VecGetArray(real, &xi)); 979552f7358SJed Brown xi[0] = coords[p * ctx->dim + 0]; 980552f7358SJed Brown xi[1] = coords[p * ctx->dim + 1]; 981552f7358SJed Brown xi[2] = coords[p * ctx->dim + 2]; 9829566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(real, &xi)); 9839566063dSJacob Faibussowitsch PetscCall(SNESSolve(snes, real, ref)); 9849566063dSJacob Faibussowitsch PetscCall(VecGetArray(ref, &xi)); 985cb313848SJed Brown xir[0] = PetscRealPart(xi[0]); 986cb313848SJed Brown xir[1] = PetscRealPart(xi[1]); 987cb313848SJed Brown xir[2] = PetscRealPart(xi[2]); 988cfe5744fSMatthew G. Knepley if (8 * ctx->dof == xSize) { 989552f7358SJed Brown for (comp = 0; comp < ctx->dof; ++comp) { 9909371c9d4SSatish 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]) + 9919371c9d4SSatish 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]; 992552f7358SJed Brown } 993cfe5744fSMatthew G. Knepley } else { 994cfe5744fSMatthew G. Knepley for (comp = 0; comp < ctx->dof; ++comp) a[p * ctx->dof + comp] = x[0 * ctx->dof + comp]; 995cfe5744fSMatthew G. Knepley } 9969566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(ref, &xi)); 9979566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices)); 9989566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x)); 999552f7358SJed Brown } 10009566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(v, &a)); 10019566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 1002552f7358SJed Brown 10039566063dSJacob Faibussowitsch PetscCall(SNESDestroy(&snes)); 10049566063dSJacob Faibussowitsch PetscCall(VecDestroy(&r)); 10059566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ref)); 10069566063dSJacob Faibussowitsch PetscCall(VecDestroy(&real)); 10079566063dSJacob Faibussowitsch PetscCall(MatDestroy(&J)); 1008552f7358SJed Brown PetscFunctionReturn(0); 1009552f7358SJed Brown } 1010552f7358SJed Brown 10114267b1a3SMatthew G. Knepley /*@C 10124267b1a3SMatthew G. Knepley DMInterpolationEvaluate - Using the input from dm and x, calculates interpolated field values at the interpolation points. 10134267b1a3SMatthew G. Knepley 1014552f7358SJed Brown Input Parameters: 1015f6dfbefdSBarry Smith + ctx - The `DMInterpolationInfo` context 1016f6dfbefdSBarry Smith . dm - The `DM` 1017552f7358SJed Brown - x - The local vector containing the field to be interpolated 1018552f7358SJed Brown 1019552f7358SJed Brown Output Parameters: 1020552f7358SJed Brown . v - The vector containing the interpolated values 10214267b1a3SMatthew G. Knepley 1022f6dfbefdSBarry Smith Note: 1023f6dfbefdSBarry Smith A suitable v can be obtained using `DMInterpolationGetVector()`. 10244267b1a3SMatthew G. Knepley 10254267b1a3SMatthew G. Knepley Level: beginner 10264267b1a3SMatthew G. Knepley 1027f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationGetVector()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 10284267b1a3SMatthew G. Knepley @*/ 1029d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationEvaluate(DMInterpolationInfo ctx, DM dm, Vec x, Vec v) 1030d71ae5a4SJacob Faibussowitsch { 103166a0a883SMatthew G. Knepley PetscDS ds; 103266a0a883SMatthew G. Knepley PetscInt n, p, Nf, field; 103366a0a883SMatthew G. Knepley PetscBool useDS = PETSC_FALSE; 1034552f7358SJed Brown 1035552f7358SJed Brown PetscFunctionBegin; 1036552f7358SJed Brown PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 1037552f7358SJed Brown PetscValidHeaderSpecific(x, VEC_CLASSID, 3); 1038552f7358SJed Brown PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 10399566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(v, &n)); 104063a3b9bcSJacob 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); 104166a0a883SMatthew G. Knepley if (!n) PetscFunctionReturn(0); 10429566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &ds)); 1043680d18d5SMatthew G. Knepley if (ds) { 104466a0a883SMatthew G. Knepley useDS = PETSC_TRUE; 10459566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &Nf)); 1046680d18d5SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 104766a0a883SMatthew G. Knepley PetscObject obj; 1048680d18d5SMatthew G. Knepley PetscClassId id; 1049680d18d5SMatthew G. Knepley 10509566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, field, &obj)); 10519566063dSJacob Faibussowitsch PetscCall(PetscObjectGetClassId(obj, &id)); 10529371c9d4SSatish Balay if (id != PETSCFE_CLASSID) { 10539371c9d4SSatish Balay useDS = PETSC_FALSE; 10549371c9d4SSatish Balay break; 10559371c9d4SSatish Balay } 105666a0a883SMatthew G. Knepley } 105766a0a883SMatthew G. Knepley } 105866a0a883SMatthew G. Knepley if (useDS) { 105966a0a883SMatthew G. Knepley const PetscScalar *coords; 106066a0a883SMatthew G. Knepley PetscScalar *interpolant; 106166a0a883SMatthew G. Knepley PetscInt cdim, d; 106266a0a883SMatthew G. Knepley 10639566063dSJacob Faibussowitsch PetscCall(DMGetCoordinateDim(dm, &cdim)); 10649566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(ctx->coords, &coords)); 10659566063dSJacob Faibussowitsch PetscCall(VecGetArrayWrite(v, &interpolant)); 1066680d18d5SMatthew G. Knepley for (p = 0; p < ctx->n; ++p) { 106766a0a883SMatthew G. Knepley PetscReal pcoords[3], xi[3]; 1068680d18d5SMatthew G. Knepley PetscScalar *xa = NULL; 106966a0a883SMatthew G. Knepley PetscInt coff = 0, foff = 0, clSize; 1070680d18d5SMatthew G. Knepley 107152aa1562SMatthew G. Knepley if (ctx->cells[p] < 0) continue; 1072680d18d5SMatthew G. Knepley for (d = 0; d < cdim; ++d) pcoords[d] = PetscRealPart(coords[p * cdim + d]); 10739566063dSJacob Faibussowitsch PetscCall(DMPlexCoordinatesToReference(dm, ctx->cells[p], 1, pcoords, xi)); 10749566063dSJacob Faibussowitsch PetscCall(DMPlexVecGetClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa)); 107566a0a883SMatthew G. Knepley for (field = 0; field < Nf; ++field) { 107666a0a883SMatthew G. Knepley PetscTabulation T; 107766a0a883SMatthew G. Knepley PetscFE fe; 107866a0a883SMatthew G. Knepley 10799566063dSJacob Faibussowitsch PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *)&fe)); 10809566063dSJacob Faibussowitsch PetscCall(PetscFECreateTabulation(fe, 1, 1, xi, 0, &T)); 1081680d18d5SMatthew G. Knepley { 1082680d18d5SMatthew G. Knepley const PetscReal *basis = T->T[0]; 1083680d18d5SMatthew G. Knepley const PetscInt Nb = T->Nb; 1084680d18d5SMatthew G. Knepley const PetscInt Nc = T->Nc; 108566a0a883SMatthew G. Knepley PetscInt f, fc; 108666a0a883SMatthew G. Knepley 1087680d18d5SMatthew G. Knepley for (fc = 0; fc < Nc; ++fc) { 108866a0a883SMatthew G. Knepley interpolant[p * ctx->dof + coff + fc] = 0.0; 1089ad540459SPierre Jolivet for (f = 0; f < Nb; ++f) interpolant[p * ctx->dof + coff + fc] += xa[foff + f] * basis[(0 * Nb + f) * Nc + fc]; 1090680d18d5SMatthew G. Knepley } 109166a0a883SMatthew G. Knepley coff += Nc; 109266a0a883SMatthew G. Knepley foff += Nb; 1093680d18d5SMatthew G. Knepley } 10949566063dSJacob Faibussowitsch PetscCall(PetscTabulationDestroy(&T)); 1095680d18d5SMatthew G. Knepley } 10969566063dSJacob Faibussowitsch PetscCall(DMPlexVecRestoreClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa)); 109763a3b9bcSJacob Faibussowitsch PetscCheck(coff == ctx->dof, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total components %" PetscInt_FMT " != %" PetscInt_FMT " dof specified for interpolation", coff, ctx->dof); 109863a3b9bcSJacob Faibussowitsch PetscCheck(foff == clSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total FE space size %" PetscInt_FMT " != %" PetscInt_FMT " closure size", foff, clSize); 109966a0a883SMatthew G. Knepley } 11009566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(ctx->coords, &coords)); 11019566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayWrite(v, &interpolant)); 110266a0a883SMatthew G. Knepley } else { 110366a0a883SMatthew G. Knepley DMPolytopeType ct; 110466a0a883SMatthew G. Knepley 1105680d18d5SMatthew G. Knepley /* TODO Check each cell individually */ 11069566063dSJacob Faibussowitsch PetscCall(DMPlexGetCellType(dm, ctx->cells[0], &ct)); 1107680d18d5SMatthew G. Knepley switch (ct) { 1108d71ae5a4SJacob Faibussowitsch case DM_POLYTOPE_SEGMENT: 1109d71ae5a4SJacob Faibussowitsch PetscCall(DMInterpolate_Segment_Private(ctx, dm, x, v)); 1110d71ae5a4SJacob Faibussowitsch break; 1111d71ae5a4SJacob Faibussowitsch case DM_POLYTOPE_TRIANGLE: 1112d71ae5a4SJacob Faibussowitsch PetscCall(DMInterpolate_Triangle_Private(ctx, dm, x, v)); 1113d71ae5a4SJacob Faibussowitsch break; 1114d71ae5a4SJacob Faibussowitsch case DM_POLYTOPE_QUADRILATERAL: 1115d71ae5a4SJacob Faibussowitsch PetscCall(DMInterpolate_Quad_Private(ctx, dm, x, v)); 1116d71ae5a4SJacob Faibussowitsch break; 1117d71ae5a4SJacob Faibussowitsch case DM_POLYTOPE_TETRAHEDRON: 1118d71ae5a4SJacob Faibussowitsch PetscCall(DMInterpolate_Tetrahedron_Private(ctx, dm, x, v)); 1119d71ae5a4SJacob Faibussowitsch break; 1120d71ae5a4SJacob Faibussowitsch case DM_POLYTOPE_HEXAHEDRON: 1121d71ae5a4SJacob Faibussowitsch PetscCall(DMInterpolate_Hex_Private(ctx, dm, x, v)); 1122d71ae5a4SJacob Faibussowitsch break; 1123d71ae5a4SJacob Faibussowitsch default: 1124d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for cell type %s", DMPolytopeTypes[PetscMax(0, PetscMin(ct, DM_NUM_POLYTOPES))]); 1125680d18d5SMatthew G. Knepley } 1126552f7358SJed Brown } 1127552f7358SJed Brown PetscFunctionReturn(0); 1128552f7358SJed Brown } 1129552f7358SJed Brown 11304267b1a3SMatthew G. Knepley /*@C 1131f6dfbefdSBarry Smith DMInterpolationDestroy - Destroys a `DMInterpolationInfo` context 11324267b1a3SMatthew G. Knepley 1133*c3339decSBarry Smith Collective 11344267b1a3SMatthew G. Knepley 11354267b1a3SMatthew G. Knepley Input Parameter: 11364267b1a3SMatthew G. Knepley . ctx - the context 11374267b1a3SMatthew G. Knepley 11384267b1a3SMatthew G. Knepley Level: beginner 11394267b1a3SMatthew G. Knepley 1140f6dfbefdSBarry Smith .seealso: `DMInterpolationInfo`, `DMInterpolationEvaluate()`, `DMInterpolationAddPoints()`, `DMInterpolationCreate()` 11414267b1a3SMatthew G. Knepley @*/ 1142d71ae5a4SJacob Faibussowitsch PetscErrorCode DMInterpolationDestroy(DMInterpolationInfo *ctx) 1143d71ae5a4SJacob Faibussowitsch { 1144552f7358SJed Brown PetscFunctionBegin; 1145064a246eSJacob Faibussowitsch PetscValidPointer(ctx, 1); 11469566063dSJacob Faibussowitsch PetscCall(VecDestroy(&(*ctx)->coords)); 11479566063dSJacob Faibussowitsch PetscCall(PetscFree((*ctx)->points)); 11489566063dSJacob Faibussowitsch PetscCall(PetscFree((*ctx)->cells)); 11499566063dSJacob Faibussowitsch PetscCall(PetscFree(*ctx)); 11500298fd71SBarry Smith *ctx = NULL; 1151552f7358SJed Brown PetscFunctionReturn(0); 1152552f7358SJed Brown } 1153cc0c4584SMatthew G. Knepley 1154cc0c4584SMatthew G. Knepley /*@C 1155cc0c4584SMatthew G. Knepley SNESMonitorFields - Monitors the residual for each field separately 1156cc0c4584SMatthew G. Knepley 1157*c3339decSBarry Smith Collective 1158cc0c4584SMatthew G. Knepley 1159cc0c4584SMatthew G. Knepley Input Parameters: 1160f6dfbefdSBarry Smith + snes - the `SNES` context 1161cc0c4584SMatthew G. Knepley . its - iteration number 1162cc0c4584SMatthew G. Knepley . fgnorm - 2-norm of residual 1163f6dfbefdSBarry Smith - vf - `PetscViewerAndFormat` of `PetscViewerType` `PETSCVIEWERASCII` 1164cc0c4584SMatthew G. Knepley 1165f6dfbefdSBarry Smith Note: 1166cc0c4584SMatthew G. Knepley This routine prints the residual norm at each iteration. 1167cc0c4584SMatthew G. Knepley 1168cc0c4584SMatthew G. Knepley Level: intermediate 1169cc0c4584SMatthew G. Knepley 1170f6dfbefdSBarry Smith .seealso: `SNES`, `SNESMonitorSet()`, `SNESMonitorDefault()` 1171cc0c4584SMatthew G. Knepley @*/ 1172d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESMonitorFields(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf) 1173d71ae5a4SJacob Faibussowitsch { 1174d43b4f6eSBarry Smith PetscViewer viewer = vf->viewer; 1175cc0c4584SMatthew G. Knepley Vec res; 1176cc0c4584SMatthew G. Knepley DM dm; 1177cc0c4584SMatthew G. Knepley PetscSection s; 1178cc0c4584SMatthew G. Knepley const PetscScalar *r; 1179cc0c4584SMatthew G. Knepley PetscReal *lnorms, *norms; 1180cc0c4584SMatthew G. Knepley PetscInt numFields, f, pStart, pEnd, p; 1181cc0c4584SMatthew G. Knepley 1182cc0c4584SMatthew G. Knepley PetscFunctionBegin; 11834d4332d5SBarry Smith PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4); 11849566063dSJacob Faibussowitsch PetscCall(SNESGetFunction(snes, &res, NULL, NULL)); 11859566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &dm)); 11869566063dSJacob Faibussowitsch PetscCall(DMGetLocalSection(dm, &s)); 11879566063dSJacob Faibussowitsch PetscCall(PetscSectionGetNumFields(s, &numFields)); 11889566063dSJacob Faibussowitsch PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 11899566063dSJacob Faibussowitsch PetscCall(PetscCalloc2(numFields, &lnorms, numFields, &norms)); 11909566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(res, &r)); 1191cc0c4584SMatthew G. Knepley for (p = pStart; p < pEnd; ++p) { 1192cc0c4584SMatthew G. Knepley for (f = 0; f < numFields; ++f) { 1193cc0c4584SMatthew G. Knepley PetscInt fdof, foff, d; 1194cc0c4584SMatthew G. Knepley 11959566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldDof(s, p, f, &fdof)); 11969566063dSJacob Faibussowitsch PetscCall(PetscSectionGetFieldOffset(s, p, f, &foff)); 1197cc0c4584SMatthew G. Knepley for (d = 0; d < fdof; ++d) lnorms[f] += PetscRealPart(PetscSqr(r[foff + d])); 1198cc0c4584SMatthew G. Knepley } 1199cc0c4584SMatthew G. Knepley } 12009566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(res, &r)); 12011c2dc1cbSBarry Smith PetscCall(MPIU_Allreduce(lnorms, norms, numFields, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 12029566063dSJacob Faibussowitsch PetscCall(PetscViewerPushFormat(viewer, vf->format)); 12039566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)snes)->tablevel)); 120463a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "%3" PetscInt_FMT " SNES Function norm %14.12e [", its, (double)fgnorm)); 1205cc0c4584SMatthew G. Knepley for (f = 0; f < numFields; ++f) { 12069566063dSJacob Faibussowitsch if (f > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 12079566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "%14.12e", (double)PetscSqrtReal(norms[f]))); 1208cc0c4584SMatthew G. Knepley } 12099566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(viewer, "]\n")); 12109566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)snes)->tablevel)); 12119566063dSJacob Faibussowitsch PetscCall(PetscViewerPopFormat(viewer)); 12129566063dSJacob Faibussowitsch PetscCall(PetscFree2(lnorms, norms)); 1213cc0c4584SMatthew G. Knepley PetscFunctionReturn(0); 1214cc0c4584SMatthew G. Knepley } 121524cdb843SMatthew G. Knepley 121624cdb843SMatthew G. Knepley /********************* Residual Computation **************************/ 121724cdb843SMatthew G. Knepley 1218d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 1219d71ae5a4SJacob Faibussowitsch { 12206528b96dSMatthew G. Knepley PetscInt depth; 12216528b96dSMatthew G. Knepley 12226528b96dSMatthew G. Knepley PetscFunctionBegin; 12239566063dSJacob Faibussowitsch PetscCall(DMPlexGetDepth(plex, &depth)); 12249566063dSJacob Faibussowitsch PetscCall(DMGetStratumIS(plex, "dim", depth, cellIS)); 12259566063dSJacob Faibussowitsch if (!*cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, cellIS)); 12266528b96dSMatthew G. Knepley PetscFunctionReturn(0); 12276528b96dSMatthew G. Knepley } 12286528b96dSMatthew G. Knepley 122924cdb843SMatthew G. Knepley /*@ 12308db23a53SJed Brown DMPlexSNESComputeResidualFEM - Sums the local residual into vector F from the local input X using pointwise functions specified by the user 123124cdb843SMatthew G. Knepley 123224cdb843SMatthew G. Knepley Input Parameters: 123324cdb843SMatthew G. Knepley + dm - The mesh 123424cdb843SMatthew G. Knepley . X - Local solution 123524cdb843SMatthew G. Knepley - user - The user context 123624cdb843SMatthew G. Knepley 123724cdb843SMatthew G. Knepley Output Parameter: 123824cdb843SMatthew G. Knepley . F - Local output vector 123924cdb843SMatthew G. Knepley 1240f6dfbefdSBarry Smith Note: 1241f6dfbefdSBarry Smith The residual is summed into F; the caller is responsible for using `VecZeroEntries()` or otherwise ensuring that any data in F is intentional. 12428db23a53SJed Brown 124324cdb843SMatthew G. Knepley Level: developer 124424cdb843SMatthew G. Knepley 1245f6dfbefdSBarry Smith .seealso: `DM`, `DMPlexComputeJacobianAction()` 124624cdb843SMatthew G. Knepley @*/ 1247d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSNESComputeResidualFEM(DM dm, Vec X, Vec F, void *user) 1248d71ae5a4SJacob Faibussowitsch { 12496da023fcSToby Isaac DM plex; 1250083401c6SMatthew G. Knepley IS allcellIS; 12516528b96dSMatthew G. Knepley PetscInt Nds, s; 125224cdb843SMatthew G. Knepley 125324cdb843SMatthew G. Knepley PetscFunctionBegin; 12549566063dSJacob Faibussowitsch PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 12559566063dSJacob Faibussowitsch PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS)); 12569566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 12576528b96dSMatthew G. Knepley for (s = 0; s < Nds; ++s) { 12586528b96dSMatthew G. Knepley PetscDS ds; 12596528b96dSMatthew G. Knepley IS cellIS; 126006ad1575SMatthew G. Knepley PetscFormKey key; 12616528b96dSMatthew G. Knepley 12629566063dSJacob Faibussowitsch PetscCall(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds)); 12636528b96dSMatthew G. Knepley key.value = 0; 12646528b96dSMatthew G. Knepley key.field = 0; 126506ad1575SMatthew G. Knepley key.part = 0; 12666528b96dSMatthew G. Knepley if (!key.label) { 12679566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)allcellIS)); 12686528b96dSMatthew G. Knepley cellIS = allcellIS; 12696528b96dSMatthew G. Knepley } else { 12706528b96dSMatthew G. Knepley IS pointIS; 12716528b96dSMatthew G. Knepley 12726528b96dSMatthew G. Knepley key.value = 1; 12739566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 12749566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS)); 12759566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 12766528b96dSMatthew G. Knepley } 12779566063dSJacob Faibussowitsch PetscCall(DMPlexComputeResidual_Internal(plex, key, cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user)); 12789566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 12796528b96dSMatthew G. Knepley } 12809566063dSJacob Faibussowitsch PetscCall(ISDestroy(&allcellIS)); 12819566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 12826528b96dSMatthew G. Knepley PetscFunctionReturn(0); 12836528b96dSMatthew G. Knepley } 12846528b96dSMatthew G. Knepley 1285d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESComputeResidual(DM dm, Vec X, Vec F, void *user) 1286d71ae5a4SJacob Faibussowitsch { 12876528b96dSMatthew G. Knepley DM plex; 12886528b96dSMatthew G. Knepley IS allcellIS; 12896528b96dSMatthew G. Knepley PetscInt Nds, s; 12906528b96dSMatthew G. Knepley 12916528b96dSMatthew G. Knepley PetscFunctionBegin; 12929566063dSJacob Faibussowitsch PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 12939566063dSJacob Faibussowitsch PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS)); 12949566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 1295083401c6SMatthew G. Knepley for (s = 0; s < Nds; ++s) { 1296083401c6SMatthew G. Knepley PetscDS ds; 1297083401c6SMatthew G. Knepley DMLabel label; 1298083401c6SMatthew G. Knepley IS cellIS; 1299083401c6SMatthew G. Knepley 13009566063dSJacob Faibussowitsch PetscCall(DMGetRegionNumDS(dm, s, &label, NULL, &ds)); 13016528b96dSMatthew G. Knepley { 130206ad1575SMatthew G. Knepley PetscWeakFormKind resmap[2] = {PETSC_WF_F0, PETSC_WF_F1}; 13036528b96dSMatthew G. Knepley PetscWeakForm wf; 13046528b96dSMatthew G. Knepley PetscInt Nm = 2, m, Nk = 0, k, kp, off = 0; 130506ad1575SMatthew G. Knepley PetscFormKey *reskeys; 13066528b96dSMatthew G. Knepley 13076528b96dSMatthew G. Knepley /* Get unique residual keys */ 13086528b96dSMatthew G. Knepley for (m = 0; m < Nm; ++m) { 13096528b96dSMatthew G. Knepley PetscInt Nkm; 13109566063dSJacob Faibussowitsch PetscCall(PetscHMapFormGetSize(ds->wf->form[resmap[m]], &Nkm)); 13116528b96dSMatthew G. Knepley Nk += Nkm; 13126528b96dSMatthew G. Knepley } 13139566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nk, &reskeys)); 131448a46eb9SPierre Jolivet for (m = 0; m < Nm; ++m) PetscCall(PetscHMapFormGetKeys(ds->wf->form[resmap[m]], &off, reskeys)); 131563a3b9bcSJacob Faibussowitsch PetscCheck(off == Nk, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %" PetscInt_FMT " should be %" PetscInt_FMT, off, Nk); 13169566063dSJacob Faibussowitsch PetscCall(PetscFormKeySort(Nk, reskeys)); 13176528b96dSMatthew G. Knepley for (k = 0, kp = 1; kp < Nk; ++kp) { 13186528b96dSMatthew G. Knepley if ((reskeys[k].label != reskeys[kp].label) || (reskeys[k].value != reskeys[kp].value)) { 13196528b96dSMatthew G. Knepley ++k; 13206528b96dSMatthew G. Knepley if (kp != k) reskeys[k] = reskeys[kp]; 13216528b96dSMatthew G. Knepley } 13226528b96dSMatthew G. Knepley } 13236528b96dSMatthew G. Knepley Nk = k; 13246528b96dSMatthew G. Knepley 13259566063dSJacob Faibussowitsch PetscCall(PetscDSGetWeakForm(ds, &wf)); 13266528b96dSMatthew G. Knepley for (k = 0; k < Nk; ++k) { 13276528b96dSMatthew G. Knepley DMLabel label = reskeys[k].label; 13286528b96dSMatthew G. Knepley PetscInt val = reskeys[k].value; 13296528b96dSMatthew G. Knepley 1330083401c6SMatthew G. Knepley if (!label) { 13319566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)allcellIS)); 1332083401c6SMatthew G. Knepley cellIS = allcellIS; 1333083401c6SMatthew G. Knepley } else { 1334083401c6SMatthew G. Knepley IS pointIS; 1335083401c6SMatthew G. Knepley 13369566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, val, &pointIS)); 13379566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS)); 13389566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 13394a3e9fdbSToby Isaac } 13409566063dSJacob Faibussowitsch PetscCall(DMPlexComputeResidual_Internal(plex, reskeys[k], cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user)); 13419566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 1342083401c6SMatthew G. Knepley } 13439566063dSJacob Faibussowitsch PetscCall(PetscFree(reskeys)); 13446528b96dSMatthew G. Knepley } 13456528b96dSMatthew G. Knepley } 13469566063dSJacob Faibussowitsch PetscCall(ISDestroy(&allcellIS)); 13479566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 134824cdb843SMatthew G. Knepley PetscFunctionReturn(0); 134924cdb843SMatthew G. Knepley } 135024cdb843SMatthew G. Knepley 1351bdd6f66aSToby Isaac /*@ 1352bdd6f66aSToby Isaac DMPlexSNESComputeBoundaryFEM - Form the boundary values for the local input X 1353bdd6f66aSToby Isaac 1354bdd6f66aSToby Isaac Input Parameters: 1355bdd6f66aSToby Isaac + dm - The mesh 1356bdd6f66aSToby Isaac - user - The user context 1357bdd6f66aSToby Isaac 1358bdd6f66aSToby Isaac Output Parameter: 1359bdd6f66aSToby Isaac . X - Local solution 1360bdd6f66aSToby Isaac 1361bdd6f66aSToby Isaac Level: developer 1362bdd6f66aSToby Isaac 1363f6dfbefdSBarry Smith .seealso: `DMPLEX`, `DMPlexComputeJacobianAction()` 1364bdd6f66aSToby Isaac @*/ 1365d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSNESComputeBoundaryFEM(DM dm, Vec X, void *user) 1366d71ae5a4SJacob Faibussowitsch { 1367bdd6f66aSToby Isaac DM plex; 1368bdd6f66aSToby Isaac 1369bdd6f66aSToby Isaac PetscFunctionBegin; 13709566063dSJacob Faibussowitsch PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 13719566063dSJacob Faibussowitsch PetscCall(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, X, PETSC_MIN_REAL, NULL, NULL, NULL)); 13729566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 1373bdd6f66aSToby Isaac PetscFunctionReturn(0); 1374bdd6f66aSToby Isaac } 1375bdd6f66aSToby Isaac 13767a73cf09SMatthew G. Knepley /*@ 13778e3a2eefSMatthew G. Knepley DMSNESComputeJacobianAction - Compute the action of the Jacobian J(X) on Y 13787a73cf09SMatthew G. Knepley 13797a73cf09SMatthew G. Knepley Input Parameters: 1380f6dfbefdSBarry Smith + dm - The `DM` 13817a73cf09SMatthew G. Knepley . X - Local solution vector 13827a73cf09SMatthew G. Knepley . Y - Local input vector 13837a73cf09SMatthew G. Knepley - user - The user context 13847a73cf09SMatthew G. Knepley 13857a73cf09SMatthew G. Knepley Output Parameter: 13868e3a2eefSMatthew G. Knepley . F - lcoal output vector 13877a73cf09SMatthew G. Knepley 13887a73cf09SMatthew G. Knepley Level: developer 13897a73cf09SMatthew G. Knepley 13908e3a2eefSMatthew G. Knepley Notes: 1391f6dfbefdSBarry Smith Users will typically use `DMSNESCreateJacobianMF()` followed by `MatMult()` instead of calling this routine directly. 13928e3a2eefSMatthew G. Knepley 1393f6dfbefdSBarry Smith .seealso: `DM`, ``DMSNESCreateJacobianMF()`, `DMPlexSNESComputeResidualFEM()` 13947a73cf09SMatthew G. Knepley @*/ 1395d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESComputeJacobianAction(DM dm, Vec X, Vec Y, Vec F, void *user) 1396d71ae5a4SJacob Faibussowitsch { 13978e3a2eefSMatthew G. Knepley DM plex; 13988e3a2eefSMatthew G. Knepley IS allcellIS; 13998e3a2eefSMatthew G. Knepley PetscInt Nds, s; 1400a925c78cSMatthew G. Knepley 1401a925c78cSMatthew G. Knepley PetscFunctionBegin; 14029566063dSJacob Faibussowitsch PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 14039566063dSJacob Faibussowitsch PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS)); 14049566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 14058e3a2eefSMatthew G. Knepley for (s = 0; s < Nds; ++s) { 14068e3a2eefSMatthew G. Knepley PetscDS ds; 14078e3a2eefSMatthew G. Knepley DMLabel label; 14088e3a2eefSMatthew G. Knepley IS cellIS; 14097a73cf09SMatthew G. Knepley 14109566063dSJacob Faibussowitsch PetscCall(DMGetRegionNumDS(dm, s, &label, NULL, &ds)); 14118e3a2eefSMatthew G. Knepley { 141206ad1575SMatthew G. Knepley PetscWeakFormKind jacmap[4] = {PETSC_WF_G0, PETSC_WF_G1, PETSC_WF_G2, PETSC_WF_G3}; 14138e3a2eefSMatthew G. Knepley PetscWeakForm wf; 14148e3a2eefSMatthew G. Knepley PetscInt Nm = 4, m, Nk = 0, k, kp, off = 0; 141506ad1575SMatthew G. Knepley PetscFormKey *jackeys; 14168e3a2eefSMatthew G. Knepley 14178e3a2eefSMatthew G. Knepley /* Get unique Jacobian keys */ 14188e3a2eefSMatthew G. Knepley for (m = 0; m < Nm; ++m) { 14198e3a2eefSMatthew G. Knepley PetscInt Nkm; 14209566063dSJacob Faibussowitsch PetscCall(PetscHMapFormGetSize(ds->wf->form[jacmap[m]], &Nkm)); 14218e3a2eefSMatthew G. Knepley Nk += Nkm; 14228e3a2eefSMatthew G. Knepley } 14239566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nk, &jackeys)); 142448a46eb9SPierre Jolivet for (m = 0; m < Nm; ++m) PetscCall(PetscHMapFormGetKeys(ds->wf->form[jacmap[m]], &off, jackeys)); 142563a3b9bcSJacob Faibussowitsch PetscCheck(off == Nk, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %" PetscInt_FMT " should be %" PetscInt_FMT, off, Nk); 14269566063dSJacob Faibussowitsch PetscCall(PetscFormKeySort(Nk, jackeys)); 14278e3a2eefSMatthew G. Knepley for (k = 0, kp = 1; kp < Nk; ++kp) { 14288e3a2eefSMatthew G. Knepley if ((jackeys[k].label != jackeys[kp].label) || (jackeys[k].value != jackeys[kp].value)) { 14298e3a2eefSMatthew G. Knepley ++k; 14308e3a2eefSMatthew G. Knepley if (kp != k) jackeys[k] = jackeys[kp]; 14318e3a2eefSMatthew G. Knepley } 14328e3a2eefSMatthew G. Knepley } 14338e3a2eefSMatthew G. Knepley Nk = k; 14348e3a2eefSMatthew G. Knepley 14359566063dSJacob Faibussowitsch PetscCall(PetscDSGetWeakForm(ds, &wf)); 14368e3a2eefSMatthew G. Knepley for (k = 0; k < Nk; ++k) { 14378e3a2eefSMatthew G. Knepley DMLabel label = jackeys[k].label; 14388e3a2eefSMatthew G. Knepley PetscInt val = jackeys[k].value; 14398e3a2eefSMatthew G. Knepley 14408e3a2eefSMatthew G. Knepley if (!label) { 14419566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)allcellIS)); 14428e3a2eefSMatthew G. Knepley cellIS = allcellIS; 14437a73cf09SMatthew G. Knepley } else { 14448e3a2eefSMatthew G. Knepley IS pointIS; 1445a925c78cSMatthew G. Knepley 14469566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(label, val, &pointIS)); 14479566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS)); 14489566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 1449a925c78cSMatthew G. Knepley } 14509566063dSJacob Faibussowitsch PetscCall(DMPlexComputeJacobian_Action_Internal(plex, jackeys[k], cellIS, 0.0, 0.0, X, NULL, Y, F, user)); 14519566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 14528e3a2eefSMatthew G. Knepley } 14539566063dSJacob Faibussowitsch PetscCall(PetscFree(jackeys)); 14548e3a2eefSMatthew G. Knepley } 14558e3a2eefSMatthew G. Knepley } 14569566063dSJacob Faibussowitsch PetscCall(ISDestroy(&allcellIS)); 14579566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 1458a925c78cSMatthew G. Knepley PetscFunctionReturn(0); 1459a925c78cSMatthew G. Knepley } 1460a925c78cSMatthew G. Knepley 146124cdb843SMatthew G. Knepley /*@ 146224cdb843SMatthew G. Knepley DMPlexSNESComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user. 146324cdb843SMatthew G. Knepley 146424cdb843SMatthew G. Knepley Input Parameters: 146524cdb843SMatthew G. Knepley + dm - The mesh 146624cdb843SMatthew G. Knepley . X - Local input vector 146724cdb843SMatthew G. Knepley - user - The user context 146824cdb843SMatthew G. Knepley 146924cdb843SMatthew G. Knepley Output Parameter: 147024cdb843SMatthew G. Knepley . Jac - Jacobian matrix 147124cdb843SMatthew G. Knepley 147224cdb843SMatthew G. Knepley Note: 147324cdb843SMatthew G. Knepley We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator, 147424cdb843SMatthew G. Knepley like a GPU, or vectorize on a multicore machine. 147524cdb843SMatthew G. Knepley 147624cdb843SMatthew G. Knepley Level: developer 147724cdb843SMatthew G. Knepley 1478f6dfbefdSBarry Smith .seealso: `DMPLEX`, `Mat` 147924cdb843SMatthew G. Knepley @*/ 1480d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSNESComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, void *user) 1481d71ae5a4SJacob Faibussowitsch { 14826da023fcSToby Isaac DM plex; 1483083401c6SMatthew G. Knepley IS allcellIS; 1484f04eb4edSMatthew G. Knepley PetscBool hasJac, hasPrec; 14856528b96dSMatthew G. Knepley PetscInt Nds, s; 148624cdb843SMatthew G. Knepley 148724cdb843SMatthew G. Knepley PetscFunctionBegin; 14889566063dSJacob Faibussowitsch PetscCall(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 14899566063dSJacob Faibussowitsch PetscCall(DMPlexGetAllCells_Internal(plex, &allcellIS)); 14909566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 1491083401c6SMatthew G. Knepley for (s = 0; s < Nds; ++s) { 1492083401c6SMatthew G. Knepley PetscDS ds; 1493083401c6SMatthew G. Knepley IS cellIS; 149406ad1575SMatthew G. Knepley PetscFormKey key; 1495083401c6SMatthew G. Knepley 14969566063dSJacob Faibussowitsch PetscCall(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds)); 14976528b96dSMatthew G. Knepley key.value = 0; 14986528b96dSMatthew G. Knepley key.field = 0; 149906ad1575SMatthew G. Knepley key.part = 0; 15006528b96dSMatthew G. Knepley if (!key.label) { 15019566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)allcellIS)); 1502083401c6SMatthew G. Knepley cellIS = allcellIS; 1503083401c6SMatthew G. Knepley } else { 1504083401c6SMatthew G. Knepley IS pointIS; 1505083401c6SMatthew G. Knepley 15066528b96dSMatthew G. Knepley key.value = 1; 15079566063dSJacob Faibussowitsch PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 15089566063dSJacob Faibussowitsch PetscCall(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS)); 15099566063dSJacob Faibussowitsch PetscCall(ISDestroy(&pointIS)); 1510083401c6SMatthew G. Knepley } 1511083401c6SMatthew G. Knepley if (!s) { 15129566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(ds, &hasJac)); 15139566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(ds, &hasPrec)); 15149566063dSJacob Faibussowitsch if (hasJac && hasPrec) PetscCall(MatZeroEntries(Jac)); 15159566063dSJacob Faibussowitsch PetscCall(MatZeroEntries(JacP)); 1516083401c6SMatthew G. Knepley } 15179566063dSJacob Faibussowitsch PetscCall(DMPlexComputeJacobian_Internal(plex, key, cellIS, 0.0, 0.0, X, NULL, Jac, JacP, user)); 15189566063dSJacob Faibussowitsch PetscCall(ISDestroy(&cellIS)); 1519083401c6SMatthew G. Knepley } 15209566063dSJacob Faibussowitsch PetscCall(ISDestroy(&allcellIS)); 15219566063dSJacob Faibussowitsch PetscCall(DMDestroy(&plex)); 152224cdb843SMatthew G. Knepley PetscFunctionReturn(0); 152324cdb843SMatthew G. Knepley } 15241878804aSMatthew G. Knepley 15259371c9d4SSatish Balay struct _DMSNESJacobianMFCtx { 15268e3a2eefSMatthew G. Knepley DM dm; 15278e3a2eefSMatthew G. Knepley Vec X; 15288e3a2eefSMatthew G. Knepley void *ctx; 15298e3a2eefSMatthew G. Knepley }; 15308e3a2eefSMatthew G. Knepley 1531d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESJacobianMF_Destroy_Private(Mat A) 1532d71ae5a4SJacob Faibussowitsch { 15338e3a2eefSMatthew G. Knepley struct _DMSNESJacobianMFCtx *ctx; 15348e3a2eefSMatthew G. Knepley 15358e3a2eefSMatthew G. Knepley PetscFunctionBegin; 15369566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &ctx)); 15379566063dSJacob Faibussowitsch PetscCall(MatShellSetContext(A, NULL)); 15389566063dSJacob Faibussowitsch PetscCall(DMDestroy(&ctx->dm)); 15399566063dSJacob Faibussowitsch PetscCall(VecDestroy(&ctx->X)); 15409566063dSJacob Faibussowitsch PetscCall(PetscFree(ctx)); 15418e3a2eefSMatthew G. Knepley PetscFunctionReturn(0); 15428e3a2eefSMatthew G. Knepley } 15438e3a2eefSMatthew G. Knepley 1544d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSNESJacobianMF_Mult_Private(Mat A, Vec Y, Vec Z) 1545d71ae5a4SJacob Faibussowitsch { 15468e3a2eefSMatthew G. Knepley struct _DMSNESJacobianMFCtx *ctx; 15478e3a2eefSMatthew G. Knepley 15488e3a2eefSMatthew G. Knepley PetscFunctionBegin; 15499566063dSJacob Faibussowitsch PetscCall(MatShellGetContext(A, &ctx)); 15509566063dSJacob Faibussowitsch PetscCall(DMSNESComputeJacobianAction(ctx->dm, ctx->X, Y, Z, ctx->ctx)); 15518e3a2eefSMatthew G. Knepley PetscFunctionReturn(0); 15528e3a2eefSMatthew G. Knepley } 15538e3a2eefSMatthew G. Knepley 15548e3a2eefSMatthew G. Knepley /*@ 1555f6dfbefdSBarry Smith DMSNESCreateJacobianMF - Create a `Mat` which computes the action of the Jacobian matrix-free 15568e3a2eefSMatthew G. Knepley 1557*c3339decSBarry Smith Collective 15588e3a2eefSMatthew G. Knepley 15598e3a2eefSMatthew G. Knepley Input Parameters: 1560f6dfbefdSBarry Smith + dm - The `DM` 15618e3a2eefSMatthew G. Knepley . X - The evaluation point for the Jacobian 15628e3a2eefSMatthew G. Knepley - user - A user context, or NULL 15638e3a2eefSMatthew G. Knepley 15648e3a2eefSMatthew G. Knepley Output Parameter: 1565f6dfbefdSBarry Smith . J - The `Mat` 15668e3a2eefSMatthew G. Knepley 15678e3a2eefSMatthew G. Knepley Level: advanced 15688e3a2eefSMatthew G. Knepley 1569f6dfbefdSBarry Smith Note: 1570f6dfbefdSBarry Smith Vec X is kept in `Mat` J, so updating X then updates the evaluation point. 15718e3a2eefSMatthew G. Knepley 1572f6dfbefdSBarry Smith .seealso: `DM`, `DMSNESComputeJacobianAction()` 15738e3a2eefSMatthew G. Knepley @*/ 1574d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCreateJacobianMF(DM dm, Vec X, void *user, Mat *J) 1575d71ae5a4SJacob Faibussowitsch { 15768e3a2eefSMatthew G. Knepley struct _DMSNESJacobianMFCtx *ctx; 15778e3a2eefSMatthew G. Knepley PetscInt n, N; 15788e3a2eefSMatthew G. Knepley 15798e3a2eefSMatthew G. Knepley PetscFunctionBegin; 15809566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)dm), J)); 15819566063dSJacob Faibussowitsch PetscCall(MatSetType(*J, MATSHELL)); 15829566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(X, &n)); 15839566063dSJacob Faibussowitsch PetscCall(VecGetSize(X, &N)); 15849566063dSJacob Faibussowitsch PetscCall(MatSetSizes(*J, n, n, N, N)); 15859566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)dm)); 15869566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)X)); 15879566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(1, &ctx)); 15888e3a2eefSMatthew G. Knepley ctx->dm = dm; 15898e3a2eefSMatthew G. Knepley ctx->X = X; 15908e3a2eefSMatthew G. Knepley ctx->ctx = user; 15919566063dSJacob Faibussowitsch PetscCall(MatShellSetContext(*J, ctx)); 15929566063dSJacob Faibussowitsch PetscCall(MatShellSetOperation(*J, MATOP_DESTROY, (void (*)(void))DMSNESJacobianMF_Destroy_Private)); 15939566063dSJacob Faibussowitsch PetscCall(MatShellSetOperation(*J, MATOP_MULT, (void (*)(void))DMSNESJacobianMF_Mult_Private)); 15948e3a2eefSMatthew G. Knepley PetscFunctionReturn(0); 15958e3a2eefSMatthew G. Knepley } 15968e3a2eefSMatthew G. Knepley 159738cfc46eSPierre Jolivet /* 159838cfc46eSPierre Jolivet MatComputeNeumannOverlap - Computes an unassembled (Neumann) local overlapping Mat in nonlinear context. 159938cfc46eSPierre Jolivet 160038cfc46eSPierre Jolivet Input Parameters: 160138cfc46eSPierre Jolivet + X - SNES linearization point 160238cfc46eSPierre Jolivet . ovl - index set of overlapping subdomains 160338cfc46eSPierre Jolivet 160438cfc46eSPierre Jolivet Output Parameter: 160538cfc46eSPierre Jolivet . J - unassembled (Neumann) local matrix 160638cfc46eSPierre Jolivet 160738cfc46eSPierre Jolivet Level: intermediate 160838cfc46eSPierre Jolivet 1609db781477SPatrick Sanan .seealso: `DMCreateNeumannOverlap()`, `MATIS`, `PCHPDDMSetAuxiliaryMat()` 161038cfc46eSPierre Jolivet */ 1611d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatComputeNeumannOverlap_Plex(Mat J, PetscReal t, Vec X, Vec X_t, PetscReal s, IS ovl, void *ctx) 1612d71ae5a4SJacob Faibussowitsch { 161338cfc46eSPierre Jolivet SNES snes; 161438cfc46eSPierre Jolivet Mat pJ; 161538cfc46eSPierre Jolivet DM ovldm, origdm; 161638cfc46eSPierre Jolivet DMSNES sdm; 161738cfc46eSPierre Jolivet PetscErrorCode (*bfun)(DM, Vec, void *); 161838cfc46eSPierre Jolivet PetscErrorCode (*jfun)(DM, Vec, Mat, Mat, void *); 161938cfc46eSPierre Jolivet void *bctx, *jctx; 162038cfc46eSPierre Jolivet 162138cfc46eSPierre Jolivet PetscFunctionBegin; 16229566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Overlap_HPDDM_MATIS", (PetscObject *)&pJ)); 162328b400f6SJacob Faibussowitsch PetscCheck(pJ, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing overlapping Mat"); 16249566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Original_HPDDM", (PetscObject *)&origdm)); 162528b400f6SJacob Faibussowitsch PetscCheck(origdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing original DM"); 16269566063dSJacob Faibussowitsch PetscCall(MatGetDM(pJ, &ovldm)); 16279566063dSJacob Faibussowitsch PetscCall(DMSNESGetBoundaryLocal(origdm, &bfun, &bctx)); 16289566063dSJacob Faibussowitsch PetscCall(DMSNESSetBoundaryLocal(ovldm, bfun, bctx)); 16299566063dSJacob Faibussowitsch PetscCall(DMSNESGetJacobianLocal(origdm, &jfun, &jctx)); 16309566063dSJacob Faibussowitsch PetscCall(DMSNESSetJacobianLocal(ovldm, jfun, jctx)); 16319566063dSJacob Faibussowitsch PetscCall(PetscObjectQuery((PetscObject)ovl, "_DM_Overlap_HPDDM_SNES", (PetscObject *)&snes)); 163238cfc46eSPierre Jolivet if (!snes) { 16339566063dSJacob Faibussowitsch PetscCall(SNESCreate(PetscObjectComm((PetscObject)ovl), &snes)); 16349566063dSJacob Faibussowitsch PetscCall(SNESSetDM(snes, ovldm)); 16359566063dSJacob Faibussowitsch PetscCall(PetscObjectCompose((PetscObject)ovl, "_DM_Overlap_HPDDM_SNES", (PetscObject)snes)); 16369566063dSJacob Faibussowitsch PetscCall(PetscObjectDereference((PetscObject)snes)); 163738cfc46eSPierre Jolivet } 16389566063dSJacob Faibussowitsch PetscCall(DMGetDMSNES(ovldm, &sdm)); 16399566063dSJacob Faibussowitsch PetscCall(VecLockReadPush(X)); 1640800f99ffSJeremy L Thompson { 1641800f99ffSJeremy L Thompson void *ctx; 1642800f99ffSJeremy L Thompson PetscErrorCode (*J)(SNES, Vec, Mat, Mat, void *); 1643800f99ffSJeremy L Thompson PetscCall(DMSNESGetJacobian(ovldm, &J, &ctx)); 1644800f99ffSJeremy L Thompson PetscCallBack("SNES callback Jacobian", (*J)(snes, X, pJ, pJ, ctx)); 1645800f99ffSJeremy L Thompson } 16469566063dSJacob Faibussowitsch PetscCall(VecLockReadPop(X)); 164738cfc46eSPierre Jolivet /* this is a no-hop, just in case we decide to change the placeholder for the local Neumann matrix */ 164838cfc46eSPierre Jolivet { 164938cfc46eSPierre Jolivet Mat locpJ; 165038cfc46eSPierre Jolivet 16519566063dSJacob Faibussowitsch PetscCall(MatISGetLocalMat(pJ, &locpJ)); 16529566063dSJacob Faibussowitsch PetscCall(MatCopy(locpJ, J, SAME_NONZERO_PATTERN)); 165338cfc46eSPierre Jolivet } 165438cfc46eSPierre Jolivet PetscFunctionReturn(0); 165538cfc46eSPierre Jolivet } 165638cfc46eSPierre Jolivet 1657a925c78cSMatthew G. Knepley /*@ 1658f6dfbefdSBarry Smith DMPlexSetSNESLocalFEM - Use `DMPLEX`'s internal FEM routines to compute `SNES` boundary values, residual, and Jacobian. 16599f520fc2SToby Isaac 16609f520fc2SToby Isaac Input Parameters: 1661f6dfbefdSBarry Smith + dm - The `DM` object 1662f6dfbefdSBarry Smith . boundaryctx - the user context that will be passed to pointwise evaluation of boundary values (see `PetscDSAddBoundary()`) 1663f6dfbefdSBarry Smith . residualctx - the user context that will be passed to pointwise evaluation of finite element residual computations (see `PetscDSSetResidual()`) 1664f6dfbefdSBarry Smith - jacobianctx - the user context that will be passed to pointwise evaluation of finite element Jacobian construction (see `PetscDSSetJacobian()`) 16651a244344SSatish Balay 16661a244344SSatish Balay Level: developer 1667f6dfbefdSBarry Smith 1668f6dfbefdSBarry Smith .seealso: `DMPLEX`, `SNES` 16699f520fc2SToby Isaac @*/ 1670d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexSetSNESLocalFEM(DM dm, void *boundaryctx, void *residualctx, void *jacobianctx) 1671d71ae5a4SJacob Faibussowitsch { 16729f520fc2SToby Isaac PetscFunctionBegin; 16739566063dSJacob Faibussowitsch PetscCall(DMSNESSetBoundaryLocal(dm, DMPlexSNESComputeBoundaryFEM, boundaryctx)); 16749566063dSJacob Faibussowitsch PetscCall(DMSNESSetFunctionLocal(dm, DMPlexSNESComputeResidualFEM, residualctx)); 16759566063dSJacob Faibussowitsch PetscCall(DMSNESSetJacobianLocal(dm, DMPlexSNESComputeJacobianFEM, jacobianctx)); 16769566063dSJacob Faibussowitsch PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", MatComputeNeumannOverlap_Plex)); 16779f520fc2SToby Isaac PetscFunctionReturn(0); 16789f520fc2SToby Isaac } 16799f520fc2SToby Isaac 1680f017bcb6SMatthew G. Knepley /*@C 1681f017bcb6SMatthew G. Knepley DMSNESCheckDiscretization - Check the discretization error of the exact solution 1682f017bcb6SMatthew G. Knepley 1683f017bcb6SMatthew G. Knepley Input Parameters: 1684f6dfbefdSBarry Smith + snes - the `SNES` object 1685f6dfbefdSBarry Smith . dm - the `DM` 1686f2cacb80SMatthew G. Knepley . t - the time 1687f6dfbefdSBarry Smith . u - a `DM` vector 1688f0fc11ceSJed Brown - tol - A tolerance for the check, or -1 to print the results instead 1689f017bcb6SMatthew G. Knepley 1690f3c94560SMatthew G. Knepley Output Parameters: 1691f3c94560SMatthew G. Knepley . error - An array which holds the discretization error in each field, or NULL 1692f3c94560SMatthew G. Knepley 1693f6dfbefdSBarry Smith Note: 1694f6dfbefdSBarry Smith The user must call `PetscDSSetExactSolution()` beforehand 16957f96f943SMatthew G. Knepley 1696f017bcb6SMatthew G. Knepley Level: developer 1697f017bcb6SMatthew G. Knepley 1698f6dfbefdSBarry Smith .seealso: `PetscDSSetExactSolution()`, `DNSNESCheckFromOptions()`, `DMSNESCheckResidual()`, `DMSNESCheckJacobian()`, `PetscDSSetExactSolution()` 1699f017bcb6SMatthew G. Knepley @*/ 1700d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckDiscretization(SNES snes, DM dm, PetscReal t, Vec u, PetscReal tol, PetscReal error[]) 1701d71ae5a4SJacob Faibussowitsch { 1702f017bcb6SMatthew G. Knepley PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx); 1703f017bcb6SMatthew G. Knepley void **ectxs; 1704f3c94560SMatthew G. Knepley PetscReal *err; 17057f96f943SMatthew G. Knepley MPI_Comm comm; 17067f96f943SMatthew G. Knepley PetscInt Nf, f; 17071878804aSMatthew G. Knepley 17081878804aSMatthew G. Knepley PetscFunctionBegin; 1709f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 1710f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 1711064a246eSJacob Faibussowitsch PetscValidHeaderSpecific(u, VEC_CLASSID, 4); 1712534a8f05SLisandro Dalcin if (error) PetscValidRealPointer(error, 6); 17137f96f943SMatthew G. Knepley 17149566063dSJacob Faibussowitsch PetscCall(DMComputeExactSolution(dm, t, u, NULL)); 17159566063dSJacob Faibussowitsch PetscCall(VecViewFromOptions(u, NULL, "-vec_view")); 17167f96f943SMatthew G. Knepley 17179566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)snes, &comm)); 17189566063dSJacob Faibussowitsch PetscCall(DMGetNumFields(dm, &Nf)); 17199566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(Nf, &exacts, Nf, &ectxs, PetscMax(1, Nf), &err)); 17207f96f943SMatthew G. Knepley { 17217f96f943SMatthew G. Knepley PetscInt Nds, s; 17227f96f943SMatthew G. Knepley 17239566063dSJacob Faibussowitsch PetscCall(DMGetNumDS(dm, &Nds)); 1724083401c6SMatthew G. Knepley for (s = 0; s < Nds; ++s) { 17257f96f943SMatthew G. Knepley PetscDS ds; 1726083401c6SMatthew G. Knepley DMLabel label; 1727083401c6SMatthew G. Knepley IS fieldIS; 17287f96f943SMatthew G. Knepley const PetscInt *fields; 17297f96f943SMatthew G. Knepley PetscInt dsNf, f; 1730083401c6SMatthew G. Knepley 17319566063dSJacob Faibussowitsch PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds)); 17329566063dSJacob Faibussowitsch PetscCall(PetscDSGetNumFields(ds, &dsNf)); 17339566063dSJacob Faibussowitsch PetscCall(ISGetIndices(fieldIS, &fields)); 1734083401c6SMatthew G. Knepley for (f = 0; f < dsNf; ++f) { 1735083401c6SMatthew G. Knepley const PetscInt field = fields[f]; 17369566063dSJacob Faibussowitsch PetscCall(PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field])); 1737083401c6SMatthew G. Knepley } 17389566063dSJacob Faibussowitsch PetscCall(ISRestoreIndices(fieldIS, &fields)); 1739083401c6SMatthew G. Knepley } 1740083401c6SMatthew G. Knepley } 1741f017bcb6SMatthew G. Knepley if (Nf > 1) { 17429566063dSJacob Faibussowitsch PetscCall(DMComputeL2FieldDiff(dm, t, exacts, ectxs, u, err)); 1743f017bcb6SMatthew G. Knepley if (tol >= 0.0) { 1744ad540459SPierre 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); 1745b878532fSMatthew G. Knepley } else if (error) { 1746b878532fSMatthew G. Knepley for (f = 0; f < Nf; ++f) error[f] = err[f]; 17471878804aSMatthew G. Knepley } else { 17489566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "L_2 Error: [")); 1749f017bcb6SMatthew G. Knepley for (f = 0; f < Nf; ++f) { 17509566063dSJacob Faibussowitsch if (f) PetscCall(PetscPrintf(comm, ", ")); 17519566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "%g", (double)err[f])); 17521878804aSMatthew G. Knepley } 17539566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "]\n")); 1754f017bcb6SMatthew G. Knepley } 1755f017bcb6SMatthew G. Knepley } else { 17569566063dSJacob Faibussowitsch PetscCall(DMComputeL2Diff(dm, t, exacts, ectxs, u, &err[0])); 1757f017bcb6SMatthew G. Knepley if (tol >= 0.0) { 175808401ef6SPierre Jolivet PetscCheck(err[0] <= tol, comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g exceeds tolerance %g", (double)err[0], (double)tol); 1759b878532fSMatthew G. Knepley } else if (error) { 1760b878532fSMatthew G. Knepley error[0] = err[0]; 1761f017bcb6SMatthew G. Knepley } else { 17629566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "L_2 Error: %g\n", (double)err[0])); 1763f017bcb6SMatthew G. Knepley } 1764f017bcb6SMatthew G. Knepley } 17659566063dSJacob Faibussowitsch PetscCall(PetscFree3(exacts, ectxs, err)); 1766f017bcb6SMatthew G. Knepley PetscFunctionReturn(0); 1767f017bcb6SMatthew G. Knepley } 1768f017bcb6SMatthew G. Knepley 1769f017bcb6SMatthew G. Knepley /*@C 1770f017bcb6SMatthew G. Knepley DMSNESCheckResidual - Check the residual of the exact solution 1771f017bcb6SMatthew G. Knepley 1772f017bcb6SMatthew G. Knepley Input Parameters: 1773f6dfbefdSBarry Smith + snes - the `SNES` object 1774f6dfbefdSBarry Smith . dm - the `DM` 1775f6dfbefdSBarry Smith . u - a `DM` vector 1776f0fc11ceSJed Brown - tol - A tolerance for the check, or -1 to print the results instead 1777f017bcb6SMatthew G. Knepley 1778f6dfbefdSBarry Smith Output Parameter: 1779f3c94560SMatthew G. Knepley . residual - The residual norm of the exact solution, or NULL 1780f3c94560SMatthew G. Knepley 1781f017bcb6SMatthew G. Knepley Level: developer 1782f017bcb6SMatthew G. Knepley 1783db781477SPatrick Sanan .seealso: `DNSNESCheckFromOptions()`, `DMSNESCheckDiscretization()`, `DMSNESCheckJacobian()` 1784f017bcb6SMatthew G. Knepley @*/ 1785d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckResidual(SNES snes, DM dm, Vec u, PetscReal tol, PetscReal *residual) 1786d71ae5a4SJacob Faibussowitsch { 1787f017bcb6SMatthew G. Knepley MPI_Comm comm; 1788f017bcb6SMatthew G. Knepley Vec r; 1789f017bcb6SMatthew G. Knepley PetscReal res; 1790f017bcb6SMatthew G. Knepley 1791f017bcb6SMatthew G. Knepley PetscFunctionBegin; 1792f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 1793f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 1794f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(u, VEC_CLASSID, 3); 1795534a8f05SLisandro Dalcin if (residual) PetscValidRealPointer(residual, 5); 17969566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)snes, &comm)); 17979566063dSJacob Faibussowitsch PetscCall(DMComputeExactSolution(dm, 0.0, u, NULL)); 17989566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &r)); 17999566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes, u, r)); 18009566063dSJacob Faibussowitsch PetscCall(VecNorm(r, NORM_2, &res)); 1801f017bcb6SMatthew G. Knepley if (tol >= 0.0) { 180208401ef6SPierre Jolivet PetscCheck(res <= tol, comm, PETSC_ERR_ARG_WRONG, "L_2 Residual %g exceeds tolerance %g", (double)res, (double)tol); 1803b878532fSMatthew G. Knepley } else if (residual) { 1804b878532fSMatthew G. Knepley *residual = res; 1805f017bcb6SMatthew G. Knepley } else { 18069566063dSJacob Faibussowitsch PetscCall(PetscPrintf(comm, "L_2 Residual: %g\n", (double)res)); 18079566063dSJacob Faibussowitsch PetscCall(VecChop(r, 1.0e-10)); 18089566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)r, "Initial Residual")); 18099566063dSJacob Faibussowitsch PetscCall(PetscObjectSetOptionsPrefix((PetscObject)r, "res_")); 18109566063dSJacob Faibussowitsch PetscCall(VecViewFromOptions(r, NULL, "-vec_view")); 1811f017bcb6SMatthew G. Knepley } 18129566063dSJacob Faibussowitsch PetscCall(VecDestroy(&r)); 1813f017bcb6SMatthew G. Knepley PetscFunctionReturn(0); 1814f017bcb6SMatthew G. Knepley } 1815f017bcb6SMatthew G. Knepley 1816f017bcb6SMatthew G. Knepley /*@C 1817f3c94560SMatthew G. Knepley DMSNESCheckJacobian - Check the Jacobian of the exact solution against the residual using the Taylor Test 1818f017bcb6SMatthew G. Knepley 1819f017bcb6SMatthew G. Knepley Input Parameters: 1820f6dfbefdSBarry Smith + snes - the `SNES` object 1821f6dfbefdSBarry Smith . dm - the `DM` 1822f6dfbefdSBarry Smith . u - a `DM` vector 1823f0fc11ceSJed Brown - tol - A tolerance for the check, or -1 to print the results instead 1824f017bcb6SMatthew G. Knepley 1825f3c94560SMatthew G. Knepley Output Parameters: 1826f3c94560SMatthew G. Knepley + isLinear - Flag indicaing that the function looks linear, or NULL 1827f3c94560SMatthew G. Knepley - convRate - The rate of convergence of the linear model, or NULL 1828f3c94560SMatthew G. Knepley 1829f017bcb6SMatthew G. Knepley Level: developer 1830f017bcb6SMatthew G. Knepley 1831db781477SPatrick Sanan .seealso: `DNSNESCheckFromOptions()`, `DMSNESCheckDiscretization()`, `DMSNESCheckResidual()` 1832f017bcb6SMatthew G. Knepley @*/ 1833d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckJacobian(SNES snes, DM dm, Vec u, PetscReal tol, PetscBool *isLinear, PetscReal *convRate) 1834d71ae5a4SJacob Faibussowitsch { 1835f017bcb6SMatthew G. Knepley MPI_Comm comm; 1836f017bcb6SMatthew G. Knepley PetscDS ds; 1837f017bcb6SMatthew G. Knepley Mat J, M; 1838f017bcb6SMatthew G. Knepley MatNullSpace nullspace; 1839f3c94560SMatthew G. Knepley PetscReal slope, intercept; 18407f96f943SMatthew G. Knepley PetscBool hasJac, hasPrec, isLin = PETSC_FALSE; 1841f017bcb6SMatthew G. Knepley 1842f017bcb6SMatthew G. Knepley PetscFunctionBegin; 1843f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 1844f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 1845f3c94560SMatthew G. Knepley PetscValidHeaderSpecific(u, VEC_CLASSID, 3); 1846534a8f05SLisandro Dalcin if (isLinear) PetscValidBoolPointer(isLinear, 5); 1847064a246eSJacob Faibussowitsch if (convRate) PetscValidRealPointer(convRate, 6); 18489566063dSJacob Faibussowitsch PetscCall(PetscObjectGetComm((PetscObject)snes, &comm)); 18499566063dSJacob Faibussowitsch PetscCall(DMComputeExactSolution(dm, 0.0, u, NULL)); 1850f017bcb6SMatthew G. Knepley /* Create and view matrices */ 18519566063dSJacob Faibussowitsch PetscCall(DMCreateMatrix(dm, &J)); 18529566063dSJacob Faibussowitsch PetscCall(DMGetDS(dm, &ds)); 18539566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobian(ds, &hasJac)); 18549566063dSJacob Faibussowitsch PetscCall(PetscDSHasJacobianPreconditioner(ds, &hasPrec)); 1855282e7bb4SMatthew G. Knepley if (hasJac && hasPrec) { 18569566063dSJacob Faibussowitsch PetscCall(DMCreateMatrix(dm, &M)); 18579566063dSJacob Faibussowitsch PetscCall(SNESComputeJacobian(snes, u, J, M)); 18589566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)M, "Preconditioning Matrix")); 18599566063dSJacob Faibussowitsch PetscCall(PetscObjectSetOptionsPrefix((PetscObject)M, "jacpre_")); 18609566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(M, NULL, "-mat_view")); 18619566063dSJacob Faibussowitsch PetscCall(MatDestroy(&M)); 1862282e7bb4SMatthew G. Knepley } else { 18639566063dSJacob Faibussowitsch PetscCall(SNESComputeJacobian(snes, u, J, J)); 1864282e7bb4SMatthew G. Knepley } 18659566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)J, "Jacobian")); 18669566063dSJacob Faibussowitsch PetscCall(PetscObjectSetOptionsPrefix((PetscObject)J, "jac_")); 18679566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(J, NULL, "-mat_view")); 1868f017bcb6SMatthew G. Knepley /* Check nullspace */ 18699566063dSJacob Faibussowitsch PetscCall(MatGetNullSpace(J, &nullspace)); 1870f017bcb6SMatthew G. Knepley if (nullspace) { 18711878804aSMatthew G. Knepley PetscBool isNull; 18729566063dSJacob Faibussowitsch PetscCall(MatNullSpaceTest(nullspace, J, &isNull)); 187328b400f6SJacob Faibussowitsch PetscCheck(isNull, comm, PETSC_ERR_PLIB, "The null space calculated for the system operator is invalid."); 18741878804aSMatthew G. Knepley } 1875f017bcb6SMatthew G. Knepley /* Taylor test */ 1876f017bcb6SMatthew G. Knepley { 1877f017bcb6SMatthew G. Knepley PetscRandom rand; 1878f017bcb6SMatthew G. Knepley Vec du, uhat, r, rhat, df; 1879f3c94560SMatthew G. Knepley PetscReal h; 1880f017bcb6SMatthew G. Knepley PetscReal *es, *hs, *errors; 1881f017bcb6SMatthew G. Knepley PetscReal hMax = 1.0, hMin = 1e-6, hMult = 0.1; 1882f017bcb6SMatthew G. Knepley PetscInt Nv, v; 1883f017bcb6SMatthew G. Knepley 1884f017bcb6SMatthew G. Knepley /* Choose a perturbation direction */ 18859566063dSJacob Faibussowitsch PetscCall(PetscRandomCreate(comm, &rand)); 18869566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &du)); 18879566063dSJacob Faibussowitsch PetscCall(VecSetRandom(du, rand)); 18889566063dSJacob Faibussowitsch PetscCall(PetscRandomDestroy(&rand)); 18899566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &df)); 18909566063dSJacob Faibussowitsch PetscCall(MatMult(J, du, df)); 1891f017bcb6SMatthew G. Knepley /* Evaluate residual at u, F(u), save in vector r */ 18929566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &r)); 18939566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes, u, r)); 1894f017bcb6SMatthew G. Knepley /* Look at the convergence of our Taylor approximation as we approach u */ 18959371c9d4SSatish Balay for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv) 18969371c9d4SSatish Balay ; 18979566063dSJacob Faibussowitsch PetscCall(PetscCalloc3(Nv, &es, Nv, &hs, Nv, &errors)); 18989566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &uhat)); 18999566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &rhat)); 1900f017bcb6SMatthew G. Knepley for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv) { 19019566063dSJacob Faibussowitsch PetscCall(VecWAXPY(uhat, h, du, u)); 1902f017bcb6SMatthew G. Knepley /* F(\hat u) \approx F(u) + J(u) (uhat - u) = F(u) + h * J(u) du */ 19039566063dSJacob Faibussowitsch PetscCall(SNESComputeFunction(snes, uhat, rhat)); 19049566063dSJacob Faibussowitsch PetscCall(VecAXPBYPCZ(rhat, -1.0, -h, 1.0, r, df)); 19059566063dSJacob Faibussowitsch PetscCall(VecNorm(rhat, NORM_2, &errors[Nv])); 1906f017bcb6SMatthew G. Knepley 1907f017bcb6SMatthew G. Knepley es[Nv] = PetscLog10Real(errors[Nv]); 1908f017bcb6SMatthew G. Knepley hs[Nv] = PetscLog10Real(h); 1909f017bcb6SMatthew G. Knepley } 19109566063dSJacob Faibussowitsch PetscCall(VecDestroy(&uhat)); 19119566063dSJacob Faibussowitsch PetscCall(VecDestroy(&rhat)); 19129566063dSJacob Faibussowitsch PetscCall(VecDestroy(&df)); 19139566063dSJacob Faibussowitsch PetscCall(VecDestroy(&r)); 19149566063dSJacob Faibussowitsch PetscCall(VecDestroy(&du)); 1915f017bcb6SMatthew G. Knepley for (v = 0; v < Nv; ++v) { 1916f017bcb6SMatthew G. Knepley if ((tol >= 0) && (errors[v] > tol)) break; 1917f017bcb6SMatthew G. Knepley else if (errors[v] > PETSC_SMALL) break; 1918f017bcb6SMatthew G. Knepley } 1919f3c94560SMatthew G. Knepley if (v == Nv) isLin = PETSC_TRUE; 19209566063dSJacob Faibussowitsch PetscCall(PetscLinearRegression(Nv, hs, es, &slope, &intercept)); 19219566063dSJacob Faibussowitsch PetscCall(PetscFree3(es, hs, errors)); 1922f017bcb6SMatthew G. Knepley /* Slope should be about 2 */ 1923f017bcb6SMatthew G. Knepley if (tol >= 0) { 19240b121fc5SBarry Smith PetscCheck(isLin || PetscAbsReal(2 - slope) <= tol, comm, PETSC_ERR_ARG_WRONG, "Taylor approximation convergence rate should be 2, not %0.2f", (double)slope); 1925b878532fSMatthew G. Knepley } else if (isLinear || convRate) { 1926b878532fSMatthew G. Knepley if (isLinear) *isLinear = isLin; 1927b878532fSMatthew G. Knepley if (convRate) *convRate = slope; 1928f017bcb6SMatthew G. Knepley } else { 19299566063dSJacob Faibussowitsch if (!isLin) PetscCall(PetscPrintf(comm, "Taylor approximation converging at order %3.2f\n", (double)slope)); 19309566063dSJacob Faibussowitsch else PetscCall(PetscPrintf(comm, "Function appears to be linear\n")); 1931f017bcb6SMatthew G. Knepley } 1932f017bcb6SMatthew G. Knepley } 19339566063dSJacob Faibussowitsch PetscCall(MatDestroy(&J)); 19341878804aSMatthew G. Knepley PetscFunctionReturn(0); 19351878804aSMatthew G. Knepley } 19361878804aSMatthew G. Knepley 1937d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheck_Internal(SNES snes, DM dm, Vec u) 1938d71ae5a4SJacob Faibussowitsch { 1939f017bcb6SMatthew G. Knepley PetscFunctionBegin; 19409566063dSJacob Faibussowitsch PetscCall(DMSNESCheckDiscretization(snes, dm, 0.0, u, -1.0, NULL)); 19419566063dSJacob Faibussowitsch PetscCall(DMSNESCheckResidual(snes, dm, u, -1.0, NULL)); 19429566063dSJacob Faibussowitsch PetscCall(DMSNESCheckJacobian(snes, dm, u, -1.0, NULL, NULL)); 1943f017bcb6SMatthew G. Knepley PetscFunctionReturn(0); 1944f017bcb6SMatthew G. Knepley } 1945f017bcb6SMatthew G. Knepley 1946bee9a294SMatthew G. Knepley /*@C 1947bee9a294SMatthew G. Knepley DMSNESCheckFromOptions - Check the residual and Jacobian functions using the exact solution by outputting some diagnostic information 1948bee9a294SMatthew G. Knepley 1949bee9a294SMatthew G. Knepley Input Parameters: 1950f6dfbefdSBarry Smith + snes - the `SNES` object 1951f6dfbefdSBarry Smith - u - representative `SNES` vector 19527f96f943SMatthew G. Knepley 1953f6dfbefdSBarry Smith Note: 1954f6dfbefdSBarry Smith The user must call `PetscDSSetExactSolution()` beforehand 1955bee9a294SMatthew G. Knepley 1956bee9a294SMatthew G. Knepley Level: developer 1957bee9a294SMatthew G. Knepley @*/ 1958d71ae5a4SJacob Faibussowitsch PetscErrorCode DMSNESCheckFromOptions(SNES snes, Vec u) 1959d71ae5a4SJacob Faibussowitsch { 19601878804aSMatthew G. Knepley DM dm; 19611878804aSMatthew G. Knepley Vec sol; 19621878804aSMatthew G. Knepley PetscBool check; 19631878804aSMatthew G. Knepley 19641878804aSMatthew G. Knepley PetscFunctionBegin; 19659566063dSJacob Faibussowitsch PetscCall(PetscOptionsHasName(((PetscObject)snes)->options, ((PetscObject)snes)->prefix, "-dmsnes_check", &check)); 19661878804aSMatthew G. Knepley if (!check) PetscFunctionReturn(0); 19679566063dSJacob Faibussowitsch PetscCall(SNESGetDM(snes, &dm)); 19689566063dSJacob Faibussowitsch PetscCall(VecDuplicate(u, &sol)); 19699566063dSJacob Faibussowitsch PetscCall(SNESSetSolution(snes, sol)); 19709566063dSJacob Faibussowitsch PetscCall(DMSNESCheck_Internal(snes, dm, sol)); 19719566063dSJacob Faibussowitsch PetscCall(VecDestroy(&sol)); 1972552f7358SJed Brown PetscFunctionReturn(0); 1973552f7358SJed Brown } 1974