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