1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 3 #include <petsc/private/petscfeimpl.h> 4 5 /*@ 6 DMPlexGetActivePoint - Get the point on which projection is currently working 7 8 Not collective 9 10 Input Parameter: 11 . dm - the DM 12 13 Output Parameter: 14 . point - The mesh point involved in the current projection 15 16 Level: developer 17 18 .seealso: `DMPlexSetActivePoint()` 19 @*/ 20 PetscErrorCode DMPlexGetActivePoint(DM dm, PetscInt *point) 21 { 22 PetscFunctionBeginHot; 23 *point = ((DM_Plex *) dm->data)->activePoint; 24 PetscFunctionReturn(0); 25 } 26 27 /*@ 28 DMPlexSetActivePoint - Set the point on which projection is currently working 29 30 Not collective 31 32 Input Parameters: 33 + dm - the DM 34 - point - The mesh point involved in the current projection 35 36 Level: developer 37 38 .seealso: `DMPlexGetActivePoint()` 39 @*/ 40 PetscErrorCode DMPlexSetActivePoint(DM dm, PetscInt point) 41 { 42 PetscFunctionBeginHot; 43 ((DM_Plex *) dm->data)->activePoint = point; 44 PetscFunctionReturn(0); 45 } 46 47 /* 48 DMProjectPoint_Func_Private - Interpolate the given function in the output basis on the given point 49 50 Input Parameters: 51 + dm - The output DM 52 . ds - The output DS 53 . dmIn - The input DM 54 . dsIn - The input DS 55 . time - The time for this evaluation 56 . fegeom - The FE geometry for this point 57 . fvgeom - The FV geometry for this point 58 . isFE - Flag indicating whether each output field has an FE discretization 59 . sp - The output PetscDualSpace for each field 60 . funcs - The evaluation function for each field 61 - ctxs - The user context for each field 62 63 Output Parameter: 64 . values - The value for each dual basis vector in the output dual space 65 66 Level: developer 67 68 .seealso: `DMProjectPoint_Field_Private()` 69 */ 70 static PetscErrorCode DMProjectPoint_Func_Private(DM dm, PetscDS ds, DM dmIn, PetscDS dsIn, PetscReal time, PetscFEGeom *fegeom, PetscFVCellGeom *fvgeom, PetscBool isFE[], PetscDualSpace sp[], 71 PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, 72 PetscScalar values[]) 73 { 74 PetscInt coordDim, Nf, *Nc, f, spDim, d, v, tp; 75 PetscBool isAffine, isCohesive, transform; 76 77 PetscFunctionBeginHot; 78 PetscCall(DMGetCoordinateDim(dmIn, &coordDim)); 79 PetscCall(DMHasBasisTransform(dmIn, &transform)); 80 PetscCall(PetscDSGetNumFields(ds, &Nf)); 81 PetscCall(PetscDSGetComponents(ds, &Nc)); 82 PetscCall(PetscDSIsCohesive(ds, &isCohesive)); 83 /* Get values for closure */ 84 isAffine = fegeom->isAffine; 85 for (f = 0, v = 0, tp = 0; f < Nf; ++f) { 86 void * const ctx = ctxs ? ctxs[f] : NULL; 87 PetscBool cohesive; 88 89 if (!sp[f]) continue; 90 PetscCall(PetscDSGetCohesive(ds, f, &cohesive)); 91 PetscCall(PetscDualSpaceGetDimension(sp[f], &spDim)); 92 if (funcs[f]) { 93 if (isFE[f]) { 94 PetscQuadrature allPoints; 95 PetscInt q, dim, numPoints; 96 const PetscReal *points; 97 PetscScalar *pointEval; 98 PetscReal *x; 99 DM rdm; 100 101 PetscCall(PetscDualSpaceGetDM(sp[f],&rdm)); 102 PetscCall(PetscDualSpaceGetAllData(sp[f], &allPoints, NULL)); 103 PetscCall(PetscQuadratureGetData(allPoints,&dim,NULL,&numPoints,&points,NULL)); 104 PetscCall(DMGetWorkArray(rdm,numPoints*Nc[f],MPIU_SCALAR,&pointEval)); 105 PetscCall(DMGetWorkArray(rdm,coordDim,MPIU_REAL,&x)); 106 PetscCall(PetscArrayzero(pointEval, numPoints*Nc[f])); 107 for (q = 0; q < numPoints; q++, tp++) { 108 const PetscReal *v0; 109 110 if (isAffine) { 111 const PetscReal *refpoint = &points[q*dim]; 112 PetscReal injpoint[3] = {0., 0., 0.}; 113 114 if (dim != fegeom->dim) { 115 if (isCohesive) { 116 /* We just need to inject into the higher dimensional space assuming the last dimension is collapsed */ 117 for (d = 0; d < dim; ++d) injpoint[d] = refpoint[d]; 118 refpoint = injpoint; 119 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Reference spatial dimension %" PetscInt_FMT " != %" PetscInt_FMT " dual basis spatial dimension", fegeom->dim, dim); 120 } 121 CoordinatesRefToReal(coordDim, fegeom->dim, fegeom->xi, fegeom->v, fegeom->J, refpoint, x); 122 v0 = x; 123 } else { 124 v0 = &fegeom->v[tp*coordDim]; 125 } 126 if (transform) {PetscCall(DMPlexBasisTransformApplyReal_Internal(dmIn, v0, PETSC_TRUE, coordDim, v0, x, dm->transformCtx)); v0 = x;} 127 PetscCall((*funcs[f])(coordDim, time, v0, Nc[f], &pointEval[Nc[f]*q], ctx)); 128 } 129 /* Transform point evaluations pointEval[q,c] */ 130 PetscCall(PetscDualSpacePullback(sp[f], fegeom, numPoints, Nc[f], pointEval)); 131 PetscCall(PetscDualSpaceApplyAll(sp[f], pointEval, &values[v])); 132 PetscCall(DMRestoreWorkArray(rdm,coordDim,MPIU_REAL,&x)); 133 PetscCall(DMRestoreWorkArray(rdm,numPoints*Nc[f],MPIU_SCALAR,&pointEval)); 134 v += spDim; 135 if (isCohesive && !cohesive) { 136 for (d = 0; d < spDim; d++, v++) values[v] = values[v - spDim]; 137 } 138 } else { 139 for (d = 0; d < spDim; ++d, ++v) { 140 PetscCall(PetscDualSpaceApplyFVM(sp[f], d, time, fvgeom, Nc[f], funcs[f], ctx, &values[v])); 141 } 142 } 143 } else { 144 for (d = 0; d < spDim; d++, v++) values[v] = 0.; 145 if (isCohesive && !cohesive) { 146 for (d = 0; d < spDim; d++, v++) values[v] = 0.; 147 } 148 } 149 } 150 PetscFunctionReturn(0); 151 } 152 153 /* 154 DMProjectPoint_Field_Private - Interpolate a function of the given field, in the input basis, using the output basis on the given point 155 156 Input Parameters: 157 + dm - The output DM 158 . ds - The output DS 159 . dmIn - The input DM 160 . dsIn - The input DS 161 . dmAux - The auxiliary DM, which is always for the input space 162 . dsAux - The auxiliary DS, which is always for the input space 163 . time - The time for this evaluation 164 . localU - The local solution 165 . localA - The local auziliary fields 166 . cgeom - The FE geometry for this point 167 . sp - The output PetscDualSpace for each field 168 . p - The point in the output DM 169 . T - Input basis and derivatives for each field tabulated on the quadrature points 170 . TAux - Auxiliary basis and derivatives for each aux field tabulated on the quadrature points 171 . funcs - The evaluation function for each field 172 - ctxs - The user context for each field 173 174 Output Parameter: 175 . values - The value for each dual basis vector in the output dual space 176 177 Note: Not supported for FV 178 179 Level: developer 180 181 .seealso: `DMProjectPoint_Field_Private()` 182 */ 183 static PetscErrorCode DMProjectPoint_Field_Private(DM dm, PetscDS ds, DM dmIn, DMEnclosureType encIn, PetscDS dsIn, DM dmAux, DMEnclosureType encAux, PetscDS dsAux, PetscReal time, Vec localU, Vec localA, PetscFEGeom *cgeom, PetscDualSpace sp[], PetscInt p, 184 PetscTabulation *T, PetscTabulation *TAux, 185 void (**funcs)(PetscInt, PetscInt, PetscInt, 186 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 187 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 188 PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void **ctxs, 189 PetscScalar values[]) 190 { 191 PetscSection section, sectionAux = NULL; 192 PetscScalar *u, *u_t = NULL, *u_x, *a = NULL, *a_t = NULL, *a_x = NULL, *bc; 193 PetscScalar *coefficients = NULL, *coefficientsAux = NULL; 194 PetscScalar *coefficients_t = NULL, *coefficientsAux_t = NULL; 195 const PetscScalar *constants; 196 PetscReal *x; 197 PetscInt *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL, *Nc; 198 PetscFEGeom fegeom; 199 const PetscInt dE = cgeom->dimEmbed; 200 PetscInt numConstants, Nf, NfIn, NfAux = 0, f, spDim, d, v, inp, tp = 0; 201 PetscBool isAffine, isCohesive, transform; 202 203 PetscFunctionBeginHot; 204 PetscCall(PetscDSGetNumFields(ds, &Nf)); 205 PetscCall(PetscDSGetComponents(ds, &Nc)); 206 PetscCall(PetscDSIsCohesive(ds, &isCohesive)); 207 PetscCall(PetscDSGetNumFields(dsIn, &NfIn)); 208 PetscCall(PetscDSGetComponentOffsets(dsIn, &uOff)); 209 PetscCall(PetscDSGetComponentDerivativeOffsets(dsIn, &uOff_x)); 210 PetscCall(PetscDSGetEvaluationArrays(dsIn, &u, &bc /*&u_t*/, &u_x)); 211 PetscCall(PetscDSGetWorkspace(dsIn, &x, NULL, NULL, NULL, NULL)); 212 PetscCall(PetscDSGetConstants(dsIn, &numConstants, &constants)); 213 PetscCall(DMHasBasisTransform(dmIn, &transform)); 214 PetscCall(DMGetLocalSection(dmIn, §ion)); 215 PetscCall(DMGetEnclosurePoint(dmIn, dm, encIn, p, &inp)); 216 PetscCall(DMPlexVecGetClosure(dmIn, section, localU, inp, NULL, &coefficients)); 217 if (dmAux) { 218 PetscInt subp; 219 220 PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, p, &subp)); 221 PetscCall(PetscDSGetNumFields(dsAux, &NfAux)); 222 PetscCall(DMGetLocalSection(dmAux, §ionAux)); 223 PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff)); 224 PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x)); 225 PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL /*&a_t*/, &a_x)); 226 PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, localA, subp, NULL, &coefficientsAux)); 227 } 228 /* Get values for closure */ 229 isAffine = cgeom->isAffine; 230 fegeom.dim = cgeom->dim; 231 fegeom.dimEmbed = cgeom->dimEmbed; 232 if (isAffine) { 233 fegeom.v = x; 234 fegeom.xi = cgeom->xi; 235 fegeom.J = cgeom->J; 236 fegeom.invJ = cgeom->invJ; 237 fegeom.detJ = cgeom->detJ; 238 } 239 for (f = 0, v = 0; f < Nf; ++f) { 240 PetscQuadrature allPoints; 241 PetscInt q, dim, numPoints; 242 const PetscReal *points; 243 PetscScalar *pointEval; 244 PetscBool cohesive; 245 DM dm; 246 247 if (!sp[f]) continue; 248 PetscCall(PetscDSGetCohesive(ds, f, &cohesive)); 249 PetscCall(PetscDualSpaceGetDimension(sp[f], &spDim)); 250 if (!funcs[f]) { 251 for (d = 0; d < spDim; d++, v++) values[v] = 0.; 252 if (isCohesive && !cohesive) { 253 for (d = 0; d < spDim; d++, v++) values[v] = 0.; 254 } 255 continue; 256 } 257 PetscCall(PetscDualSpaceGetDM(sp[f],&dm)); 258 PetscCall(PetscDualSpaceGetAllData(sp[f], &allPoints, NULL)); 259 PetscCall(PetscQuadratureGetData(allPoints,&dim,NULL,&numPoints,&points,NULL)); 260 PetscCall(DMGetWorkArray(dm,numPoints*Nc[f],MPIU_SCALAR,&pointEval)); 261 for (q = 0; q < numPoints; ++q, ++tp) { 262 if (isAffine) { 263 CoordinatesRefToReal(dE, cgeom->dim, fegeom.xi, cgeom->v, fegeom.J, &points[q*dim], x); 264 } else { 265 fegeom.v = &cgeom->v[tp*dE]; 266 fegeom.J = &cgeom->J[tp*dE*dE]; 267 fegeom.invJ = &cgeom->invJ[tp*dE*dE]; 268 fegeom.detJ = &cgeom->detJ[tp]; 269 } 270 PetscCall(PetscFEEvaluateFieldJets_Internal(dsIn, NfIn, 0, tp, T, &fegeom, coefficients, coefficients_t, u, u_x, u_t)); 271 if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, 0, tp, TAux, &fegeom, coefficientsAux, coefficientsAux_t, a, a_x, a_t)); 272 if (transform) PetscCall(DMPlexBasisTransformApplyReal_Internal(dmIn, fegeom.v, PETSC_TRUE, dE, fegeom.v, fegeom.v, dm->transformCtx)); 273 (*funcs[f])(dE, NfIn, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, a_t, a_x, time, fegeom.v, numConstants, constants, &pointEval[Nc[f]*q]); 274 } 275 PetscCall(PetscDualSpaceApplyAll(sp[f], pointEval, &values[v])); 276 PetscCall(DMRestoreWorkArray(dm,numPoints*Nc[f],MPIU_SCALAR,&pointEval)); 277 v += spDim; 278 /* TODO: For now, set both sides equal, but this should use info from other support cell */ 279 if (isCohesive && !cohesive) { 280 for (d = 0; d < spDim; d++, v++) values[v] = values[v - spDim]; 281 } 282 } 283 PetscCall(DMPlexVecRestoreClosure(dmIn, section, localU, inp, NULL, &coefficients)); 284 if (dmAux) PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, localA, p, NULL, &coefficientsAux)); 285 PetscFunctionReturn(0); 286 } 287 288 static PetscErrorCode DMProjectPoint_BdField_Private(DM dm, PetscDS ds, DM dmIn, PetscDS dsIn, DM dmAux, DMEnclosureType encAux, PetscDS dsAux, PetscReal time, Vec localU, Vec localA, PetscFEGeom *fgeom, PetscDualSpace sp[], PetscInt p, 289 PetscTabulation *T, PetscTabulation *TAux, 290 void (**funcs)(PetscInt, PetscInt, PetscInt, 291 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 292 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 293 PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void **ctxs, 294 PetscScalar values[]) 295 { 296 PetscSection section, sectionAux = NULL; 297 PetscScalar *u, *u_t = NULL, *u_x, *a = NULL, *a_t = NULL, *a_x = NULL, *bc; 298 PetscScalar *coefficients = NULL, *coefficientsAux = NULL; 299 PetscScalar *coefficients_t = NULL, *coefficientsAux_t = NULL; 300 const PetscScalar *constants; 301 PetscReal *x; 302 PetscInt *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL, *Nc; 303 PetscFEGeom fegeom, cgeom; 304 const PetscInt dE = fgeom->dimEmbed; 305 PetscInt numConstants, Nf, NfAux = 0, f, spDim, d, v, tp = 0; 306 PetscBool isAffine; 307 308 PetscFunctionBeginHot; 309 PetscCheck(dm == dmIn,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Not yet upgraded to use different input DM"); 310 PetscCall(PetscDSGetNumFields(ds, &Nf)); 311 PetscCall(PetscDSGetComponents(ds, &Nc)); 312 PetscCall(PetscDSGetComponentOffsets(ds, &uOff)); 313 PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x)); 314 PetscCall(PetscDSGetEvaluationArrays(ds, &u, &bc /*&u_t*/, &u_x)); 315 PetscCall(PetscDSGetWorkspace(ds, &x, NULL, NULL, NULL, NULL)); 316 PetscCall(PetscDSGetConstants(ds, &numConstants, &constants)); 317 PetscCall(DMGetLocalSection(dm, §ion)); 318 PetscCall(DMPlexVecGetClosure(dmIn, section, localU, p, NULL, &coefficients)); 319 if (dmAux) { 320 PetscInt subp; 321 322 PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, p, &subp)); 323 PetscCall(PetscDSGetNumFields(dsAux, &NfAux)); 324 PetscCall(DMGetLocalSection(dmAux, §ionAux)); 325 PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff)); 326 PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x)); 327 PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL /*&a_t*/, &a_x)); 328 PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, localA, subp, NULL, &coefficientsAux)); 329 } 330 /* Get values for closure */ 331 isAffine = fgeom->isAffine; 332 fegeom.n = NULL; 333 fegeom.J = NULL; 334 fegeom.v = NULL; 335 fegeom.xi = NULL; 336 cgeom.dim = fgeom->dim; 337 cgeom.dimEmbed = fgeom->dimEmbed; 338 if (isAffine) { 339 fegeom.v = x; 340 fegeom.xi = fgeom->xi; 341 fegeom.J = fgeom->J; 342 fegeom.invJ = fgeom->invJ; 343 fegeom.detJ = fgeom->detJ; 344 fegeom.n = fgeom->n; 345 346 cgeom.J = fgeom->suppJ[0]; 347 cgeom.invJ = fgeom->suppInvJ[0]; 348 cgeom.detJ = fgeom->suppDetJ[0]; 349 } 350 for (f = 0, v = 0; f < Nf; ++f) { 351 PetscQuadrature allPoints; 352 PetscInt q, dim, numPoints; 353 const PetscReal *points; 354 PetscScalar *pointEval; 355 DM dm; 356 357 if (!sp[f]) continue; 358 PetscCall(PetscDualSpaceGetDimension(sp[f], &spDim)); 359 if (!funcs[f]) { 360 for (d = 0; d < spDim; d++, v++) values[v] = 0.; 361 continue; 362 } 363 PetscCall(PetscDualSpaceGetDM(sp[f],&dm)); 364 PetscCall(PetscDualSpaceGetAllData(sp[f], &allPoints, NULL)); 365 PetscCall(PetscQuadratureGetData(allPoints,&dim,NULL,&numPoints,&points,NULL)); 366 PetscCall(DMGetWorkArray(dm,numPoints*Nc[f],MPIU_SCALAR,&pointEval)); 367 for (q = 0; q < numPoints; ++q, ++tp) { 368 if (isAffine) { 369 CoordinatesRefToReal(dE, fgeom->dim, fegeom.xi, fgeom->v, fegeom.J, &points[q*dim], x); 370 } else { 371 fegeom.v = &fgeom->v[tp*dE]; 372 fegeom.J = &fgeom->J[tp*dE*dE]; 373 fegeom.invJ = &fgeom->invJ[tp*dE*dE]; 374 fegeom.detJ = &fgeom->detJ[tp]; 375 fegeom.n = &fgeom->n[tp*dE]; 376 377 cgeom.J = &fgeom->suppJ[0][tp*dE*dE]; 378 cgeom.invJ = &fgeom->suppInvJ[0][tp*dE*dE]; 379 cgeom.detJ = &fgeom->suppDetJ[0][tp]; 380 } 381 /* TODO We should use cgeom here, instead of fegeom, however the geometry coming in through fgeom does not have the support cell geometry */ 382 PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, 0, tp, T, &cgeom, coefficients, coefficients_t, u, u_x, u_t)); 383 if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, 0, tp, TAux, &cgeom, coefficientsAux, coefficientsAux_t, a, a_x, a_t)); 384 (*funcs[f])(dE, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, a_t, a_x, time, fegeom.v, fegeom.n, numConstants, constants, &pointEval[Nc[f]*q]); 385 } 386 PetscCall(PetscDualSpaceApplyAll(sp[f], pointEval, &values[v])); 387 PetscCall(DMRestoreWorkArray(dm,numPoints*Nc[f],MPIU_SCALAR,&pointEval)); 388 v += spDim; 389 } 390 PetscCall(DMPlexVecRestoreClosure(dmIn, section, localU, p, NULL, &coefficients)); 391 if (dmAux) PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, localA, p, NULL, &coefficientsAux)); 392 PetscFunctionReturn(0); 393 } 394 395 static PetscErrorCode DMProjectPoint_Private(DM dm, PetscDS ds, DM dmIn, DMEnclosureType encIn, PetscDS dsIn, DM dmAux, DMEnclosureType encAux, PetscDS dsAux, PetscFEGeom *fegeom, PetscInt effectiveHeight, PetscReal time, Vec localU, Vec localA, PetscBool hasFE, PetscBool hasFV, PetscBool isFE[], 396 PetscDualSpace sp[], PetscInt p, PetscTabulation *T, PetscTabulation *TAux, 397 DMBoundaryConditionType type, void (**funcs)(void), void **ctxs, PetscBool fieldActive[], PetscScalar values[]) 398 { 399 PetscFVCellGeom fvgeom; 400 PetscInt dim, dimEmbed; 401 402 PetscFunctionBeginHot; 403 PetscCall(DMGetDimension(dm, &dim)); 404 PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 405 if (hasFV) PetscCall(DMPlexComputeCellGeometryFVM(dm, p, &fvgeom.volume, fvgeom.centroid, NULL)); 406 switch (type) { 407 case DM_BC_ESSENTIAL: 408 case DM_BC_NATURAL: 409 PetscCall(DMProjectPoint_Func_Private(dm, ds, dmIn, dsIn, time, fegeom, &fvgeom, isFE, sp, (PetscErrorCode (**)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *)) funcs, ctxs, values));break; 410 case DM_BC_ESSENTIAL_FIELD: 411 case DM_BC_NATURAL_FIELD: 412 PetscCall(DMProjectPoint_Field_Private(dm, ds, dmIn, encIn, dsIn, dmAux, encAux, dsAux, time, localU, localA, fegeom, sp, p, T, TAux, 413 (void (**)(PetscInt, PetscInt, PetscInt, 414 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 415 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 416 PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[])) funcs, ctxs, values)); 417 break; 418 case DM_BC_ESSENTIAL_BD_FIELD: 419 PetscCall(DMProjectPoint_BdField_Private(dm, ds, dmIn, dsIn, dmAux, encAux, dsAux, time, localU, localA, fegeom, sp, p, T, TAux, 420 (void (**)(PetscInt, PetscInt, PetscInt, 421 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 422 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 423 PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[])) funcs, ctxs, values)); 424 break; 425 default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown boundary condition type: %d", (int) type); 426 } 427 PetscFunctionReturn(0); 428 } 429 430 static PetscErrorCode PetscDualSpaceGetAllPointsUnion(PetscInt Nf, PetscDualSpace *sp, PetscInt dim, void (**funcs)(void), PetscQuadrature *allPoints) 431 { 432 PetscReal *points; 433 PetscInt f, numPoints; 434 435 PetscFunctionBegin; 436 if (!dim) { 437 PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, allPoints)); 438 PetscFunctionReturn(0); 439 } 440 numPoints = 0; 441 for (f = 0; f < Nf; ++f) { 442 if (funcs[f]) { 443 PetscQuadrature fAllPoints; 444 PetscInt fNumPoints; 445 446 PetscCall(PetscDualSpaceGetAllData(sp[f],&fAllPoints, NULL)); 447 PetscCall(PetscQuadratureGetData(fAllPoints, NULL, NULL, &fNumPoints, NULL, NULL)); 448 numPoints += fNumPoints; 449 } 450 } 451 PetscCall(PetscMalloc1(dim*numPoints,&points)); 452 numPoints = 0; 453 for (f = 0; f < Nf; ++f) { 454 if (funcs[f]) { 455 PetscQuadrature fAllPoints; 456 PetscInt qdim, fNumPoints, q; 457 const PetscReal *fPoints; 458 459 PetscCall(PetscDualSpaceGetAllData(sp[f],&fAllPoints, NULL)); 460 PetscCall(PetscQuadratureGetData(fAllPoints, &qdim, NULL, &fNumPoints, &fPoints, NULL)); 461 PetscCheck(qdim == dim,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Spatial dimension %" PetscInt_FMT " for dual basis does not match input dimension %" PetscInt_FMT, qdim, dim); 462 for (q = 0; q < fNumPoints*dim; ++q) points[numPoints*dim+q] = fPoints[q]; 463 numPoints += fNumPoints; 464 } 465 } 466 PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF,allPoints)); 467 PetscCall(PetscQuadratureSetData(*allPoints,dim,0,numPoints,points,NULL)); 468 PetscFunctionReturn(0); 469 } 470 471 /*@C 472 DMGetFirstLabeledPoint - Find first labeled point p_o in odm such that the corresponding point p in dm has the specified height. Return p and the corresponding ds. 473 474 Input Parameters: 475 dm - the DM 476 odm - the enclosing DM 477 label - label for DM domain, or NULL for whole domain 478 numIds - the number of ids 479 ids - An array of the label ids in sequence for the domain 480 height - Height of target cells in DMPlex topology 481 482 Output Parameters: 483 point - the first labeled point 484 ds - the ds corresponding to the first labeled point 485 486 Level: developer 487 @*/ 488 PetscErrorCode DMGetFirstLabeledPoint(DM dm, DM odm, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt height, PetscInt *point, PetscDS *ds) 489 { 490 DM plex; 491 DMEnclosureType enc; 492 PetscInt ls = -1; 493 494 PetscFunctionBegin; 495 if (point) *point = -1; 496 if (!label) PetscFunctionReturn(0); 497 PetscCall(DMGetEnclosureRelation(dm, odm, &enc)); 498 PetscCall(DMConvert(dm, DMPLEX, &plex)); 499 for (PetscInt i = 0; i < numIds; ++i) { 500 IS labelIS; 501 PetscInt num_points, pStart, pEnd; 502 PetscCall(DMLabelGetStratumIS(label, ids[i], &labelIS)); 503 if (!labelIS) continue; /* No points with that id on this process */ 504 PetscCall(DMPlexGetHeightStratum(plex, height, &pStart, &pEnd)); 505 PetscCall(ISGetSize(labelIS, &num_points)); 506 if (num_points) { 507 const PetscInt *points; 508 PetscCall(ISGetIndices(labelIS, &points)); 509 for (PetscInt i=0; i<num_points; i++) { 510 PetscInt point; 511 PetscCall(DMGetEnclosurePoint(dm, odm, enc, points[i], &point)); 512 if (pStart <= point && point < pEnd) { 513 ls = point; 514 if (ds) PetscCall(DMGetCellDS(dm, ls, ds)); 515 } 516 } 517 PetscCall(ISRestoreIndices(labelIS, &points)); 518 } 519 PetscCall(ISDestroy(&labelIS)); 520 if (ls >= 0) break; 521 } 522 if (point) *point = ls; 523 PetscCall(DMDestroy(&plex)); 524 PetscFunctionReturn(0); 525 } 526 527 /* 528 This function iterates over a manifold, and interpolates the input function/field using the basis provided by the DS in our DM 529 530 There are several different scenarios: 531 532 1) Volumetric mesh with volumetric auxiliary data 533 534 Here minHeight=0 since we loop over cells. 535 536 2) Boundary mesh with boundary auxiliary data 537 538 Here minHeight=1 since we loop over faces. This normally happens since we hang cells off of our boundary meshes to facilitate computation. 539 540 3) Volumetric mesh with boundary auxiliary data 541 542 Here minHeight=1 and auxbd=PETSC_TRUE since we loop over faces and use data only supported on those faces. This is common when imposing Dirichlet boundary conditions. 543 544 4) Volumetric input mesh with boundary output mesh 545 546 Here we must get a subspace for the input DS 547 548 The maxHeight is used to support enforcement of constraints in DMForest. 549 550 If localU is given and not equal to localX, we call DMPlexInsertBoundaryValues() to complete it. 551 552 If we are using an input field (DM_BC_ESSENTIAL_FIELD or DM_BC_NATURAL_FIELD), we need to evaluate it at all the quadrature points of the dual basis functionals. 553 - We use effectiveHeight to mean the height above our incoming DS. For example, if the DS is for a submesh then the effective height is zero, whereas if the DS 554 is for the volumetric mesh, but we are iterating over a surface, then the effective height is nonzero. When the effective height is nonzero, we need to extract 555 dual spaces for the boundary from our input spaces. 556 - After extracting all quadrature points, we tabulate the input fields and auxiliary fields on them. 557 558 We check that the #dof(closure(p)) == #dual basis functionals(p) for a representative p in the iteration 559 560 If we have a label, we iterate over those points. This will probably break the maxHeight functionality since we do not check the height of those points. 561 */ 562 static PetscErrorCode DMProjectLocal_Generic_Plex(DM dm, PetscReal time, Vec localU, 563 PetscInt Ncc, const PetscInt comps[], DMLabel label, PetscInt numIds, const PetscInt ids[], 564 DMBoundaryConditionType type, void (**funcs)(void), void **ctxs, 565 InsertMode mode, Vec localX) 566 { 567 DM plex, dmIn, plexIn, dmAux = NULL, plexAux = NULL, tdm; 568 DMEnclosureType encIn, encAux; 569 PetscDS ds = NULL, dsIn = NULL, dsAux = NULL; 570 Vec localA = NULL, tv; 571 IS fieldIS; 572 PetscSection section; 573 PetscDualSpace *sp, *cellsp, *spIn, *cellspIn; 574 PetscTabulation *T = NULL, *TAux = NULL; 575 PetscInt *Nc; 576 PetscInt dim, dimEmbed, depth, htInc = 0, htIncIn = 0, htIncAux = 0, minHeight, maxHeight, h, regionNum, Nf, NfIn, NfAux = 0, NfTot, f; 577 PetscBool *isFE, hasFE = PETSC_FALSE, hasFV = PETSC_FALSE, isCohesive = PETSC_FALSE, transform; 578 DMField coordField; 579 DMLabel depthLabel; 580 PetscQuadrature allPoints = NULL; 581 582 PetscFunctionBegin; 583 if (localU) PetscCall(VecGetDM(localU, &dmIn)); 584 else {dmIn = dm;} 585 PetscCall(DMGetAuxiliaryVec(dm, label, numIds ? ids[0] : 0, 0, &localA)); 586 if (localA) PetscCall(VecGetDM(localA, &dmAux)); else {dmAux = NULL;} 587 PetscCall(DMConvert(dm, DMPLEX, &plex)); 588 PetscCall(DMConvert(dmIn, DMPLEX, &plexIn)); 589 PetscCall(DMGetEnclosureRelation(dmIn, dm, &encIn)); 590 PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 591 PetscCall(DMGetDimension(dm, &dim)); 592 PetscCall(DMPlexGetVTKCellHeight(plex, &minHeight)); 593 PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 594 PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 595 PetscCall(DMHasBasisTransform(dm, &transform)); 596 /* Auxiliary information can only be used with interpolation of field functions */ 597 if (dmAux) { 598 PetscCall(DMConvert(dmAux, DMPLEX, &plexAux)); 599 if (type == DM_BC_ESSENTIAL_FIELD || type == DM_BC_ESSENTIAL_BD_FIELD || type == DM_BC_NATURAL_FIELD) { 600 PetscCheck(localA,PETSC_COMM_SELF, PETSC_ERR_USER, "Missing localA vector"); 601 } 602 } 603 if (localU && localU != localX) PetscCall(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, localU, time, NULL, NULL, NULL)); 604 PetscCall(DMGetCoordinateField(dm,&coordField)); 605 /**** No collective calls below this point ****/ 606 /* Determine height for iteration of all meshes */ 607 { 608 DMPolytopeType ct, ctIn, ctAux; 609 PetscInt minHeightIn, minHeightAux, lStart, pStart, pEnd, p, pStartIn, pStartAux, pEndAux; 610 PetscInt dim = -1, dimIn = -1, dimAux = -1; 611 612 PetscCall(DMPlexGetSimplexOrBoxCells(plex, minHeight, &pStart, &pEnd)); 613 if (pEnd > pStart) { 614 PetscCall(DMGetFirstLabeledPoint(dm, dm, label, numIds, ids, minHeight, &lStart, NULL)); 615 p = lStart < 0 ? pStart : lStart; 616 PetscCall(DMPlexGetCellType(plex, p, &ct)); 617 dim = DMPolytopeTypeGetDim(ct); 618 PetscCall(DMPlexGetVTKCellHeight(plexIn, &minHeightIn)); 619 PetscCall(DMPlexGetSimplexOrBoxCells(plexIn, minHeightIn, &pStartIn, NULL)); 620 PetscCall(DMPlexGetCellType(plexIn, pStartIn, &ctIn)); 621 dimIn = DMPolytopeTypeGetDim(ctIn); 622 if (dmAux) { 623 PetscCall(DMPlexGetVTKCellHeight(plexAux, &minHeightAux)); 624 PetscCall(DMPlexGetSimplexOrBoxCells(plexAux, minHeightAux, &pStartAux, &pEndAux)); 625 if (pStartAux < pEndAux) { 626 PetscCall(DMPlexGetCellType(plexAux, pStartAux, &ctAux)); 627 dimAux = DMPolytopeTypeGetDim(ctAux); 628 } 629 } else dimAux = dim; 630 } else { 631 PetscCall(DMDestroy(&plex)); 632 PetscCall(DMDestroy(&plexIn)); 633 if (dmAux) PetscCall(DMDestroy(&plexAux)); 634 PetscFunctionReturn(0); 635 } 636 if (dim < 0) { 637 DMLabel spmap = NULL, spmapIn = NULL, spmapAux = NULL; 638 639 /* Fall back to determination based on being a submesh */ 640 PetscCall(DMPlexGetSubpointMap(plex, &spmap)); 641 PetscCall(DMPlexGetSubpointMap(plexIn, &spmapIn)); 642 if (plexAux) PetscCall(DMPlexGetSubpointMap(plexAux, &spmapAux)); 643 dim = spmap ? 1 : 0; 644 dimIn = spmapIn ? 1 : 0; 645 dimAux = spmapAux ? 1 : 0; 646 } 647 { 648 PetscInt dimProj = PetscMin(PetscMin(dim, dimIn), (dimAux < 0 ? PETSC_MAX_INT : dimAux)); 649 PetscInt dimAuxEff = dimAux < 0 ? dimProj : dimAux; 650 651 PetscCheck(PetscAbsInt(dimProj - dim) <= 1 && PetscAbsInt(dimProj - dimIn) <= 1 && PetscAbsInt(dimProj - dimAuxEff) <= 1,PETSC_COMM_SELF, PETSC_ERR_SUP, "Do not currently support differences of more than 1 in dimension"); 652 if (dimProj < dim) minHeight = 1; 653 htInc = dim - dimProj; 654 htIncIn = dimIn - dimProj; 655 htIncAux = dimAuxEff - dimProj; 656 } 657 } 658 PetscCall(DMPlexGetDepth(plex, &depth)); 659 PetscCall(DMPlexGetDepthLabel(plex, &depthLabel)); 660 PetscCall(DMPlexGetMaxProjectionHeight(plex, &maxHeight)); 661 maxHeight = PetscMax(maxHeight, minHeight); 662 PetscCheck(maxHeight >= 0 && maxHeight <= dim,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Maximum projection height %" PetscInt_FMT " not in [0, %" PetscInt_FMT ")", maxHeight, dim); 663 PetscCall(DMGetFirstLabeledPoint(dm, dm, label, numIds, ids, 0, NULL, &ds)); 664 if (!ds) PetscCall(DMGetDS(dm, &ds)); 665 PetscCall(DMGetFirstLabeledPoint(dmIn, dm, label, numIds, ids, 0, NULL, &dsIn)); 666 if (!dsIn) PetscCall(DMGetDS(dmIn, &dsIn)); 667 PetscCall(PetscDSGetNumFields(ds, &Nf)); 668 PetscCall(PetscDSGetNumFields(dsIn, &NfIn)); 669 PetscCall(DMGetNumFields(dm, &NfTot)); 670 PetscCall(DMFindRegionNum(dm, ds, ®ionNum)); 671 PetscCall(DMGetRegionNumDS(dm, regionNum, NULL, &fieldIS, NULL)); 672 PetscCall(PetscDSIsCohesive(ds, &isCohesive)); 673 PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 674 PetscCall(DMGetLocalSection(dm, §ion)); 675 if (dmAux) { 676 PetscCall(DMGetDS(dmAux, &dsAux)); 677 PetscCall(PetscDSGetNumFields(dsAux, &NfAux)); 678 } 679 PetscCall(PetscDSGetComponents(ds, &Nc)); 680 PetscCall(PetscMalloc3(Nf, &isFE, Nf, &sp, NfIn, &spIn)); 681 if (maxHeight > 0) PetscCall(PetscMalloc2(Nf, &cellsp, NfIn, &cellspIn)); 682 else {cellsp = sp; cellspIn = spIn;} 683 /* Get cell dual spaces */ 684 for (f = 0; f < Nf; ++f) { 685 PetscDiscType disctype; 686 687 PetscCall(PetscDSGetDiscType_Internal(ds, f, &disctype)); 688 if (disctype == PETSC_DISC_FE) { 689 PetscFE fe; 690 691 isFE[f] = PETSC_TRUE; 692 hasFE = PETSC_TRUE; 693 PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *) &fe)); 694 PetscCall(PetscFEGetDualSpace(fe, &cellsp[f])); 695 } else if (disctype == PETSC_DISC_FV) { 696 PetscFV fv; 697 698 isFE[f] = PETSC_FALSE; 699 hasFV = PETSC_TRUE; 700 PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *) &fv)); 701 PetscCall(PetscFVGetDualSpace(fv, &cellsp[f])); 702 } else { 703 isFE[f] = PETSC_FALSE; 704 cellsp[f] = NULL; 705 } 706 } 707 for (f = 0; f < NfIn; ++f) { 708 PetscDiscType disctype; 709 710 PetscCall(PetscDSGetDiscType_Internal(dsIn, f, &disctype)); 711 if (disctype == PETSC_DISC_FE) { 712 PetscFE fe; 713 714 PetscCall(PetscDSGetDiscretization(dsIn, f, (PetscObject *) &fe)); 715 PetscCall(PetscFEGetDualSpace(fe, &cellspIn[f])); 716 } else if (disctype == PETSC_DISC_FV) { 717 PetscFV fv; 718 719 PetscCall(PetscDSGetDiscretization(dsIn, f, (PetscObject *) &fv)); 720 PetscCall(PetscFVGetDualSpace(fv, &cellspIn[f])); 721 } else { 722 cellspIn[f] = NULL; 723 } 724 } 725 for (f = 0; f < Nf; ++f) { 726 if (!htInc) {sp[f] = cellsp[f];} 727 else PetscCall(PetscDualSpaceGetHeightSubspace(cellsp[f], htInc, &sp[f])); 728 } 729 if (type == DM_BC_ESSENTIAL_FIELD || type == DM_BC_ESSENTIAL_BD_FIELD || type == DM_BC_NATURAL_FIELD) { 730 PetscFE fem, subfem; 731 PetscDiscType disctype; 732 const PetscReal *points; 733 PetscInt numPoints; 734 735 PetscCheck(maxHeight <= minHeight,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Field projection not supported for face interpolation"); 736 PetscCall(PetscDualSpaceGetAllPointsUnion(Nf, sp, dim-htInc, funcs, &allPoints)); 737 PetscCall(PetscQuadratureGetData(allPoints, NULL, NULL, &numPoints, &points, NULL)); 738 PetscCall(PetscMalloc2(NfIn, &T, NfAux, &TAux)); 739 for (f = 0; f < NfIn; ++f) { 740 if (!htIncIn) {spIn[f] = cellspIn[f];} 741 else PetscCall(PetscDualSpaceGetHeightSubspace(cellspIn[f], htIncIn, &spIn[f])); 742 743 PetscCall(PetscDSGetDiscType_Internal(dsIn, f, &disctype)); 744 if (disctype != PETSC_DISC_FE) continue; 745 PetscCall(PetscDSGetDiscretization(dsIn, f, (PetscObject *) &fem)); 746 if (!htIncIn) {subfem = fem;} 747 else PetscCall(PetscFEGetHeightSubspace(fem, htIncIn, &subfem)); 748 PetscCall(PetscFECreateTabulation(subfem, 1, numPoints, points, 1, &T[f])); 749 } 750 for (f = 0; f < NfAux; ++f) { 751 PetscCall(PetscDSGetDiscType_Internal(dsAux, f, &disctype)); 752 if (disctype != PETSC_DISC_FE) continue; 753 PetscCall(PetscDSGetDiscretization(dsAux, f, (PetscObject *) &fem)); 754 if (!htIncAux) {subfem = fem;} 755 else PetscCall(PetscFEGetHeightSubspace(fem, htIncAux, &subfem)); 756 PetscCall(PetscFECreateTabulation(subfem, 1, numPoints, points, 1, &TAux[f])); 757 } 758 } 759 /* Note: We make no attempt to optimize for height. Higher height things just overwrite the lower height results. */ 760 for (h = minHeight; h <= maxHeight; h++) { 761 PetscInt hEff = h - minHeight + htInc; 762 PetscInt hEffIn = h - minHeight + htIncIn; 763 PetscInt hEffAux = h - minHeight + htIncAux; 764 PetscDS dsEff = ds; 765 PetscDS dsEffIn = dsIn; 766 PetscDS dsEffAux = dsAux; 767 PetscScalar *values; 768 PetscBool *fieldActive; 769 PetscInt maxDegree; 770 PetscInt pStart, pEnd, p, lStart, spDim, totDim, numValues; 771 IS heightIS; 772 773 if (h > minHeight) { 774 for (f = 0; f < Nf; ++f) PetscCall(PetscDualSpaceGetHeightSubspace(cellsp[f], hEff, &sp[f])); 775 } 776 PetscCall(DMPlexGetSimplexOrBoxCells(plex, h, &pStart, &pEnd)); 777 PetscCall(DMGetFirstLabeledPoint(dm, dm, label, numIds, ids, h, &lStart, NULL)); 778 PetscCall(DMLabelGetStratumIS(depthLabel, depth - h, &heightIS)); 779 if (pEnd <= pStart) { 780 PetscCall(ISDestroy(&heightIS)); 781 continue; 782 } 783 /* Compute totDim, the number of dofs in the closure of a point at this height */ 784 totDim = 0; 785 for (f = 0; f < Nf; ++f) { 786 PetscBool cohesive; 787 788 if (!sp[f]) continue; 789 PetscCall(PetscDSGetCohesive(ds, f, &cohesive)); 790 PetscCall(PetscDualSpaceGetDimension(sp[f], &spDim)); 791 totDim += spDim; 792 if (isCohesive && !cohesive) totDim += spDim; 793 } 794 p = lStart < 0 ? pStart : lStart; 795 PetscCall(DMPlexVecGetClosure(plex, section, localX, p, &numValues, NULL)); 796 PetscCheck(numValues == totDim,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The output section point (%" PetscInt_FMT ") closure size %" PetscInt_FMT " != dual space dimension %" PetscInt_FMT " at height %" PetscInt_FMT " in [%" PetscInt_FMT ", %" PetscInt_FMT "]", p, numValues, totDim, h, minHeight, maxHeight); 797 if (!totDim) { 798 PetscCall(ISDestroy(&heightIS)); 799 continue; 800 } 801 if (htInc) PetscCall(PetscDSGetHeightSubspace(ds, hEff, &dsEff)); 802 /* Compute totDimIn, the number of dofs in the closure of a point at this height */ 803 if (localU) { 804 PetscInt totDimIn, pIn, numValuesIn; 805 806 totDimIn = 0; 807 for (f = 0; f < NfIn; ++f) { 808 PetscBool cohesive; 809 810 if (!spIn[f]) continue; 811 PetscCall(PetscDSGetCohesive(dsIn, f, &cohesive)); 812 PetscCall(PetscDualSpaceGetDimension(spIn[f], &spDim)); 813 totDimIn += spDim; 814 if (isCohesive && !cohesive) totDimIn += spDim; 815 } 816 PetscCall(DMGetEnclosurePoint(dmIn, dm, encIn, lStart < 0 ? pStart : lStart, &pIn)); 817 PetscCall(DMPlexVecGetClosure(plexIn, NULL, localU, pIn, &numValuesIn, NULL)); 818 PetscCheck(numValuesIn == totDimIn,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The input section point (%" PetscInt_FMT ") closure size %" PetscInt_FMT " != dual space dimension %" PetscInt_FMT " at height %" PetscInt_FMT, pIn, numValuesIn, totDimIn, htIncIn); 819 if (htIncIn) PetscCall(PetscDSGetHeightSubspace(dsIn, hEffIn, &dsEffIn)); 820 } 821 if (htIncAux) PetscCall(PetscDSGetHeightSubspace(dsAux, hEffAux, &dsEffAux)); 822 /* Loop over points at this height */ 823 PetscCall(DMGetWorkArray(dm, numValues, MPIU_SCALAR, &values)); 824 PetscCall(DMGetWorkArray(dm, NfTot, MPI_INT, &fieldActive)); 825 { 826 const PetscInt *fields; 827 828 PetscCall(ISGetIndices(fieldIS, &fields)); 829 for (f = 0; f < NfTot; ++f) {fieldActive[f] = PETSC_FALSE;} 830 for (f = 0; f < Nf; ++f) {fieldActive[fields[f]] = (funcs[f] && sp[f]) ? PETSC_TRUE : PETSC_FALSE;} 831 PetscCall(ISRestoreIndices(fieldIS, &fields)); 832 } 833 if (label) { 834 PetscInt i; 835 836 for (i = 0; i < numIds; ++i) { 837 IS pointIS, isectIS; 838 const PetscInt *points; 839 PetscInt n; 840 PetscFEGeom *fegeom = NULL, *chunkgeom = NULL; 841 PetscQuadrature quad = NULL; 842 843 PetscCall(DMLabelGetStratumIS(label, ids[i], &pointIS)); 844 if (!pointIS) continue; /* No points with that id on this process */ 845 PetscCall(ISIntersect(pointIS,heightIS,&isectIS)); 846 PetscCall(ISDestroy(&pointIS)); 847 if (!isectIS) continue; 848 PetscCall(ISGetLocalSize(isectIS, &n)); 849 PetscCall(ISGetIndices(isectIS, &points)); 850 PetscCall(DMFieldGetDegree(coordField,isectIS,NULL,&maxDegree)); 851 if (maxDegree <= 1) { 852 PetscCall(DMFieldCreateDefaultQuadrature(coordField,isectIS,&quad)); 853 } 854 if (!quad) { 855 if (!h && allPoints) { 856 quad = allPoints; 857 allPoints = NULL; 858 } else { 859 PetscCall(PetscDualSpaceGetAllPointsUnion(Nf,sp,isCohesive ? dim-htInc-1 : dim-htInc,funcs,&quad)); 860 } 861 } 862 PetscCall(DMFieldCreateFEGeom(coordField, isectIS, quad, (htInc && h == minHeight) ? PETSC_TRUE : PETSC_FALSE, &fegeom)); 863 for (p = 0; p < n; ++p) { 864 const PetscInt point = points[p]; 865 866 PetscCall(PetscArrayzero(values, numValues)); 867 PetscCall(PetscFEGeomGetChunk(fegeom,p,p+1,&chunkgeom)); 868 PetscCall(DMPlexSetActivePoint(dm, point)); 869 PetscCall(DMProjectPoint_Private(dm, dsEff, plexIn, encIn, dsEffIn, plexAux, encAux, dsEffAux, chunkgeom, htInc, time, localU, localA, hasFE, hasFV, isFE, sp, point, T, TAux, type, funcs, ctxs, fieldActive, values)); 870 if (transform) PetscCall(DMPlexBasisTransformPoint_Internal(plex, tdm, tv, point, fieldActive, PETSC_FALSE, values)); 871 PetscCall(DMPlexVecSetFieldClosure_Internal(plex, section, localX, fieldActive, point, Ncc, comps, label, ids[i], values, mode)); 872 } 873 PetscCall(PetscFEGeomRestoreChunk(fegeom,p,p+1,&chunkgeom)); 874 PetscCall(PetscFEGeomDestroy(&fegeom)); 875 PetscCall(PetscQuadratureDestroy(&quad)); 876 PetscCall(ISRestoreIndices(isectIS, &points)); 877 PetscCall(ISDestroy(&isectIS)); 878 } 879 } else { 880 PetscFEGeom *fegeom = NULL, *chunkgeom = NULL; 881 PetscQuadrature quad = NULL; 882 IS pointIS; 883 884 PetscCall(ISCreateStride(PETSC_COMM_SELF,pEnd-pStart,pStart,1,&pointIS)); 885 PetscCall(DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree)); 886 if (maxDegree <= 1) { 887 PetscCall(DMFieldCreateDefaultQuadrature(coordField,pointIS,&quad)); 888 } 889 if (!quad) { 890 if (!h && allPoints) { 891 quad = allPoints; 892 allPoints = NULL; 893 } else { 894 PetscCall(PetscDualSpaceGetAllPointsUnion(Nf, sp, dim-htInc, funcs, &quad)); 895 } 896 } 897 PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, (htInc && h == minHeight) ? PETSC_TRUE : PETSC_FALSE, &fegeom)); 898 for (p = pStart; p < pEnd; ++p) { 899 PetscCall(PetscArrayzero(values, numValues)); 900 PetscCall(PetscFEGeomGetChunk(fegeom,p-pStart,p-pStart+1,&chunkgeom)); 901 PetscCall(DMPlexSetActivePoint(dm, p)); 902 PetscCall(DMProjectPoint_Private(dm, dsEff, plexIn, encIn, dsEffIn, plexAux, encAux, dsEffAux, chunkgeom, htInc, time, localU, localA, hasFE, hasFV, isFE, sp, p, T, TAux, type, funcs, ctxs, fieldActive, values)); 903 if (transform) PetscCall(DMPlexBasisTransformPoint_Internal(plex, tdm, tv, p, fieldActive, PETSC_FALSE, values)); 904 PetscCall(DMPlexVecSetFieldClosure_Internal(plex, section, localX, fieldActive, p, Ncc, comps, NULL, -1, values, mode)); 905 } 906 PetscCall(PetscFEGeomRestoreChunk(fegeom,p-pStart,pStart-p+1,&chunkgeom)); 907 PetscCall(PetscFEGeomDestroy(&fegeom)); 908 PetscCall(PetscQuadratureDestroy(&quad)); 909 PetscCall(ISDestroy(&pointIS)); 910 } 911 PetscCall(ISDestroy(&heightIS)); 912 PetscCall(DMRestoreWorkArray(dm, numValues, MPIU_SCALAR, &values)); 913 PetscCall(DMRestoreWorkArray(dm, Nf, MPI_INT, &fieldActive)); 914 } 915 /* Cleanup */ 916 if (type == DM_BC_ESSENTIAL_FIELD || type == DM_BC_ESSENTIAL_BD_FIELD || type == DM_BC_NATURAL_FIELD) { 917 for (f = 0; f < NfIn; ++f) PetscCall(PetscTabulationDestroy(&T[f])); 918 for (f = 0; f < NfAux; ++f) PetscCall(PetscTabulationDestroy(&TAux[f])); 919 PetscCall(PetscFree2(T, TAux)); 920 } 921 PetscCall(PetscQuadratureDestroy(&allPoints)); 922 PetscCall(PetscFree3(isFE, sp, spIn)); 923 if (maxHeight > 0) PetscCall(PetscFree2(cellsp, cellspIn)); 924 PetscCall(DMDestroy(&plex)); 925 PetscCall(DMDestroy(&plexIn)); 926 if (dmAux) PetscCall(DMDestroy(&plexAux)); 927 PetscFunctionReturn(0); 928 } 929 930 PetscErrorCode DMProjectFunctionLocal_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX) 931 { 932 PetscFunctionBegin; 933 PetscCall(DMProjectLocal_Generic_Plex(dm, time, NULL, 0, NULL, NULL, 0, NULL, DM_BC_ESSENTIAL, (void (**)(void)) funcs, ctxs, mode, localX)); 934 PetscFunctionReturn(0); 935 } 936 937 PetscErrorCode DMProjectFunctionLabelLocal_Plex(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Ncc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX) 938 { 939 PetscFunctionBegin; 940 PetscCall(DMProjectLocal_Generic_Plex(dm, time, NULL, Ncc, comps, label, numIds, ids, DM_BC_ESSENTIAL, (void (**)(void)) funcs, ctxs, mode, localX)); 941 PetscFunctionReturn(0); 942 } 943 944 PetscErrorCode DMProjectFieldLocal_Plex(DM dm, PetscReal time, Vec localU, 945 void (**funcs)(PetscInt, PetscInt, PetscInt, 946 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 947 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 948 PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), 949 InsertMode mode, Vec localX) 950 { 951 PetscFunctionBegin; 952 PetscCall(DMProjectLocal_Generic_Plex(dm, time, localU, 0, NULL, NULL, 0, NULL, DM_BC_ESSENTIAL_FIELD, (void (**)(void)) funcs, NULL, mode, localX)); 953 PetscFunctionReturn(0); 954 } 955 956 PetscErrorCode DMProjectFieldLabelLocal_Plex(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Ncc, const PetscInt comps[], Vec localU, 957 void (**funcs)(PetscInt, PetscInt, PetscInt, 958 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 959 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 960 PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), 961 InsertMode mode, Vec localX) 962 { 963 PetscFunctionBegin; 964 PetscCall(DMProjectLocal_Generic_Plex(dm, time, localU, Ncc, comps, label, numIds, ids, DM_BC_ESSENTIAL_FIELD, (void (**)(void)) funcs, NULL, mode, localX)); 965 PetscFunctionReturn(0); 966 } 967 968 PetscErrorCode DMProjectBdFieldLabelLocal_Plex(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Ncc, const PetscInt comps[], Vec localU, 969 void (**funcs)(PetscInt, PetscInt, PetscInt, 970 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 971 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 972 PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), 973 InsertMode mode, Vec localX) 974 { 975 PetscFunctionBegin; 976 PetscCall(DMProjectLocal_Generic_Plex(dm, time, localU, Ncc, comps, label, numIds, ids, DM_BC_ESSENTIAL_BD_FIELD, (void (**)(void)) funcs, NULL, mode, localX)); 977 PetscFunctionReturn(0); 978 } 979