1 #include <petsc/private/dmplextransformimpl.h> /*I "petscdmplextransform.h" I*/ 2 3 #include <petsc/private/petscfeimpl.h> /* For PetscFEInterpolate_Static() */ 4 5 PetscClassId DMPLEXTRANSFORM_CLASSID; 6 7 PetscFunctionList DMPlexTransformList = NULL; 8 PetscBool DMPlexTransformRegisterAllCalled = PETSC_FALSE; 9 10 PetscLogEvent DMPLEXTRANSFORM_SetUp, DMPLEXTRANSFORM_Apply, DMPLEXTRANSFORM_SetConeSizes, DMPLEXTRANSFORM_SetCones, DMPLEXTRANSFORM_CreateSF, DMPLEXTRANSFORM_CreateLabels, DMPLEXTRANSFORM_SetCoordinates; 11 12 /* Construct cell type order since we must loop over cell types in the same dimensional order they are stored in the plex if dm != NULL 13 OR in standard plex ordering if dm == NULL */ 14 static PetscErrorCode DMPlexCreateCellTypeOrder_Internal(DM dm, PetscInt dim, PetscInt *ctOrder[], PetscInt *ctOrderInv[]) 15 { 16 PetscInt *ctO, *ctOInv; 17 PetscInt d, c, off = 0; 18 PetscInt dimOrder[5] = {3, 2, 1, 0, -1}; 19 20 PetscFunctionBegin; 21 PetscCall(PetscCalloc2(DM_NUM_POLYTOPES + 1, &ctO, DM_NUM_POLYTOPES + 1, &ctOInv)); 22 if (dm) { // Order the dimensions by their starting location 23 PetscInt hStart[4] = {-1, -1, -1, -1}; 24 for (d = 0; d <= dim; ++d) PetscCall(DMPlexGetDepthStratum(dm, dim - d, &hStart[d], NULL)); 25 PetscCall(PetscSortIntWithArray(dim + 1, hStart, &dimOrder[3 - dim])); 26 } else if (dim > 1) { // Standard plex ordering. dimOrder is in correct order if dim > 1 27 off = 4 - dim; 28 dimOrder[off++] = 0; 29 for (d = dim - 1; d > 0; --d) { dimOrder[off++] = d; } 30 } 31 32 off = 0; 33 for (d = 0; d < 5; ++d) { 34 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 35 if (c == DM_POLYTOPE_UNKNOWN_CELL || c == DM_POLYTOPE_UNKNOWN_FACE) continue; 36 if (DMPolytopeTypeGetDim((DMPolytopeType)c) == dimOrder[d]) ctO[off++] = c; 37 } 38 } 39 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 40 if (c == DM_POLYTOPE_UNKNOWN_CELL || c == DM_POLYTOPE_UNKNOWN_FACE) ctO[off++] = c; 41 } 42 ctO[off++] = DM_NUM_POLYTOPES; 43 PetscCheck(off == DM_NUM_POLYTOPES + 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid offset %" PetscInt_FMT " for cell type order", off); 44 45 for (c = 0; c <= DM_NUM_POLYTOPES; ++c) ctOInv[ctO[c]] = c; 46 47 *ctOrder = ctO; 48 *ctOrderInv = ctOInv; 49 PetscFunctionReturn(PETSC_SUCCESS); 50 } 51 52 /*@C 53 DMPlexTransformRegister - Adds a new transform component implementation 54 55 Not Collective 56 57 Input Parameters: 58 + name - The name of a new user-defined creation routine 59 - create_func - The creation routine 60 61 Example Usage: 62 .vb 63 DMPlexTransformRegister("my_transform", MyTransformCreate); 64 .ve 65 66 Then, your transform type can be chosen with the procedural interface via 67 .vb 68 DMPlexTransformCreate(MPI_Comm, DMPlexTransform *); 69 DMPlexTransformSetType(DMPlexTransform, "my_transform"); 70 .ve 71 or at runtime via the option 72 .vb 73 -dm_plex_transform_type my_transform 74 .ve 75 76 Level: advanced 77 78 Note: 79 `DMPlexTransformRegister()` may be called multiple times to add several user-defined transforms 80 81 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformRegisterAll()`, `DMPlexTransformRegisterDestroy()` 82 @*/ 83 PetscErrorCode DMPlexTransformRegister(const char name[], PetscErrorCode (*create_func)(DMPlexTransform)) 84 { 85 PetscFunctionBegin; 86 PetscCall(DMInitializePackage()); 87 PetscCall(PetscFunctionListAdd(&DMPlexTransformList, name, create_func)); 88 PetscFunctionReturn(PETSC_SUCCESS); 89 } 90 91 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Filter(DMPlexTransform); 92 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Regular(DMPlexTransform); 93 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_ToBox(DMPlexTransform); 94 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Alfeld(DMPlexTransform); 95 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_SBR(DMPlexTransform); 96 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_BL(DMPlexTransform); 97 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_1D(DMPlexTransform); 98 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Extrude(DMPlexTransform); 99 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Cohesive(DMPlexTransform); 100 101 /*@C 102 DMPlexTransformRegisterAll - Registers all of the transform components in the `DM` package. 103 104 Not Collective 105 106 Level: advanced 107 108 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransformType`, `DMRegisterAll()`, `DMPlexTransformRegisterDestroy()` 109 @*/ 110 PetscErrorCode DMPlexTransformRegisterAll(void) 111 { 112 PetscFunctionBegin; 113 if (DMPlexTransformRegisterAllCalled) PetscFunctionReturn(PETSC_SUCCESS); 114 DMPlexTransformRegisterAllCalled = PETSC_TRUE; 115 116 PetscCall(DMPlexTransformRegister(DMPLEXTRANSFORMFILTER, DMPlexTransformCreate_Filter)); 117 PetscCall(DMPlexTransformRegister(DMPLEXREFINEREGULAR, DMPlexTransformCreate_Regular)); 118 PetscCall(DMPlexTransformRegister(DMPLEXREFINETOBOX, DMPlexTransformCreate_ToBox)); 119 PetscCall(DMPlexTransformRegister(DMPLEXREFINEALFELD, DMPlexTransformCreate_Alfeld)); 120 PetscCall(DMPlexTransformRegister(DMPLEXREFINEBOUNDARYLAYER, DMPlexTransformCreate_BL)); 121 PetscCall(DMPlexTransformRegister(DMPLEXREFINESBR, DMPlexTransformCreate_SBR)); 122 PetscCall(DMPlexTransformRegister(DMPLEXREFINE1D, DMPlexTransformCreate_1D)); 123 PetscCall(DMPlexTransformRegister(DMPLEXEXTRUDETYPE, DMPlexTransformCreate_Extrude)); 124 PetscCall(DMPlexTransformRegister(DMPLEXCOHESIVEEXTRUDE, DMPlexTransformCreate_Cohesive)); 125 PetscFunctionReturn(PETSC_SUCCESS); 126 } 127 128 /*@C 129 DMPlexTransformRegisterDestroy - This function destroys the registered `DMPlexTransformType`. It is called from `PetscFinalize()`. 130 131 Not collective 132 133 Level: developer 134 135 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMRegisterAll()`, `DMPlexTransformType`, `PetscInitialize()` 136 @*/ 137 PetscErrorCode DMPlexTransformRegisterDestroy(void) 138 { 139 PetscFunctionBegin; 140 PetscCall(PetscFunctionListDestroy(&DMPlexTransformList)); 141 DMPlexTransformRegisterAllCalled = PETSC_FALSE; 142 PetscFunctionReturn(PETSC_SUCCESS); 143 } 144 145 /*@ 146 DMPlexTransformCreate - Creates an empty transform object. The type can then be set with `DMPlexTransformSetType()`. 147 148 Collective 149 150 Input Parameter: 151 . comm - The communicator for the transform object 152 153 Output Parameter: 154 . tr - The transform object 155 156 Level: beginner 157 158 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `DMPlexTransformSetType()`, `DMPLEXREFINEREGULAR`, `DMPLEXTRANSFORMFILTER` 159 @*/ 160 PetscErrorCode DMPlexTransformCreate(MPI_Comm comm, DMPlexTransform *tr) 161 { 162 DMPlexTransform t; 163 164 PetscFunctionBegin; 165 PetscAssertPointer(tr, 2); 166 *tr = NULL; 167 PetscCall(DMInitializePackage()); 168 169 PetscCall(PetscHeaderCreate(t, DMPLEXTRANSFORM_CLASSID, "DMPlexTransform", "Mesh Transform", "DMPlexTransform", comm, DMPlexTransformDestroy, DMPlexTransformView)); 170 t->setupcalled = PETSC_FALSE; 171 PetscCall(PetscCalloc2(DM_NUM_POLYTOPES, &t->coordFE, DM_NUM_POLYTOPES, &t->refGeom)); 172 *tr = t; 173 PetscFunctionReturn(PETSC_SUCCESS); 174 } 175 176 /*@ 177 DMPlexTransformSetType - Sets the particular implementation for a transform. 178 179 Collective 180 181 Input Parameters: 182 + tr - The transform 183 - method - The name of the transform type 184 185 Options Database Key: 186 . -dm_plex_transform_type <type> - Sets the transform type; see `DMPlexTransformType` 187 188 Level: intermediate 189 190 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `DMPlexTransformGetType()`, `DMPlexTransformCreate()` 191 @*/ 192 PetscErrorCode DMPlexTransformSetType(DMPlexTransform tr, DMPlexTransformType method) 193 { 194 PetscErrorCode (*r)(DMPlexTransform); 195 PetscBool match; 196 197 PetscFunctionBegin; 198 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 199 PetscCall(PetscObjectTypeCompare((PetscObject)tr, method, &match)); 200 if (match) PetscFunctionReturn(PETSC_SUCCESS); 201 202 PetscCall(DMPlexTransformRegisterAll()); 203 PetscCall(PetscFunctionListFind(DMPlexTransformList, method, &r)); 204 PetscCheck(r, PetscObjectComm((PetscObject)tr), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DMPlexTransform type: %s", method); 205 206 PetscTryTypeMethod(tr, destroy); 207 PetscCall(PetscMemzero(tr->ops, sizeof(*tr->ops))); 208 PetscCall(PetscObjectChangeTypeName((PetscObject)tr, method)); 209 PetscCall((*r)(tr)); 210 PetscFunctionReturn(PETSC_SUCCESS); 211 } 212 213 /*@ 214 DMPlexTransformGetType - Gets the type name (as a string) from the transform. 215 216 Not Collective 217 218 Input Parameter: 219 . tr - The `DMPlexTransform` 220 221 Output Parameter: 222 . type - The `DMPlexTransformType` name 223 224 Level: intermediate 225 226 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `DMPlexTransformSetType()`, `DMPlexTransformCreate()` 227 @*/ 228 PetscErrorCode DMPlexTransformGetType(DMPlexTransform tr, DMPlexTransformType *type) 229 { 230 PetscFunctionBegin; 231 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 232 PetscAssertPointer(type, 2); 233 PetscCall(DMPlexTransformRegisterAll()); 234 *type = ((PetscObject)tr)->type_name; 235 PetscFunctionReturn(PETSC_SUCCESS); 236 } 237 238 static PetscErrorCode DMPlexTransformView_Ascii(DMPlexTransform tr, PetscViewer v) 239 { 240 PetscViewerFormat format; 241 242 PetscFunctionBegin; 243 PetscCall(PetscViewerGetFormat(v, &format)); 244 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 245 const PetscInt *trTypes = NULL; 246 IS trIS; 247 PetscInt cols = 8; 248 PetscInt Nrt = 8, f, g; 249 250 if (tr->trType) PetscCall(DMLabelView(tr->trType, v)); 251 PetscCall(PetscViewerASCIIPrintf(v, "Source Starts\n")); 252 for (g = 0; g <= cols; ++g) PetscCall(PetscViewerASCIIPrintf(v, " %14s", DMPolytopeTypes[g])); 253 PetscCall(PetscViewerASCIIPrintf(v, "\n")); 254 for (f = 0; f <= cols; ++f) PetscCall(PetscViewerASCIIPrintf(v, " %14" PetscInt_FMT, tr->ctStart[f])); 255 PetscCall(PetscViewerASCIIPrintf(v, "\n")); 256 PetscCall(PetscViewerASCIIPrintf(v, "Target Starts\n")); 257 for (g = 0; g <= cols; ++g) PetscCall(PetscViewerASCIIPrintf(v, " %14s", DMPolytopeTypes[g])); 258 PetscCall(PetscViewerASCIIPrintf(v, "\n")); 259 for (f = 0; f <= cols; ++f) PetscCall(PetscViewerASCIIPrintf(v, " %14" PetscInt_FMT, tr->ctStartNew[f])); 260 PetscCall(PetscViewerASCIIPrintf(v, "\n")); 261 262 if (tr->trType) { 263 PetscCall(DMLabelGetNumValues(tr->trType, &Nrt)); 264 PetscCall(DMLabelGetValueIS(tr->trType, &trIS)); 265 PetscCall(ISGetIndices(trIS, &trTypes)); 266 } 267 PetscCall(PetscViewerASCIIPrintf(v, "Offsets\n")); 268 PetscCall(PetscViewerASCIIPrintf(v, " ")); 269 for (g = 0; g < cols; ++g) PetscCall(PetscViewerASCIIPrintf(v, " %14s", DMPolytopeTypes[g])); 270 PetscCall(PetscViewerASCIIPrintf(v, "\n")); 271 for (f = 0; f < Nrt; ++f) { 272 PetscCall(PetscViewerASCIIPrintf(v, "%2" PetscInt_FMT " |", trTypes ? trTypes[f] : f)); 273 for (g = 0; g < cols; ++g) PetscCall(PetscViewerASCIIPrintf(v, " %14" PetscInt_FMT, tr->offset[f * DM_NUM_POLYTOPES + g])); 274 PetscCall(PetscViewerASCIIPrintf(v, " |\n")); 275 } 276 if (tr->trType) { 277 PetscCall(ISRestoreIndices(trIS, &trTypes)); 278 PetscCall(ISDestroy(&trIS)); 279 } 280 } 281 PetscFunctionReturn(PETSC_SUCCESS); 282 } 283 284 /*@ 285 DMPlexTransformView - Views a `DMPlexTransform` 286 287 Collective 288 289 Input Parameters: 290 + tr - the `DMPlexTransform` object to view 291 - v - the viewer 292 293 Level: beginner 294 295 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformType`, `PetscViewer`, `DMPlexTransformDestroy()`, `DMPlexTransformCreate()` 296 @*/ 297 PetscErrorCode DMPlexTransformView(DMPlexTransform tr, PetscViewer v) 298 { 299 PetscBool isascii; 300 301 PetscFunctionBegin; 302 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 303 if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)tr), &v)); 304 PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2); 305 PetscCheckSameComm(tr, 1, v, 2); 306 PetscCall(PetscViewerCheckWritable(v)); 307 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)tr, v)); 308 PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &isascii)); 309 if (isascii) PetscCall(DMPlexTransformView_Ascii(tr, v)); 310 PetscTryTypeMethod(tr, view, v); 311 PetscFunctionReturn(PETSC_SUCCESS); 312 } 313 314 /*@ 315 DMPlexTransformSetFromOptions - Sets parameters in a transform from values in the options database 316 317 Collective 318 319 Input Parameter: 320 . tr - the `DMPlexTransform` object to set options for 321 322 Options Database Keys: 323 + -dm_plex_transform_type - Set the transform type, e.g. refine_regular 324 . -dm_plex_transform_label_match_strata - Only label points of the same stratum as the producing point 325 . -dm_plex_transform_label_replica_inc <inc> - Increment for the label value to be multiplied by the replica number, so that the new label value is oldValue + r * inc 326 . -dm_plex_transform_active <name> - Name for active mesh label 327 - -dm_plex_transform_active_values <v0,v1,...> - Values in the active label 328 329 Level: intermediate 330 331 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformView()`, `DMPlexTransformCreate()` 332 @*/ 333 PetscErrorCode DMPlexTransformSetFromOptions(DMPlexTransform tr) 334 { 335 char typeName[1024], active[PETSC_MAX_PATH_LEN]; 336 const char *defName = DMPLEXREFINEREGULAR; 337 PetscBool flg, match; 338 339 PetscFunctionBegin; 340 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 341 PetscObjectOptionsBegin((PetscObject)tr); 342 PetscCall(PetscOptionsFList("-dm_plex_transform_type", "DMPlexTransform", "DMPlexTransformSetType", DMPlexTransformList, defName, typeName, 1024, &flg)); 343 if (flg) PetscCall(DMPlexTransformSetType(tr, typeName)); 344 else if (!((PetscObject)tr)->type_name) PetscCall(DMPlexTransformSetType(tr, defName)); 345 PetscCall(PetscOptionsBool("-dm_plex_transform_label_match_strata", "Only label points of the same stratum as the producing point", "", tr->labelMatchStrata, &match, &flg)); 346 if (flg) PetscCall(DMPlexTransformSetMatchStrata(tr, match)); 347 PetscCall(PetscOptionsInt("-dm_plex_transform_label_replica_inc", "Increment for the label value to be multiplied by the replica number", "", tr->labelReplicaInc, &tr->labelReplicaInc, NULL)); 348 PetscCall(PetscOptionsString("-dm_plex_transform_active", "Name for active mesh label", "DMPlexTransformSetActive", active, active, sizeof(active), &flg)); 349 if (flg) { 350 DM dm; 351 DMLabel label; 352 PetscInt values[16]; 353 PetscInt n = 16; 354 355 PetscCall(DMPlexTransformGetDM(tr, &dm)); 356 PetscCall(DMGetLabel(dm, active, &label)); 357 PetscCall(PetscOptionsIntArray("-dm_plex_transform_active_values", "The label values to be active", "DMPlexTransformSetActive", values, &n, &flg)); 358 if (flg && n) { 359 DMLabel newlabel; 360 361 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Active", &newlabel)); 362 for (PetscInt i = 0; i < n; ++i) { 363 IS is; 364 365 PetscCall(DMLabelGetStratumIS(label, values[i], &is)); 366 PetscCall(DMLabelInsertIS(newlabel, is, values[i])); 367 PetscCall(ISDestroy(&is)); 368 } 369 PetscCall(DMPlexTransformSetActive(tr, newlabel)); 370 PetscCall(DMLabelDestroy(&newlabel)); 371 } else { 372 PetscCall(DMPlexTransformSetActive(tr, label)); 373 } 374 } 375 PetscTryTypeMethod(tr, setfromoptions, PetscOptionsObject); 376 /* process any options handlers added with PetscObjectAddOptionsHandler() */ 377 PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)tr, PetscOptionsObject)); 378 PetscOptionsEnd(); 379 PetscFunctionReturn(PETSC_SUCCESS); 380 } 381 382 /*@ 383 DMPlexTransformDestroy - Destroys a `DMPlexTransform` 384 385 Collective 386 387 Input Parameter: 388 . tr - the transform object to destroy 389 390 Level: beginner 391 392 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformView()`, `DMPlexTransformCreate()` 393 @*/ 394 PetscErrorCode DMPlexTransformDestroy(DMPlexTransform *tr) 395 { 396 PetscInt c; 397 398 PetscFunctionBegin; 399 if (!*tr) PetscFunctionReturn(PETSC_SUCCESS); 400 PetscValidHeaderSpecific(*tr, DMPLEXTRANSFORM_CLASSID, 1); 401 if (--((PetscObject)*tr)->refct > 0) { 402 *tr = NULL; 403 PetscFunctionReturn(PETSC_SUCCESS); 404 } 405 406 PetscTryTypeMethod(*tr, destroy); 407 PetscCall(DMDestroy(&(*tr)->dm)); 408 PetscCall(DMLabelDestroy(&(*tr)->active)); 409 PetscCall(DMLabelDestroy(&(*tr)->trType)); 410 PetscCall(PetscFree2((*tr)->ctOrderOld, (*tr)->ctOrderInvOld)); 411 PetscCall(PetscFree2((*tr)->ctOrderNew, (*tr)->ctOrderInvNew)); 412 PetscCall(PetscFree2((*tr)->ctStart, (*tr)->ctStartNew)); 413 PetscCall(PetscFree((*tr)->offset)); 414 PetscCall(PetscFree2((*tr)->depthStart, (*tr)->depthEnd)); 415 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 416 PetscCall(PetscFEDestroy(&(*tr)->coordFE[c])); 417 PetscCall(PetscFEGeomDestroy(&(*tr)->refGeom[c])); 418 } 419 if ((*tr)->trVerts) { 420 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 421 DMPolytopeType *rct; 422 PetscInt *rsize, *rcone, *rornt, Nct, n, r; 423 424 if (DMPolytopeTypeGetDim((DMPolytopeType)c) > 0 && c != DM_POLYTOPE_UNKNOWN_CELL && c != DM_POLYTOPE_UNKNOWN_FACE) { 425 PetscCall(DMPlexTransformCellTransform(*tr, (DMPolytopeType)c, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 426 for (n = 0; n < Nct; ++n) { 427 if (rct[n] == DM_POLYTOPE_POINT) continue; 428 for (r = 0; r < rsize[n]; ++r) PetscCall(PetscFree((*tr)->trSubVerts[c][rct[n]][r])); 429 PetscCall(PetscFree((*tr)->trSubVerts[c][rct[n]])); 430 } 431 } 432 PetscCall(PetscFree((*tr)->trSubVerts[c])); 433 PetscCall(PetscFree((*tr)->trVerts[c])); 434 } 435 } 436 PetscCall(PetscFree3((*tr)->trNv, (*tr)->trVerts, (*tr)->trSubVerts)); 437 PetscCall(PetscFree2((*tr)->coordFE, (*tr)->refGeom)); 438 /* We do not destroy (*dm)->data here so that we can reference count backend objects */ 439 PetscCall(PetscHeaderDestroy(tr)); 440 PetscFunctionReturn(PETSC_SUCCESS); 441 } 442 443 static PetscErrorCode DMPlexTransformCreateOffset_Internal(DMPlexTransform tr, PetscInt ctOrderOld[], PetscInt ctStart[], PetscInt **offset) 444 { 445 DMLabel trType = tr->trType; 446 PetscInt c, cN, *off; 447 448 PetscFunctionBegin; 449 if (trType) { 450 DM dm; 451 IS rtIS; 452 const PetscInt *reftypes; 453 PetscInt Nrt, r; 454 455 PetscCall(DMPlexTransformGetDM(tr, &dm)); 456 PetscCall(DMLabelGetNumValues(trType, &Nrt)); 457 PetscCall(DMLabelGetValueIS(trType, &rtIS)); 458 PetscCall(ISGetIndices(rtIS, &reftypes)); 459 PetscCall(PetscCalloc1(Nrt * DM_NUM_POLYTOPES, &off)); 460 for (r = 0; r < Nrt; ++r) { 461 const PetscInt rt = reftypes[r]; 462 IS rtIS; 463 const PetscInt *points; 464 DMPolytopeType ct; 465 PetscInt np, p; 466 467 PetscCall(DMLabelGetStratumIS(trType, rt, &rtIS)); 468 PetscCall(ISGetLocalSize(rtIS, &np)); 469 PetscCall(ISGetIndices(rtIS, &points)); 470 if (!np) continue; 471 p = points[0]; 472 PetscCall(ISRestoreIndices(rtIS, &points)); 473 PetscCall(ISDestroy(&rtIS)); 474 PetscCall(DMPlexGetCellType(dm, p, &ct)); 475 for (cN = DM_POLYTOPE_POINT; cN < DM_NUM_POLYTOPES; ++cN) { 476 const DMPolytopeType ctNew = (DMPolytopeType)cN; 477 DMPolytopeType *rct; 478 PetscInt *rsize, *cone, *ornt; 479 PetscInt Nct, n, s; 480 481 if (DMPolytopeTypeGetDim(ct) < 0 || DMPolytopeTypeGetDim(ctNew) < 0) { 482 off[r * DM_NUM_POLYTOPES + ctNew] = -1; 483 break; 484 } 485 off[r * DM_NUM_POLYTOPES + ctNew] = 0; 486 for (s = 0; s <= r; ++s) { 487 const PetscInt st = reftypes[s]; 488 DMPolytopeType sct; 489 PetscInt q, qrt; 490 491 PetscCall(DMLabelGetStratumIS(trType, st, &rtIS)); 492 PetscCall(ISGetLocalSize(rtIS, &np)); 493 PetscCall(ISGetIndices(rtIS, &points)); 494 if (!np) continue; 495 q = points[0]; 496 PetscCall(ISRestoreIndices(rtIS, &points)); 497 PetscCall(ISDestroy(&rtIS)); 498 PetscCall(DMPlexGetCellType(dm, q, &sct)); 499 PetscCall(DMPlexTransformCellTransform(tr, sct, q, &qrt, &Nct, &rct, &rsize, &cone, &ornt)); 500 PetscCheck(st == qrt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Refine type %" PetscInt_FMT " of point %" PetscInt_FMT " does not match predicted type %" PetscInt_FMT, qrt, q, st); 501 if (st == rt) { 502 for (n = 0; n < Nct; ++n) 503 if (rct[n] == ctNew) break; 504 if (n == Nct) off[r * DM_NUM_POLYTOPES + ctNew] = -1; 505 break; 506 } 507 for (n = 0; n < Nct; ++n) { 508 if (rct[n] == ctNew) { 509 PetscInt sn; 510 511 PetscCall(DMLabelGetStratumSize(trType, st, &sn)); 512 off[r * DM_NUM_POLYTOPES + ctNew] += sn * rsize[n]; 513 } 514 } 515 } 516 } 517 } 518 PetscCall(ISRestoreIndices(rtIS, &reftypes)); 519 PetscCall(ISDestroy(&rtIS)); 520 } else { 521 PetscCall(PetscCalloc1(DM_NUM_POLYTOPES * DM_NUM_POLYTOPES, &off)); 522 for (c = DM_POLYTOPE_POINT; c < DM_NUM_POLYTOPES; ++c) { 523 const DMPolytopeType ct = (DMPolytopeType)c; 524 for (cN = DM_POLYTOPE_POINT; cN < DM_NUM_POLYTOPES; ++cN) { 525 const DMPolytopeType ctNew = (DMPolytopeType)cN; 526 DMPolytopeType *rct; 527 PetscInt *rsize, *cone, *ornt; 528 PetscInt Nct, n, i; 529 530 if (DMPolytopeTypeGetDim(ct) < 0 || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE || DMPolytopeTypeGetDim(ctNew) < 0 || ctNew == DM_POLYTOPE_UNKNOWN_CELL || ctNew == DM_POLYTOPE_UNKNOWN_FACE) { 531 off[ct * DM_NUM_POLYTOPES + ctNew] = -1; 532 continue; 533 } 534 off[ct * DM_NUM_POLYTOPES + ctNew] = 0; 535 for (i = DM_POLYTOPE_POINT; i < DM_NUM_POLYTOPES; ++i) { 536 const DMPolytopeType ict = (DMPolytopeType)ctOrderOld[i]; 537 const DMPolytopeType ictn = (DMPolytopeType)ctOrderOld[i + 1]; 538 539 PetscCall(DMPlexTransformCellTransform(tr, ict, PETSC_DETERMINE, NULL, &Nct, &rct, &rsize, &cone, &ornt)); 540 if (ict == ct) { 541 for (n = 0; n < Nct; ++n) 542 if (rct[n] == ctNew) break; 543 if (n == Nct) off[ct * DM_NUM_POLYTOPES + ctNew] = -1; 544 break; 545 } 546 for (n = 0; n < Nct; ++n) 547 if (rct[n] == ctNew) off[ct * DM_NUM_POLYTOPES + ctNew] += (ctStart[ictn] - ctStart[ict]) * rsize[n]; 548 } 549 } 550 } 551 } 552 *offset = off; 553 PetscFunctionReturn(PETSC_SUCCESS); 554 } 555 556 /*@ 557 DMPlexTransformSetUp - Create the tables that drive the transform 558 559 Input Parameter: 560 . tr - The `DMPlexTransform` object 561 562 Level: intermediate 563 564 .seealso: [](plex_transform_table), [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformApply()`, `DMPlexTransformCreate()` 565 @*/ 566 PetscErrorCode DMPlexTransformSetUp(DMPlexTransform tr) 567 { 568 DMPolytopeType ctCell; 569 DM dm; 570 PetscInt pStart, pEnd, p, c, celldim = 0; 571 572 PetscFunctionBegin; 573 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 574 if (tr->setupcalled) PetscFunctionReturn(PETSC_SUCCESS); 575 PetscCall(DMPlexTransformGetDM(tr, &dm)); 576 PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetUp, tr, dm, 0, 0)); 577 PetscTryTypeMethod(tr, setup); 578 PetscCall(DMSetSnapToGeomModel(dm, NULL)); 579 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 580 581 if (pEnd > pStart) { 582 // Ignore cells hanging off of embedded surfaces 583 PetscInt c = pStart; 584 585 ctCell = DM_POLYTOPE_FV_GHOST; 586 while (DMPolytopeTypeGetDim(ctCell) < 0) PetscCall(DMPlexGetCellType(dm, c++, &ctCell)); 587 } else { 588 PetscInt dim; 589 590 PetscCall(DMGetDimension(dm, &dim)); 591 switch (dim) { 592 case 0: 593 ctCell = DM_POLYTOPE_POINT; 594 break; 595 case 1: 596 ctCell = DM_POLYTOPE_SEGMENT; 597 break; 598 case 2: 599 ctCell = DM_POLYTOPE_TRIANGLE; 600 break; 601 case 3: 602 ctCell = DM_POLYTOPE_TETRAHEDRON; 603 break; 604 default: 605 ctCell = DM_POLYTOPE_UNKNOWN; 606 } 607 } 608 PetscCall(DMPlexCreateCellTypeOrder_Internal(dm, DMPolytopeTypeGetDim(ctCell), &tr->ctOrderOld, &tr->ctOrderInvOld)); 609 for (p = pStart; p < pEnd; ++p) { 610 DMPolytopeType ct; 611 DMPolytopeType *rct; 612 PetscInt *rsize, *cone, *ornt; 613 PetscInt Nct, n; 614 615 PetscCall(DMPlexGetCellType(dm, p, &ct)); 616 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell type for point %" PetscInt_FMT, p); 617 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &cone, &ornt)); 618 for (n = 0; n < Nct; ++n) celldim = PetscMax(celldim, DMPolytopeTypeGetDim(rct[n])); 619 } 620 PetscCall(DMPlexCreateCellTypeOrder_Internal(NULL, celldim, &tr->ctOrderNew, &tr->ctOrderInvNew)); 621 /* Construct sizes and offsets for each cell type */ 622 if (!tr->ctStart) { 623 PetscInt *ctS, *ctSN, *ctC, *ctCN; 624 625 PetscCall(PetscCalloc2(DM_NUM_POLYTOPES + 1, &ctS, DM_NUM_POLYTOPES + 1, &ctSN)); 626 PetscCall(PetscCalloc2(DM_NUM_POLYTOPES + 1, &ctC, DM_NUM_POLYTOPES + 1, &ctCN)); 627 for (p = pStart; p < pEnd; ++p) { 628 DMPolytopeType ct; 629 DMPolytopeType *rct; 630 PetscInt *rsize, *cone, *ornt; 631 PetscInt Nct, n; 632 633 PetscCall(DMPlexGetCellType(dm, p, &ct)); 634 PetscCheck(ct != DM_POLYTOPE_UNKNOWN && ct != DM_POLYTOPE_UNKNOWN_CELL && ct != DM_POLYTOPE_UNKNOWN_FACE, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No cell type for point %" PetscInt_FMT, p); 635 ++ctC[ct]; 636 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &cone, &ornt)); 637 for (n = 0; n < Nct; ++n) ctCN[rct[n]] += rsize[n]; 638 } 639 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 640 const PetscInt cto = tr->ctOrderOld[c]; 641 const PetscInt cton = tr->ctOrderOld[c + 1]; 642 const PetscInt ctn = tr->ctOrderNew[c]; 643 const PetscInt ctnn = tr->ctOrderNew[c + 1]; 644 645 ctS[cton] = ctS[cto] + ctC[cto]; 646 ctSN[ctnn] = ctSN[ctn] + ctCN[ctn]; 647 } 648 PetscCall(PetscFree2(ctC, ctCN)); 649 tr->ctStart = ctS; 650 tr->ctStartNew = ctSN; 651 } 652 PetscCall(DMPlexTransformCreateOffset_Internal(tr, tr->ctOrderOld, tr->ctStart, &tr->offset)); 653 // Compute depth information 654 tr->depth = -1; 655 for (c = 0; c < DM_NUM_POLYTOPES; ++c) 656 if (tr->ctStartNew[tr->ctOrderNew[c + 1]] > tr->ctStartNew[tr->ctOrderNew[c]]) tr->depth = PetscMax(tr->depth, DMPolytopeTypeGetDim((DMPolytopeType)tr->ctOrderNew[c])); 657 PetscCall(PetscMalloc2(tr->depth + 1, &tr->depthStart, tr->depth + 1, &tr->depthEnd)); 658 for (PetscInt d = 0; d <= tr->depth; ++d) { 659 tr->depthStart[d] = PETSC_INT_MAX; 660 tr->depthEnd[d] = -1; 661 } 662 for (c = 0; c < DM_NUM_POLYTOPES; ++c) { 663 const PetscInt dep = DMPolytopeTypeGetDim((DMPolytopeType)tr->ctOrderNew[c]); 664 665 if (tr->ctStartNew[tr->ctOrderNew[c + 1]] <= tr->ctStartNew[tr->ctOrderNew[c]]) continue; 666 tr->depthStart[dep] = PetscMin(tr->depthStart[dep], tr->ctStartNew[tr->ctOrderNew[c]]); 667 tr->depthEnd[dep] = PetscMax(tr->depthEnd[dep], tr->ctStartNew[tr->ctOrderNew[c + 1]]); 668 } 669 tr->setupcalled = PETSC_TRUE; 670 PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetUp, tr, dm, 0, 0)); 671 PetscFunctionReturn(PETSC_SUCCESS); 672 } 673 674 /*@ 675 DMPlexTransformGetDM - Get the base `DM` for the transform 676 677 Input Parameter: 678 . tr - The `DMPlexTransform` object 679 680 Output Parameter: 681 . dm - The original `DM` which will be transformed 682 683 Level: intermediate 684 685 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformSetDM()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()` 686 @*/ 687 PetscErrorCode DMPlexTransformGetDM(DMPlexTransform tr, DM *dm) 688 { 689 PetscFunctionBegin; 690 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 691 PetscAssertPointer(dm, 2); 692 *dm = tr->dm; 693 PetscFunctionReturn(PETSC_SUCCESS); 694 } 695 696 /*@ 697 DMPlexTransformSetDM - Set the base `DM` for the transform 698 699 Input Parameters: 700 + tr - The `DMPlexTransform` object 701 - dm - The original `DM` which will be transformed 702 703 Level: intermediate 704 705 Note: 706 The user does not typically call this, as it is called by `DMPlexTransformApply()`. 707 708 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetDM()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()` 709 @*/ 710 PetscErrorCode DMPlexTransformSetDM(DMPlexTransform tr, DM dm) 711 { 712 PetscFunctionBegin; 713 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 714 PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 715 PetscCall(PetscObjectReference((PetscObject)dm)); 716 PetscCall(DMDestroy(&tr->dm)); 717 tr->dm = dm; 718 PetscFunctionReturn(PETSC_SUCCESS); 719 } 720 721 /*@ 722 DMPlexTransformGetActive - Get the `DMLabel` marking the active points for the transform 723 724 Input Parameter: 725 . tr - The `DMPlexTransform` object 726 727 Output Parameter: 728 . active - The `DMLabel` indicating which points will be transformed 729 730 Level: intermediate 731 732 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformSetActive()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()` 733 @*/ 734 PetscErrorCode DMPlexTransformGetActive(DMPlexTransform tr, DMLabel *active) 735 { 736 PetscFunctionBegin; 737 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 738 PetscAssertPointer(active, 2); 739 *active = tr->active; 740 PetscFunctionReturn(PETSC_SUCCESS); 741 } 742 743 /*@ 744 DMPlexTransformSetActive - Set the `DMLabel` marking the active points for the transform 745 746 Input Parameters: 747 + tr - The `DMPlexTransform` object 748 - active - The `DMLabel` indicating which points will be transformed 749 750 Level: intermediate 751 752 Note: 753 This only applies to transforms listed in [](plex_transform_table) that operate on a subset of the mesh. 754 755 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetActive()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()` 756 @*/ 757 PetscErrorCode DMPlexTransformSetActive(DMPlexTransform tr, DMLabel active) 758 { 759 PetscFunctionBegin; 760 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 761 if (active) PetscValidHeaderSpecific(active, DMLABEL_CLASSID, 2); 762 PetscCall(PetscObjectReference((PetscObject)active)); 763 PetscCall(DMLabelDestroy(&tr->active)); 764 tr->active = active; 765 PetscFunctionReturn(PETSC_SUCCESS); 766 } 767 768 /*@ 769 DMPlexTransformGetTransformTypes - Get the `DMLabel` marking the transform type of each point for the transform 770 771 Input Parameter: 772 . tr - The `DMPlexTransform` object 773 774 Output Parameter: 775 . trType - The `DMLabel` indicating the transform type for each point 776 777 Level: intermediate 778 779 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexSetTransformType()`, `DMPlexTransformGetActive()`, `DMPlexTransformApply()`, `DMPlexTransformCreate()` 780 @*/ 781 PetscErrorCode DMPlexTransformGetTransformTypes(DMPlexTransform tr, DMLabel *trType) 782 { 783 PetscFunctionBegin; 784 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 785 PetscAssertPointer(trType, 2); 786 *trType = tr->trType; 787 PetscFunctionReturn(PETSC_SUCCESS); 788 } 789 790 /*@ 791 DMPlexTransformSetTransformTypes - Set the `DMLabel` marking the transform type of each point for the transform 792 793 Input Parameters: 794 + tr - The `DMPlexTransform` object 795 - trType - The original `DM` which will be transformed 796 797 Level: intermediate 798 799 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetTransformTypes()`, `DMPlexTransformGetActive())`, `DMPlexTransformApply()`, `DMPlexTransformCreate()` 800 @*/ 801 PetscErrorCode DMPlexTransformSetTransformTypes(DMPlexTransform tr, DMLabel trType) 802 { 803 PetscFunctionBegin; 804 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 805 if (trType) PetscValidHeaderSpecific(trType, DMLABEL_CLASSID, 2); 806 PetscCall(PetscObjectReference((PetscObject)trType)); 807 PetscCall(DMLabelDestroy(&tr->trType)); 808 tr->trType = trType; 809 PetscFunctionReturn(PETSC_SUCCESS); 810 } 811 812 static PetscErrorCode DMPlexTransformGetCoordinateFE(DMPlexTransform tr, DMPolytopeType ct, PetscFE *fe) 813 { 814 PetscFunctionBegin; 815 if (!tr->coordFE[ct]) { 816 PetscInt dim, cdim; 817 818 dim = DMPolytopeTypeGetDim(ct); 819 PetscCall(DMGetCoordinateDim(tr->dm, &cdim)); 820 PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, cdim, ct, 1, PETSC_DETERMINE, &tr->coordFE[ct])); 821 { 822 PetscDualSpace dsp; 823 PetscQuadrature quad; 824 DM K; 825 PetscFEGeom *cg; 826 PetscScalar *Xq; 827 PetscReal *xq, *wq; 828 PetscInt Nq, q; 829 830 PetscCall(DMPlexTransformGetCellVertices(tr, ct, &Nq, &Xq)); 831 PetscCall(PetscMalloc1(Nq * cdim, &xq)); 832 for (q = 0; q < Nq * cdim; ++q) xq[q] = PetscRealPart(Xq[q]); 833 PetscCall(PetscMalloc1(Nq, &wq)); 834 for (q = 0; q < Nq; ++q) wq[q] = 1.0; 835 PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &quad)); 836 PetscCall(PetscQuadratureSetData(quad, dim, 1, Nq, xq, wq)); 837 PetscCall(PetscFESetQuadrature(tr->coordFE[ct], quad)); 838 839 PetscCall(PetscFEGetDualSpace(tr->coordFE[ct], &dsp)); 840 PetscCall(PetscDualSpaceGetDM(dsp, &K)); 841 PetscCall(PetscFEGeomCreate(quad, 1, cdim, PETSC_FEGEOM_BASIC, &tr->refGeom[ct])); 842 cg = tr->refGeom[ct]; 843 PetscCall(DMPlexComputeCellGeometryFEM(K, 0, NULL, cg->v, cg->J, cg->invJ, cg->detJ)); 844 PetscCall(PetscQuadratureDestroy(&quad)); 845 } 846 } 847 *fe = tr->coordFE[ct]; 848 PetscFunctionReturn(PETSC_SUCCESS); 849 } 850 851 PetscErrorCode DMPlexTransformSetDimensions_Internal(DMPlexTransform tr, DM dm, DM tdm) 852 { 853 PetscInt dim, cdim; 854 855 PetscFunctionBegin; 856 PetscCall(DMGetDimension(dm, &dim)); 857 PetscCall(DMSetDimension(tdm, dim)); 858 PetscCall(DMGetCoordinateDim(dm, &cdim)); 859 PetscCall(DMSetCoordinateDim(tdm, cdim)); 860 PetscFunctionReturn(PETSC_SUCCESS); 861 } 862 863 /*@ 864 DMPlexTransformSetDimensions - Set the dimensions for the transformed `DM` 865 866 Input Parameters: 867 + tr - The `DMPlexTransform` object 868 - dm - The original `DM` 869 870 Output Parameter: 871 . tdm - The transformed `DM` 872 873 Level: advanced 874 875 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformApply()`, `DMPlexTransformCreate()` 876 @*/ 877 PetscErrorCode DMPlexTransformSetDimensions(DMPlexTransform tr, DM dm, DM tdm) 878 { 879 PetscFunctionBegin; 880 PetscUseTypeMethod(tr, setdimensions, dm, tdm); 881 PetscFunctionReturn(PETSC_SUCCESS); 882 } 883 884 PetscErrorCode DMPlexTransformGetChart(DMPlexTransform tr, PetscInt *pStart, PetscInt *pEnd) 885 { 886 PetscFunctionBegin; 887 if (pStart) *pStart = 0; 888 if (pEnd) *pEnd = tr->ctStartNew[tr->ctOrderNew[DM_NUM_POLYTOPES]]; 889 PetscFunctionReturn(PETSC_SUCCESS); 890 } 891 892 PetscErrorCode DMPlexTransformGetCellType(DMPlexTransform tr, PetscInt cell, DMPolytopeType *celltype) 893 { 894 PetscInt ctNew; 895 896 PetscFunctionBegin; 897 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 898 PetscAssertPointer(celltype, 3); 899 /* TODO Can do bisection since everything is sorted */ 900 for (ctNew = DM_POLYTOPE_POINT; ctNew < DM_NUM_POLYTOPES; ++ctNew) { 901 PetscInt ctSN = tr->ctStartNew[ctNew], ctEN = tr->ctStartNew[tr->ctOrderNew[tr->ctOrderInvNew[ctNew] + 1]]; 902 903 if (cell >= ctSN && cell < ctEN) break; 904 } 905 PetscCheck(ctNew < DM_NUM_POLYTOPES, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " cannot be located in the transformed mesh", cell); 906 *celltype = (DMPolytopeType)ctNew; 907 PetscFunctionReturn(PETSC_SUCCESS); 908 } 909 910 PetscErrorCode DMPlexTransformGetCellTypeStratum(DMPlexTransform tr, DMPolytopeType celltype, PetscInt *start, PetscInt *end) 911 { 912 PetscFunctionBegin; 913 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 914 if (start) *start = tr->ctStartNew[celltype]; 915 if (end) *end = tr->ctStartNew[tr->ctOrderNew[tr->ctOrderInvNew[celltype] + 1]]; 916 PetscFunctionReturn(PETSC_SUCCESS); 917 } 918 919 PetscErrorCode DMPlexTransformGetDepth(DMPlexTransform tr, PetscInt *depth) 920 { 921 PetscFunctionBegin; 922 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 923 *depth = tr->depth; 924 PetscFunctionReturn(PETSC_SUCCESS); 925 } 926 927 PetscErrorCode DMPlexTransformGetDepthStratum(DMPlexTransform tr, PetscInt depth, PetscInt *start, PetscInt *end) 928 { 929 PetscFunctionBegin; 930 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 931 if (start) *start = tr->depthStart[depth]; 932 if (end) *end = tr->depthEnd[depth]; 933 PetscFunctionReturn(PETSC_SUCCESS); 934 } 935 936 /*@ 937 DMPlexTransformGetMatchStrata - Get the flag which determines what points get added to the transformed labels 938 939 Not Collective 940 941 Input Parameter: 942 . tr - The `DMPlexTransform` 943 944 Output Parameter: 945 . match - If `PETSC_TRUE`, only add produced points at the same stratum as the original point to new labels 946 947 Level: intermediate 948 949 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformSetMatchStrata()`, `DMPlexGetPointDepth()` 950 @*/ 951 PetscErrorCode DMPlexTransformGetMatchStrata(DMPlexTransform tr, PetscBool *match) 952 { 953 PetscFunctionBegin; 954 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 955 PetscAssertPointer(match, 2); 956 *match = tr->labelMatchStrata; 957 PetscFunctionReturn(PETSC_SUCCESS); 958 } 959 960 /*@ 961 DMPlexTransformSetMatchStrata - Set the flag which determines what points get added to the transformed labels 962 963 Not Collective 964 965 Input Parameters: 966 + tr - The `DMPlexTransform` 967 - match - If `PETSC_TRUE`, only add produced points at the same stratum as the original point to new labels 968 969 Level: intermediate 970 971 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformGetMatchStrata()`, `DMPlexGetPointDepth()` 972 @*/ 973 PetscErrorCode DMPlexTransformSetMatchStrata(DMPlexTransform tr, PetscBool match) 974 { 975 PetscFunctionBegin; 976 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 977 tr->labelMatchStrata = match; 978 PetscFunctionReturn(PETSC_SUCCESS); 979 } 980 981 /*@ 982 DMPlexTransformGetTargetPoint - Get the number of a point in the transformed mesh based on information from the original mesh. 983 984 Not Collective 985 986 Input Parameters: 987 + tr - The `DMPlexTransform` 988 . ct - The type of the original point which produces the new point 989 . ctNew - The type of the new point 990 . p - The original point which produces the new point 991 - r - The replica number of the new point, meaning it is the rth point of type `ctNew` produced from `p` 992 993 Output Parameter: 994 . pNew - The new point number 995 996 Level: developer 997 998 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetSourcePoint()`, `DMPlexTransformCellTransform()` 999 @*/ 1000 PetscErrorCode DMPlexTransformGetTargetPoint(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType ctNew, PetscInt p, PetscInt r, PetscInt *pNew) 1001 { 1002 DMPolytopeType *rct; 1003 PetscInt *rsize, *cone, *ornt; 1004 PetscInt rt, Nct, n, off, rp; 1005 DMLabel trType = tr->trType; 1006 PetscInt ctS = tr->ctStart[ct], ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ct] + 1]]; 1007 PetscInt ctSN = tr->ctStartNew[ctNew], ctEN = tr->ctStartNew[tr->ctOrderNew[tr->ctOrderInvNew[ctNew] + 1]]; 1008 PetscInt newp = ctSN, cind; 1009 1010 PetscFunctionBeginHot; 1011 PetscCheck(p >= ctS && p < ctE, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " is not a %s [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, DMPolytopeTypes[ct], ctS, ctE); 1012 PetscCall(DMPlexTransformCellTransform(tr, ct, p, &rt, &Nct, &rct, &rsize, &cone, &ornt)); 1013 if (trType) { 1014 PetscCall(DMLabelGetValueIndex(trType, rt, &cind)); 1015 PetscCall(DMLabelGetStratumPointIndex(trType, rt, p, &rp)); 1016 PetscCheck(rp >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell type %s point %" PetscInt_FMT " does not have refine type %" PetscInt_FMT, DMPolytopeTypes[ct], p, rt); 1017 } else { 1018 cind = ct; 1019 rp = p - ctS; 1020 } 1021 off = tr->offset[cind * DM_NUM_POLYTOPES + ctNew]; 1022 PetscCheck(off >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell type %s (%" PetscInt_FMT ") of point %" PetscInt_FMT " does not produce type %s for transform %s", DMPolytopeTypes[ct], rt, p, DMPolytopeTypes[ctNew], tr->hdr.type_name); 1023 newp += off; 1024 for (n = 0; n < Nct; ++n) { 1025 if (rct[n] == ctNew) { 1026 if (rsize[n] && r >= rsize[n]) 1027 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Replica number %" PetscInt_FMT " should be in [0, %" PetscInt_FMT ") for subcell type %s in cell type %s", r, rsize[n], DMPolytopeTypes[rct[n]], DMPolytopeTypes[ct]); 1028 newp += rp * rsize[n] + r; 1029 break; 1030 } 1031 } 1032 1033 PetscCheck(!(newp < ctSN) && !(newp >= ctEN), PETSC_COMM_SELF, PETSC_ERR_PLIB, "New point %" PetscInt_FMT " is not a %s [%" PetscInt_FMT ", %" PetscInt_FMT ")", newp, DMPolytopeTypes[ctNew], ctSN, ctEN); 1034 *pNew = newp; 1035 PetscFunctionReturn(PETSC_SUCCESS); 1036 } 1037 1038 /*@ 1039 DMPlexTransformGetSourcePoint - Get the number of a point in the original mesh based on information from the transformed mesh. 1040 1041 Not Collective 1042 1043 Input Parameters: 1044 + tr - The `DMPlexTransform` 1045 - pNew - The new point number 1046 1047 Output Parameters: 1048 + ct - The type of the original point which produces the new point 1049 . ctNew - The type of the new point 1050 . p - The original point which produces the new point 1051 - r - The replica number of the new point, meaning it is the rth point of type ctNew produced from p 1052 1053 Level: developer 1054 1055 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetTargetPoint()`, `DMPlexTransformCellTransform()` 1056 @*/ 1057 PetscErrorCode DMPlexTransformGetSourcePoint(DMPlexTransform tr, PetscInt pNew, DMPolytopeType *ct, DMPolytopeType *ctNew, PetscInt *p, PetscInt *r) 1058 { 1059 DMLabel trType = tr->trType; 1060 DMPolytopeType *rct, ctN; 1061 PetscInt *rsize, *cone, *ornt; 1062 PetscInt rt = -1, rtTmp, Nct, n, rp = 0, rO = 0, pO; 1063 PetscInt offset = -1, ctS, ctE, ctO = 0, ctTmp, rtS; 1064 1065 PetscFunctionBegin; 1066 PetscCall(DMPlexTransformGetCellType(tr, pNew, &ctN)); 1067 if (trType) { 1068 DM dm; 1069 IS rtIS; 1070 const PetscInt *reftypes; 1071 PetscInt Nrt, r, rtStart; 1072 1073 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1074 PetscCall(DMLabelGetNumValues(trType, &Nrt)); 1075 PetscCall(DMLabelGetValueIS(trType, &rtIS)); 1076 PetscCall(ISGetIndices(rtIS, &reftypes)); 1077 for (r = 0; r < Nrt; ++r) { 1078 const PetscInt off = tr->offset[r * DM_NUM_POLYTOPES + ctN]; 1079 1080 if (tr->ctStartNew[ctN] + off > pNew) continue; 1081 /* Check that any of this refinement type exist */ 1082 /* TODO Actually keep track of the number produced here instead */ 1083 if (off > offset) { 1084 rt = reftypes[r]; 1085 offset = off; 1086 } 1087 } 1088 PetscCall(ISRestoreIndices(rtIS, &reftypes)); 1089 PetscCall(ISDestroy(&rtIS)); 1090 PetscCheck(offset >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Source cell type for target point %" PetscInt_FMT " could be not found", pNew); 1091 /* TODO Map refinement types to cell types */ 1092 PetscCall(DMLabelGetStratumBounds(trType, rt, &rtStart, NULL)); 1093 PetscCheck(rtStart >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Refinement type %" PetscInt_FMT " has no source points", rt); 1094 for (ctO = 0; ctO < DM_NUM_POLYTOPES; ++ctO) { 1095 PetscInt ctS = tr->ctStart[ctO], ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctO] + 1]]; 1096 1097 if ((rtStart >= ctS) && (rtStart < ctE)) break; 1098 } 1099 PetscCheck(ctO != DM_NUM_POLYTOPES, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not determine a cell type for refinement type %" PetscInt_FMT, rt); 1100 } else { 1101 for (ctTmp = 0; ctTmp < DM_NUM_POLYTOPES; ++ctTmp) { 1102 const PetscInt off = tr->offset[ctTmp * DM_NUM_POLYTOPES + ctN]; 1103 1104 if (tr->ctStartNew[ctN] + off > pNew) continue; 1105 if (tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctTmp] + 1]] <= tr->ctStart[ctTmp]) continue; 1106 /* TODO Actually keep track of the number produced here instead */ 1107 if (off > offset) { 1108 ctO = ctTmp; 1109 offset = off; 1110 } 1111 } 1112 rt = -1; 1113 PetscCheck(offset >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Source cell type for target point %" PetscInt_FMT " could be not found", pNew); 1114 } 1115 ctS = tr->ctStart[ctO]; 1116 ctE = tr->ctStart[tr->ctOrderOld[tr->ctOrderInvOld[ctO] + 1]]; 1117 if (trType) { 1118 for (rtS = ctS; rtS < ctE; ++rtS) { 1119 PetscInt val; 1120 PetscCall(DMLabelGetValue(trType, rtS, &val)); 1121 if (val == rt) break; 1122 } 1123 PetscCheck(rtS < ctE, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find point of type %s with refine type %" PetscInt_FMT, DMPolytopeTypes[ctO], rt); 1124 } else rtS = ctS; 1125 PetscCall(DMPlexTransformCellTransform(tr, (DMPolytopeType)ctO, rtS, &rtTmp, &Nct, &rct, &rsize, &cone, &ornt)); 1126 PetscCheck(!trType || rt == rtTmp, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " has refine type %" PetscInt_FMT " != %" PetscInt_FMT " refine type which produced point %" PetscInt_FMT, rtS, rtTmp, rt, pNew); 1127 for (n = 0; n < Nct; ++n) { 1128 if (rct[n] == ctN) { 1129 PetscInt tmp = pNew - tr->ctStartNew[ctN] - offset, val, c; 1130 1131 if (trType) { 1132 for (c = ctS; c < ctE; ++c) { 1133 PetscCall(DMLabelGetValue(trType, c, &val)); 1134 if (val == rt) { 1135 if (tmp < rsize[n]) break; 1136 tmp -= rsize[n]; 1137 } 1138 } 1139 PetscCheck(c < ctE, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Parent point for target point %" PetscInt_FMT " could be not found", pNew); 1140 rp = c - ctS; 1141 rO = tmp; 1142 } else { 1143 // This assumes that all points of type ctO transform the same way 1144 rp = tmp / rsize[n]; 1145 rO = tmp % rsize[n]; 1146 } 1147 break; 1148 } 1149 } 1150 PetscCheck(n != Nct, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Replica number for target point %" PetscInt_FMT " could be not found", pNew); 1151 pO = rp + ctS; 1152 PetscCheck(!(pO < ctS) && !(pO >= ctE), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Source point %" PetscInt_FMT " is not a %s [%" PetscInt_FMT ", %" PetscInt_FMT ")", pO, DMPolytopeTypes[ctO], ctS, ctE); 1153 if (ct) *ct = (DMPolytopeType)ctO; 1154 if (ctNew) *ctNew = ctN; 1155 if (p) *p = pO; 1156 if (r) *r = rO; 1157 PetscFunctionReturn(PETSC_SUCCESS); 1158 } 1159 1160 /*@ 1161 DMPlexTransformCellTransform - Describes the transform of a given source cell into a set of other target cells. These produced cells become the new mesh. 1162 1163 Input Parameters: 1164 + tr - The `DMPlexTransform` object 1165 . source - The source cell type 1166 - p - The source point, which can also determine the refine type 1167 1168 Output Parameters: 1169 + rt - The refine type for this point 1170 . Nt - The number of types produced by this point 1171 . target - An array of length `Nt` giving the types produced 1172 . size - An array of length `Nt` giving the number of cells of each type produced 1173 . cone - An array of length `Nt`*size[t]*coneSize[t] giving the cell type for each point in the cone of each produced point 1174 - ornt - An array of length `Nt`*size[t]*coneSize[t] giving the orientation for each point in the cone of each produced point 1175 1176 Level: advanced 1177 1178 Notes: 1179 The cone array gives the cone of each subcell listed by the first three outputs. For each cone point, we 1180 need the cell type, point identifier, and orientation within the subcell. The orientation is with respect to the canonical 1181 division (described in these outputs) of the cell in the original mesh. The point identifier is given by 1182 .vb 1183 the number of cones to be taken, or 0 for the current cell 1184 the cell cone point number at each level from which it is subdivided 1185 the replica number r of the subdivision. 1186 .ve 1187 The orientation is with respect to the canonical cone orientation. For example, the prescription for edge division is 1188 .vb 1189 Nt = 2 1190 target = {DM_POLYTOPE_POINT, DM_POLYTOPE_SEGMENT} 1191 size = {1, 2} 1192 cone = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 0, 0, DM_POLYTOPE_POINT, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0} 1193 ornt = { 0, 0, 0, 0} 1194 .ve 1195 1196 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformApply()`, `DMPlexTransformCreate()` 1197 @*/ 1198 PetscErrorCode DMPlexTransformCellTransform(DMPlexTransform tr, DMPolytopeType source, PetscInt p, PetscInt *rt, PetscInt *Nt, DMPolytopeType *target[], PetscInt *size[], PetscInt *cone[], PetscInt *ornt[]) 1199 { 1200 PetscFunctionBegin; 1201 PetscUseTypeMethod(tr, celltransform, source, p, rt, Nt, target, size, cone, ornt); 1202 PetscFunctionReturn(PETSC_SUCCESS); 1203 } 1204 1205 PetscErrorCode DMPlexTransformGetSubcellOrientationIdentity(DMPlexTransform tr, DMPolytopeType sct, PetscInt sp, PetscInt so, DMPolytopeType tct, PetscInt r, PetscInt o, PetscInt *rnew, PetscInt *onew) 1206 { 1207 PetscFunctionBegin; 1208 *rnew = r; 1209 *onew = DMPolytopeTypeComposeOrientation(tct, o, so); 1210 PetscFunctionReturn(PETSC_SUCCESS); 1211 } 1212 1213 /* Returns the same thing */ 1214 PetscErrorCode DMPlexTransformCellTransformIdentity(DMPlexTransform tr, DMPolytopeType source, PetscInt p, PetscInt *rt, PetscInt *Nt, DMPolytopeType *target[], PetscInt *size[], PetscInt *cone[], PetscInt *ornt[]) 1215 { 1216 static DMPolytopeType vertexT[] = {DM_POLYTOPE_POINT}; 1217 static PetscInt vertexS[] = {1}; 1218 static PetscInt vertexC[] = {0}; 1219 static PetscInt vertexO[] = {0}; 1220 static DMPolytopeType edgeT[] = {DM_POLYTOPE_SEGMENT}; 1221 static PetscInt edgeS[] = {1}; 1222 static PetscInt edgeC[] = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0}; 1223 static PetscInt edgeO[] = {0, 0}; 1224 static DMPolytopeType tedgeT[] = {DM_POLYTOPE_POINT_PRISM_TENSOR}; 1225 static PetscInt tedgeS[] = {1}; 1226 static PetscInt tedgeC[] = {DM_POLYTOPE_POINT, 1, 0, 0, DM_POLYTOPE_POINT, 1, 1, 0}; 1227 static PetscInt tedgeO[] = {0, 0}; 1228 static DMPolytopeType triT[] = {DM_POLYTOPE_TRIANGLE}; 1229 static PetscInt triS[] = {1}; 1230 static PetscInt triC[] = {DM_POLYTOPE_SEGMENT, 1, 0, 0, DM_POLYTOPE_SEGMENT, 1, 1, 0, DM_POLYTOPE_SEGMENT, 1, 2, 0}; 1231 static PetscInt triO[] = {0, 0, 0}; 1232 static DMPolytopeType quadT[] = {DM_POLYTOPE_QUADRILATERAL}; 1233 static PetscInt quadS[] = {1}; 1234 static PetscInt quadC[] = {DM_POLYTOPE_SEGMENT, 1, 0, 0, DM_POLYTOPE_SEGMENT, 1, 1, 0, DM_POLYTOPE_SEGMENT, 1, 2, 0, DM_POLYTOPE_SEGMENT, 1, 3, 0}; 1235 static PetscInt quadO[] = {0, 0, 0, 0}; 1236 static DMPolytopeType tquadT[] = {DM_POLYTOPE_SEG_PRISM_TENSOR}; 1237 static PetscInt tquadS[] = {1}; 1238 static PetscInt tquadC[] = {DM_POLYTOPE_SEGMENT, 1, 0, 0, DM_POLYTOPE_SEGMENT, 1, 1, 0, DM_POLYTOPE_POINT_PRISM_TENSOR, 1, 2, 0, DM_POLYTOPE_POINT_PRISM_TENSOR, 1, 3, 0}; 1239 static PetscInt tquadO[] = {0, 0, 0, 0}; 1240 static DMPolytopeType tetT[] = {DM_POLYTOPE_TETRAHEDRON}; 1241 static PetscInt tetS[] = {1}; 1242 static PetscInt tetC[] = {DM_POLYTOPE_TRIANGLE, 1, 0, 0, DM_POLYTOPE_TRIANGLE, 1, 1, 0, DM_POLYTOPE_TRIANGLE, 1, 2, 0, DM_POLYTOPE_TRIANGLE, 1, 3, 0}; 1243 static PetscInt tetO[] = {0, 0, 0, 0}; 1244 static DMPolytopeType hexT[] = {DM_POLYTOPE_HEXAHEDRON}; 1245 static PetscInt hexS[] = {1}; 1246 static PetscInt hexC[] = {DM_POLYTOPE_QUADRILATERAL, 1, 0, 0, DM_POLYTOPE_QUADRILATERAL, 1, 1, 0, DM_POLYTOPE_QUADRILATERAL, 1, 2, 0, DM_POLYTOPE_QUADRILATERAL, 1, 3, 0, DM_POLYTOPE_QUADRILATERAL, 1, 4, 0, DM_POLYTOPE_QUADRILATERAL, 1, 5, 0}; 1247 static PetscInt hexO[] = {0, 0, 0, 0, 0, 0}; 1248 static DMPolytopeType tripT[] = {DM_POLYTOPE_TRI_PRISM}; 1249 static PetscInt tripS[] = {1}; 1250 static PetscInt tripC[] = {DM_POLYTOPE_TRIANGLE, 1, 0, 0, DM_POLYTOPE_TRIANGLE, 1, 1, 0, DM_POLYTOPE_QUADRILATERAL, 1, 2, 0, DM_POLYTOPE_QUADRILATERAL, 1, 3, 0, DM_POLYTOPE_QUADRILATERAL, 1, 4, 0}; 1251 static PetscInt tripO[] = {0, 0, 0, 0, 0}; 1252 static DMPolytopeType ttripT[] = {DM_POLYTOPE_TRI_PRISM_TENSOR}; 1253 static PetscInt ttripS[] = {1}; 1254 static PetscInt ttripC[] = {DM_POLYTOPE_TRIANGLE, 1, 0, 0, DM_POLYTOPE_TRIANGLE, 1, 1, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 2, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 3, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 4, 0}; 1255 static PetscInt ttripO[] = {0, 0, 0, 0, 0}; 1256 static DMPolytopeType tquadpT[] = {DM_POLYTOPE_QUAD_PRISM_TENSOR}; 1257 static PetscInt tquadpS[] = {1}; 1258 static PetscInt tquadpC[] = {DM_POLYTOPE_QUADRILATERAL, 1, 0, 0, DM_POLYTOPE_QUADRILATERAL, 1, 1, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 2, 0, 1259 DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 3, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 4, 0, DM_POLYTOPE_SEG_PRISM_TENSOR, 1, 5, 0}; 1260 static PetscInt tquadpO[] = {0, 0, 0, 0, 0, 0}; 1261 static DMPolytopeType pyrT[] = {DM_POLYTOPE_PYRAMID}; 1262 static PetscInt pyrS[] = {1}; 1263 static PetscInt pyrC[] = {DM_POLYTOPE_QUADRILATERAL, 1, 0, 0, DM_POLYTOPE_TRIANGLE, 1, 1, 0, DM_POLYTOPE_TRIANGLE, 1, 2, 0, DM_POLYTOPE_TRIANGLE, 1, 3, 0, DM_POLYTOPE_TRIANGLE, 1, 4, 0}; 1264 static PetscInt pyrO[] = {0, 0, 0, 0, 0}; 1265 1266 PetscFunctionBegin; 1267 if (rt) *rt = 0; 1268 switch (source) { 1269 case DM_POLYTOPE_POINT: 1270 *Nt = 1; 1271 *target = vertexT; 1272 *size = vertexS; 1273 *cone = vertexC; 1274 *ornt = vertexO; 1275 break; 1276 case DM_POLYTOPE_SEGMENT: 1277 *Nt = 1; 1278 *target = edgeT; 1279 *size = edgeS; 1280 *cone = edgeC; 1281 *ornt = edgeO; 1282 break; 1283 case DM_POLYTOPE_POINT_PRISM_TENSOR: 1284 *Nt = 1; 1285 *target = tedgeT; 1286 *size = tedgeS; 1287 *cone = tedgeC; 1288 *ornt = tedgeO; 1289 break; 1290 case DM_POLYTOPE_TRIANGLE: 1291 *Nt = 1; 1292 *target = triT; 1293 *size = triS; 1294 *cone = triC; 1295 *ornt = triO; 1296 break; 1297 case DM_POLYTOPE_QUADRILATERAL: 1298 *Nt = 1; 1299 *target = quadT; 1300 *size = quadS; 1301 *cone = quadC; 1302 *ornt = quadO; 1303 break; 1304 case DM_POLYTOPE_SEG_PRISM_TENSOR: 1305 *Nt = 1; 1306 *target = tquadT; 1307 *size = tquadS; 1308 *cone = tquadC; 1309 *ornt = tquadO; 1310 break; 1311 case DM_POLYTOPE_TETRAHEDRON: 1312 *Nt = 1; 1313 *target = tetT; 1314 *size = tetS; 1315 *cone = tetC; 1316 *ornt = tetO; 1317 break; 1318 case DM_POLYTOPE_HEXAHEDRON: 1319 *Nt = 1; 1320 *target = hexT; 1321 *size = hexS; 1322 *cone = hexC; 1323 *ornt = hexO; 1324 break; 1325 case DM_POLYTOPE_TRI_PRISM: 1326 *Nt = 1; 1327 *target = tripT; 1328 *size = tripS; 1329 *cone = tripC; 1330 *ornt = tripO; 1331 break; 1332 case DM_POLYTOPE_TRI_PRISM_TENSOR: 1333 *Nt = 1; 1334 *target = ttripT; 1335 *size = ttripS; 1336 *cone = ttripC; 1337 *ornt = ttripO; 1338 break; 1339 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 1340 *Nt = 1; 1341 *target = tquadpT; 1342 *size = tquadpS; 1343 *cone = tquadpC; 1344 *ornt = tquadpO; 1345 break; 1346 case DM_POLYTOPE_PYRAMID: 1347 *Nt = 1; 1348 *target = pyrT; 1349 *size = pyrS; 1350 *cone = pyrC; 1351 *ornt = pyrO; 1352 break; 1353 default: 1354 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No refinement strategy for %s", DMPolytopeTypes[source]); 1355 } 1356 PetscFunctionReturn(PETSC_SUCCESS); 1357 } 1358 1359 /*@ 1360 DMPlexTransformGetSubcellOrientation - Transform the replica number and orientation for a target point according to the group action for the source point 1361 1362 Not Collective 1363 1364 Input Parameters: 1365 + tr - The `DMPlexTransform` 1366 . sct - The source point cell type, from whom the new cell is being produced 1367 . sp - The source point 1368 . so - The orientation of the source point in its enclosing parent 1369 . tct - The target point cell type 1370 . r - The replica number requested for the produced cell type 1371 - o - The orientation of the replica 1372 1373 Output Parameters: 1374 + rnew - The replica number, given the orientation of the parent 1375 - onew - The replica orientation, given the orientation of the parent 1376 1377 Level: advanced 1378 1379 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformCellTransform()`, `DMPlexTransformApply()` 1380 @*/ 1381 PetscErrorCode DMPlexTransformGetSubcellOrientation(DMPlexTransform tr, DMPolytopeType sct, PetscInt sp, PetscInt so, DMPolytopeType tct, PetscInt r, PetscInt o, PetscInt *rnew, PetscInt *onew) 1382 { 1383 PetscFunctionBeginHot; 1384 PetscUseTypeMethod(tr, getsubcellorientation, sct, sp, so, tct, r, o, rnew, onew); 1385 PetscFunctionReturn(PETSC_SUCCESS); 1386 } 1387 1388 static PetscErrorCode DMPlexTransformSetConeSizes(DMPlexTransform tr, DM rdm) 1389 { 1390 DM dm; 1391 PetscInt pStart, pEnd, pNew; 1392 1393 PetscFunctionBegin; 1394 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1395 PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetConeSizes, tr, dm, 0, 0)); 1396 /* Must create the celltype label here so that we do not automatically try to compute the types */ 1397 PetscCall(DMCreateLabel(rdm, "celltype")); 1398 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1399 for (PetscInt p = pStart; p < pEnd; ++p) { 1400 DMPolytopeType ct; 1401 DMPolytopeType *rct; 1402 PetscInt *rsize, *rcone, *rornt; 1403 PetscInt Nct, n, r; 1404 1405 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1406 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 1407 for (n = 0; n < Nct; ++n) { 1408 for (r = 0; r < rsize[n]; ++r) { 1409 PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew)); 1410 PetscCall(DMPlexSetConeSize(rdm, pNew, DMPolytopeTypeGetConeSize(rct[n]))); 1411 PetscCall(DMPlexSetCellType(rdm, pNew, rct[n])); 1412 } 1413 } 1414 } 1415 /* Let the DM know we have set all the cell types */ 1416 { 1417 DMLabel ctLabel; 1418 DM_Plex *plex = (DM_Plex *)rdm->data; 1419 1420 PetscCall(DMPlexGetCellTypeLabel(rdm, &ctLabel)); 1421 PetscCall(PetscObjectStateGet((PetscObject)ctLabel, &plex->celltypeState)); 1422 } 1423 PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetConeSizes, tr, dm, 0, 0)); 1424 PetscFunctionReturn(PETSC_SUCCESS); 1425 } 1426 1427 PetscErrorCode DMPlexTransformGetConeSize(DMPlexTransform tr, PetscInt q, PetscInt *coneSize) 1428 { 1429 DMPolytopeType ctNew; 1430 1431 PetscFunctionBegin; 1432 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 1433 PetscAssertPointer(coneSize, 3); 1434 PetscCall(DMPlexTransformGetCellType(tr, q, &ctNew)); 1435 *coneSize = DMPolytopeTypeGetConeSize(ctNew); 1436 PetscFunctionReturn(PETSC_SUCCESS); 1437 } 1438 1439 /* The orientation o is for the interior of the cell p */ 1440 static PetscErrorCode DMPlexTransformGetCone_Internal(DMPlexTransform tr, PetscInt p, PetscInt o, DMPolytopeType ct, DMPolytopeType ctNew, const PetscInt rcone[], PetscInt *coneoff, const PetscInt rornt[], PetscInt *orntoff, PetscInt coneNew[], PetscInt orntNew[]) 1441 { 1442 DM dm; 1443 const PetscInt csizeNew = DMPolytopeTypeGetConeSize(ctNew); 1444 const PetscInt *cone; 1445 PetscInt c, coff = *coneoff, ooff = *orntoff; 1446 1447 PetscFunctionBegin; 1448 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1449 PetscCall(DMPlexGetOrientedCone(dm, p, &cone, NULL)); 1450 for (c = 0; c < csizeNew; ++c) { 1451 PetscInt ppp = -1; /* Parent Parent point: Parent of point pp */ 1452 PetscInt pp = p; /* Parent point: Point in the original mesh producing new cone point */ 1453 PetscInt po = 0; /* Orientation of parent point pp in parent parent point ppp */ 1454 DMPolytopeType pct = ct; /* Parent type: Cell type for parent of new cone point */ 1455 const PetscInt *pcone = cone; /* Parent cone: Cone of parent point pp */ 1456 PetscInt pr = -1; /* Replica number of pp that produces new cone point */ 1457 const DMPolytopeType ft = (DMPolytopeType)rcone[coff++]; /* Cell type for new cone point of pNew */ 1458 const PetscInt fn = rcone[coff++]; /* Number of cones of p that need to be taken when producing new cone point */ 1459 PetscInt fo = rornt[ooff++]; /* Orientation of new cone point in pNew */ 1460 PetscInt lc; 1461 1462 /* Get the type (pct) and point number (pp) of the parent point in the original mesh which produces this cone point */ 1463 for (lc = 0; lc < fn; ++lc) { 1464 const PetscInt *parr = DMPolytopeTypeGetArrangement(pct, po); 1465 const PetscInt acp = rcone[coff++]; 1466 const PetscInt pcp = parr[acp * 2]; 1467 const PetscInt pco = parr[acp * 2 + 1]; 1468 const PetscInt *ppornt; 1469 1470 ppp = pp; 1471 pp = pcone[pcp]; 1472 PetscCall(DMPlexGetCellType(dm, pp, &pct)); 1473 // Restore the parent cone from the last iterate 1474 if (lc) PetscCall(DMPlexRestoreOrientedCone(dm, ppp, &pcone, NULL)); 1475 PetscCall(DMPlexGetOrientedCone(dm, pp, &pcone, NULL)); 1476 PetscCall(DMPlexGetOrientedCone(dm, ppp, NULL, &ppornt)); 1477 po = DMPolytopeTypeComposeOrientation(pct, ppornt[pcp], pco); 1478 PetscCall(DMPlexRestoreOrientedCone(dm, ppp, NULL, &ppornt)); 1479 } 1480 if (lc) PetscCall(DMPlexRestoreOrientedCone(dm, pp, &pcone, NULL)); 1481 pr = rcone[coff++]; 1482 /* Orientation po of pp maps (pr, fo) -> (pr', fo') */ 1483 PetscCall(DMPlexTransformGetSubcellOrientation(tr, pct, pp, fn ? po : o, ft, pr, fo, &pr, &fo)); 1484 PetscCall(DMPlexTransformGetTargetPoint(tr, pct, ft, pp, pr, &coneNew[c])); 1485 orntNew[c] = fo; 1486 } 1487 PetscCall(DMPlexRestoreOrientedCone(dm, p, &cone, NULL)); 1488 *coneoff = coff; 1489 *orntoff = ooff; 1490 PetscFunctionReturn(PETSC_SUCCESS); 1491 } 1492 1493 static PetscErrorCode DMPlexTransformSetCones(DMPlexTransform tr, DM rdm) 1494 { 1495 DM dm; 1496 DMPolytopeType ct; 1497 PetscInt *coneNew, *orntNew; 1498 PetscInt maxConeSize = 0, pStart, pEnd, p, pNew; 1499 1500 PetscFunctionBegin; 1501 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1502 PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetCones, tr, dm, 0, 0)); 1503 for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p)); 1504 PetscCall(DMGetWorkArray(rdm, maxConeSize, MPIU_INT, &coneNew)); 1505 PetscCall(DMGetWorkArray(rdm, maxConeSize, MPIU_INT, &orntNew)); 1506 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1507 for (p = pStart; p < pEnd; ++p) { 1508 PetscInt coff, ooff; 1509 DMPolytopeType *rct; 1510 PetscInt *rsize, *rcone, *rornt; 1511 PetscInt Nct, n, r; 1512 1513 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1514 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 1515 for (n = 0, coff = 0, ooff = 0; n < Nct; ++n) { 1516 const DMPolytopeType ctNew = rct[n]; 1517 1518 for (r = 0; r < rsize[n]; ++r) { 1519 PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew)); 1520 PetscCall(DMPlexTransformGetCone_Internal(tr, p, 0, ct, ctNew, rcone, &coff, rornt, &ooff, coneNew, orntNew)); 1521 PetscCall(DMPlexSetCone(rdm, pNew, coneNew)); 1522 PetscCall(DMPlexSetConeOrientation(rdm, pNew, orntNew)); 1523 } 1524 } 1525 } 1526 PetscCall(DMRestoreWorkArray(rdm, maxConeSize, MPIU_INT, &coneNew)); 1527 PetscCall(DMRestoreWorkArray(rdm, maxConeSize, MPIU_INT, &orntNew)); 1528 PetscCall(DMViewFromOptions(rdm, NULL, "-rdm_view")); 1529 PetscCall(DMPlexSymmetrize(rdm)); 1530 PetscCall(DMPlexStratify(rdm)); 1531 PetscTryTypeMethod(tr, ordersupports, dm, rdm); 1532 PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetCones, tr, dm, 0, 0)); 1533 PetscFunctionReturn(PETSC_SUCCESS); 1534 } 1535 1536 PetscErrorCode DMPlexTransformGetConeOriented(DMPlexTransform tr, PetscInt q, PetscInt po, const PetscInt *cone[], const PetscInt *ornt[]) 1537 { 1538 DM dm; 1539 DMPolytopeType ct, qct; 1540 DMPolytopeType *rct; 1541 PetscInt *rsize, *rcone, *rornt, *qcone, *qornt; 1542 PetscInt maxConeSize = 0, Nct, p, r, n, nr, coff = 0, ooff = 0; 1543 1544 PetscFunctionBegin; 1545 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 1546 PetscAssertPointer(cone, 4); 1547 PetscAssertPointer(ornt, 5); 1548 for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p)); 1549 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1550 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qcone)); 1551 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qornt)); 1552 PetscCall(DMPlexTransformGetSourcePoint(tr, q, &ct, &qct, &p, &r)); 1553 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 1554 for (n = 0; n < Nct; ++n) { 1555 const DMPolytopeType ctNew = rct[n]; 1556 const PetscInt csizeNew = DMPolytopeTypeGetConeSize(ctNew); 1557 PetscInt Nr = rsize[n], fn, c; 1558 1559 if (ctNew == qct) Nr = r; 1560 for (nr = 0; nr < Nr; ++nr) { 1561 for (c = 0; c < csizeNew; ++c) { 1562 ++coff; /* Cell type of new cone point */ 1563 fn = rcone[coff++]; /* Number of cones of p that need to be taken when producing new cone point */ 1564 coff += fn; 1565 ++coff; /* Replica number of new cone point */ 1566 ++ooff; /* Orientation of new cone point */ 1567 } 1568 } 1569 if (ctNew == qct) break; 1570 } 1571 PetscCall(DMPlexTransformGetCone_Internal(tr, p, po, ct, qct, rcone, &coff, rornt, &ooff, qcone, qornt)); 1572 *cone = qcone; 1573 *ornt = qornt; 1574 PetscFunctionReturn(PETSC_SUCCESS); 1575 } 1576 1577 PetscErrorCode DMPlexTransformGetCone(DMPlexTransform tr, PetscInt q, const PetscInt *cone[], const PetscInt *ornt[]) 1578 { 1579 DM dm; 1580 DMPolytopeType ct, qct; 1581 DMPolytopeType *rct; 1582 PetscInt *rsize, *rcone, *rornt, *qcone, *qornt; 1583 PetscInt maxConeSize = 0, Nct, p, r, n, nr, coff = 0, ooff = 0; 1584 1585 PetscFunctionBegin; 1586 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 1587 if (cone) PetscAssertPointer(cone, 3); 1588 if (ornt) PetscAssertPointer(ornt, 4); 1589 for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p)); 1590 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1591 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qcone)); 1592 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qornt)); 1593 PetscCall(DMPlexTransformGetSourcePoint(tr, q, &ct, &qct, &p, &r)); 1594 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 1595 for (n = 0; n < Nct; ++n) { 1596 const DMPolytopeType ctNew = rct[n]; 1597 const PetscInt csizeNew = DMPolytopeTypeGetConeSize(ctNew); 1598 PetscInt Nr = rsize[n], fn, c; 1599 1600 if (ctNew == qct) Nr = r; 1601 for (nr = 0; nr < Nr; ++nr) { 1602 for (c = 0; c < csizeNew; ++c) { 1603 ++coff; /* Cell type of new cone point */ 1604 fn = rcone[coff++]; /* Number of cones of p that need to be taken when producing new cone point */ 1605 coff += fn; 1606 ++coff; /* Replica number of new cone point */ 1607 ++ooff; /* Orientation of new cone point */ 1608 } 1609 } 1610 if (ctNew == qct) break; 1611 } 1612 PetscCall(DMPlexTransformGetCone_Internal(tr, p, 0, ct, qct, rcone, &coff, rornt, &ooff, qcone, qornt)); 1613 if (cone) *cone = qcone; 1614 else PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &qcone)); 1615 if (ornt) *ornt = qornt; 1616 else PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &qornt)); 1617 PetscFunctionReturn(PETSC_SUCCESS); 1618 } 1619 1620 PetscErrorCode DMPlexTransformRestoreCone(DMPlexTransform tr, PetscInt q, const PetscInt *cone[], const PetscInt *ornt[]) 1621 { 1622 DM dm; 1623 1624 PetscFunctionBegin; 1625 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 1626 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1627 if (cone) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, cone)); 1628 if (ornt) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, ornt)); 1629 PetscFunctionReturn(PETSC_SUCCESS); 1630 } 1631 1632 static PetscErrorCode DMPlexTransformCreateCellVertices_Internal(DMPlexTransform tr) 1633 { 1634 PetscInt ict; 1635 1636 PetscFunctionBegin; 1637 PetscCall(PetscCalloc3(DM_NUM_POLYTOPES, &tr->trNv, DM_NUM_POLYTOPES, &tr->trVerts, DM_NUM_POLYTOPES, &tr->trSubVerts)); 1638 for (ict = DM_POLYTOPE_POINT; ict < DM_NUM_POLYTOPES; ++ict) { 1639 const DMPolytopeType ct = (DMPolytopeType)ict; 1640 DMPlexTransform reftr; 1641 DM refdm, trdm; 1642 Vec coordinates; 1643 const PetscScalar *coords; 1644 DMPolytopeType *rct; 1645 PetscInt *rsize, *rcone, *rornt; 1646 PetscInt Nct, n, r, pNew = 0; 1647 PetscInt trdim, vStart, vEnd, Nc; 1648 const PetscInt debug = 0; 1649 const char *typeName; 1650 1651 /* Since points are 0-dimensional, coordinates make no sense */ 1652 if (DMPolytopeTypeGetDim(ct) <= 0 || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) continue; 1653 PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, ct, &refdm)); 1654 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &reftr)); 1655 PetscCall(DMPlexTransformSetDM(reftr, refdm)); 1656 PetscCall(DMPlexTransformGetType(tr, &typeName)); 1657 PetscCall(DMPlexTransformSetType(reftr, typeName)); 1658 PetscCall(DMPlexTransformSetUp(reftr)); 1659 PetscCall(DMPlexTransformApply(reftr, refdm, &trdm)); 1660 1661 PetscCall(DMGetDimension(trdm, &trdim)); 1662 PetscCall(DMPlexGetDepthStratum(trdm, 0, &vStart, &vEnd)); 1663 tr->trNv[ct] = vEnd - vStart; 1664 PetscCall(DMGetCoordinatesLocal(trdm, &coordinates)); 1665 PetscCall(VecGetLocalSize(coordinates, &Nc)); 1666 PetscCheck(tr->trNv[ct] * trdim == Nc, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cell type %s, transformed coordinate size %" PetscInt_FMT " != %" PetscInt_FMT " size of coordinate storage", DMPolytopeTypes[ct], tr->trNv[ct] * trdim, Nc); 1667 PetscCall(PetscCalloc1(Nc, &tr->trVerts[ct])); 1668 PetscCall(VecGetArrayRead(coordinates, &coords)); 1669 PetscCall(PetscArraycpy(tr->trVerts[ct], coords, Nc)); 1670 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1671 1672 PetscCall(PetscCalloc1(DM_NUM_POLYTOPES, &tr->trSubVerts[ct])); 1673 PetscCall(DMPlexTransformCellTransform(reftr, ct, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 1674 for (n = 0; n < Nct; ++n) { 1675 /* Since points are 0-dimensional, coordinates make no sense */ 1676 if (rct[n] == DM_POLYTOPE_POINT) continue; 1677 PetscCall(PetscCalloc1(rsize[n], &tr->trSubVerts[ct][rct[n]])); 1678 for (r = 0; r < rsize[n]; ++r) { 1679 PetscInt *closure = NULL; 1680 PetscInt clSize, cl, Nv = 0; 1681 1682 PetscCall(PetscCalloc1(DMPolytopeTypeGetNumVertices(rct[n]), &tr->trSubVerts[ct][rct[n]][r])); 1683 PetscCall(DMPlexTransformGetTargetPoint(reftr, ct, rct[n], 0, r, &pNew)); 1684 PetscCall(DMPlexGetTransitiveClosure(trdm, pNew, PETSC_TRUE, &clSize, &closure)); 1685 for (cl = 0; cl < clSize * 2; cl += 2) { 1686 const PetscInt sv = closure[cl]; 1687 1688 if ((sv >= vStart) && (sv < vEnd)) tr->trSubVerts[ct][rct[n]][r][Nv++] = sv - vStart; 1689 } 1690 PetscCall(DMPlexRestoreTransitiveClosure(trdm, pNew, PETSC_TRUE, &clSize, &closure)); 1691 PetscCheck(Nv == DMPolytopeTypeGetNumVertices(rct[n]), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of vertices %" PetscInt_FMT " != %" PetscInt_FMT " for %s subcell %" PetscInt_FMT " from cell %s", Nv, DMPolytopeTypeGetNumVertices(rct[n]), DMPolytopeTypes[rct[n]], r, DMPolytopeTypes[ct]); 1692 } 1693 } 1694 if (debug) { 1695 DMPolytopeType *rct; 1696 PetscInt *rsize, *rcone, *rornt; 1697 PetscInt v, dE = trdim, d, off = 0; 1698 1699 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s: %" PetscInt_FMT " vertices\n", DMPolytopeTypes[ct], tr->trNv[ct])); 1700 for (v = 0; v < tr->trNv[ct]; ++v) { 1701 PetscCall(PetscPrintf(PETSC_COMM_SELF, " ")); 1702 for (d = 0; d < dE; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g ", (double)PetscRealPart(tr->trVerts[ct][off++]))); 1703 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 1704 } 1705 1706 PetscCall(DMPlexTransformCellTransform(reftr, ct, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 1707 for (n = 0; n < Nct; ++n) { 1708 if (rct[n] == DM_POLYTOPE_POINT) continue; 1709 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s: %s subvertices %" PetscInt_FMT "\n", DMPolytopeTypes[ct], DMPolytopeTypes[rct[n]], tr->trNv[ct])); 1710 for (r = 0; r < rsize[n]; ++r) { 1711 PetscCall(PetscPrintf(PETSC_COMM_SELF, " ")); 1712 for (v = 0; v < DMPolytopeTypeGetNumVertices(rct[n]); ++v) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT " ", tr->trSubVerts[ct][rct[n]][r][v])); 1713 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 1714 } 1715 } 1716 } 1717 PetscCall(DMDestroy(&refdm)); 1718 PetscCall(DMDestroy(&trdm)); 1719 PetscCall(DMPlexTransformDestroy(&reftr)); 1720 } 1721 PetscFunctionReturn(PETSC_SUCCESS); 1722 } 1723 1724 /*@C 1725 DMPlexTransformGetCellVertices - Get the set of transformed vertices lying in the closure of a reference cell of given type 1726 1727 Input Parameters: 1728 + tr - The `DMPlexTransform` object 1729 - ct - The cell type 1730 1731 Output Parameters: 1732 + Nv - The number of transformed vertices in the closure of the reference cell of given type 1733 - trVerts - The coordinates of these vertices in the reference cell 1734 1735 Level: developer 1736 1737 .seealso: `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetSubcellVertices()` 1738 @*/ 1739 PetscErrorCode DMPlexTransformGetCellVertices(DMPlexTransform tr, DMPolytopeType ct, PetscInt *Nv, PetscScalar *trVerts[]) 1740 { 1741 PetscFunctionBegin; 1742 if (!tr->trNv) PetscCall(DMPlexTransformCreateCellVertices_Internal(tr)); 1743 if (Nv) *Nv = tr->trNv[ct]; 1744 if (trVerts) *trVerts = tr->trVerts[ct]; 1745 PetscFunctionReturn(PETSC_SUCCESS); 1746 } 1747 1748 /*@C 1749 DMPlexTransformGetSubcellVertices - Get the set of transformed vertices defining a subcell in the reference cell of given type 1750 1751 Input Parameters: 1752 + tr - The `DMPlexTransform` object 1753 . ct - The cell type 1754 . rct - The subcell type 1755 - r - The subcell index 1756 1757 Output Parameter: 1758 . subVerts - The indices of these vertices in the set of vertices returned by `DMPlexTransformGetCellVertices()` 1759 1760 Level: developer 1761 1762 .seealso: `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetCellVertices()` 1763 @*/ 1764 PetscErrorCode DMPlexTransformGetSubcellVertices(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType rct, PetscInt r, PetscInt *subVerts[]) 1765 { 1766 PetscFunctionBegin; 1767 if (!tr->trNv) PetscCall(DMPlexTransformCreateCellVertices_Internal(tr)); 1768 PetscCheck(tr->trSubVerts[ct][rct], PetscObjectComm((PetscObject)tr), PETSC_ERR_ARG_WRONG, "Cell type %s does not produce %s", DMPolytopeTypes[ct], DMPolytopeTypes[rct]); 1769 if (subVerts) *subVerts = tr->trSubVerts[ct][rct][r]; 1770 PetscFunctionReturn(PETSC_SUCCESS); 1771 } 1772 1773 /* Computes new vertex as the barycenter, or centroid */ 1774 PetscErrorCode DMPlexTransformMapCoordinatesBarycenter_Internal(DMPlexTransform tr, DMPolytopeType pct, DMPolytopeType ct, PetscInt p, PetscInt r, PetscInt Nv, PetscInt dE, const PetscScalar in[], PetscScalar out[]) 1775 { 1776 PetscInt v, d; 1777 1778 PetscFunctionBeginHot; 1779 PetscCheck(ct == DM_POLYTOPE_POINT, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for refined point type %s", DMPolytopeTypes[ct]); 1780 for (d = 0; d < dE; ++d) out[d] = 0.0; 1781 for (v = 0; v < Nv; ++v) 1782 for (d = 0; d < dE; ++d) out[d] += in[v * dE + d]; 1783 for (d = 0; d < dE; ++d) out[d] /= Nv; 1784 PetscFunctionReturn(PETSC_SUCCESS); 1785 } 1786 1787 /*@ 1788 DMPlexTransformMapCoordinates - Calculate new coordinates for produced points 1789 1790 Not collective 1791 1792 Input Parameters: 1793 + tr - The `DMPlexTransform` 1794 . pct - The cell type of the parent, from whom the new cell is being produced 1795 . ct - The type being produced 1796 . p - The original point 1797 . r - The replica number requested for the produced cell type 1798 . Nv - Number of vertices in the closure of the parent cell 1799 . dE - Spatial dimension 1800 - in - array of size Nv*dE, holding coordinates of the vertices in the closure of the parent cell 1801 1802 Output Parameter: 1803 . out - The coordinates of the new vertices 1804 1805 Level: intermediate 1806 1807 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformApply()` 1808 @*/ 1809 PetscErrorCode DMPlexTransformMapCoordinates(DMPlexTransform tr, DMPolytopeType pct, DMPolytopeType ct, PetscInt p, PetscInt r, PetscInt Nv, PetscInt dE, const PetscScalar in[], PetscScalar out[]) 1810 { 1811 PetscFunctionBeginHot; 1812 if (Nv) PetscUseTypeMethod(tr, mapcoordinates, pct, ct, p, r, Nv, dE, in, out); 1813 PetscFunctionReturn(PETSC_SUCCESS); 1814 } 1815 1816 /* 1817 DMPlexTransformLabelProducedPoint_Private - Label a produced point based on its parent label 1818 1819 Not Collective 1820 1821 Input Parameters: 1822 + tr - The `DMPlexTransform` 1823 . label - The label in the transformed mesh 1824 . pp - The parent point in the original mesh 1825 . pct - The cell type of the parent point 1826 . p - The point in the transformed mesh 1827 . ct - The cell type of the point 1828 . r - The replica number of the point 1829 - val - The label value of the parent point 1830 1831 Level: developer 1832 1833 .seealso: `DMPlexTransformCreateLabels()`, `RefineLabel_Internal()` 1834 */ 1835 static PetscErrorCode DMPlexTransformLabelProducedPoint_Private(DMPlexTransform tr, DMLabel label, PetscInt pp, DMPolytopeType pct, PetscInt p, DMPolytopeType ct, PetscInt r, PetscInt val) 1836 { 1837 PetscFunctionBeginHot; 1838 if (tr->labelMatchStrata && pct != ct) PetscFunctionReturn(PETSC_SUCCESS); 1839 PetscCall(DMLabelSetValue(label, p, val + tr->labelReplicaInc * r)); 1840 PetscFunctionReturn(PETSC_SUCCESS); 1841 } 1842 1843 static PetscErrorCode RefineLabel_Internal(DMPlexTransform tr, DMLabel label, DMLabel labelNew) 1844 { 1845 DM dm; 1846 IS valueIS; 1847 const PetscInt *values; 1848 PetscInt defVal, Nv, val; 1849 1850 PetscFunctionBegin; 1851 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1852 PetscCall(DMLabelGetDefaultValue(label, &defVal)); 1853 PetscCall(DMLabelSetDefaultValue(labelNew, defVal)); 1854 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1855 PetscCall(ISGetLocalSize(valueIS, &Nv)); 1856 PetscCall(ISGetIndices(valueIS, &values)); 1857 for (val = 0; val < Nv; ++val) { 1858 IS pointIS; 1859 const PetscInt *points; 1860 PetscInt numPoints, p; 1861 1862 /* Ensure refined label is created with same number of strata as 1863 * original (even if no entries here). */ 1864 PetscCall(DMLabelAddStratum(labelNew, values[val])); 1865 PetscCall(DMLabelGetStratumIS(label, values[val], &pointIS)); 1866 PetscCall(ISGetLocalSize(pointIS, &numPoints)); 1867 PetscCall(ISGetIndices(pointIS, &points)); 1868 for (p = 0; p < numPoints; ++p) { 1869 const PetscInt point = points[p]; 1870 DMPolytopeType ct; 1871 DMPolytopeType *rct; 1872 PetscInt *rsize, *rcone, *rornt; 1873 PetscInt Nct, n, r, pNew = 0; 1874 1875 PetscCall(DMPlexGetCellType(dm, point, &ct)); 1876 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 1877 for (n = 0; n < Nct; ++n) { 1878 for (r = 0; r < rsize[n]; ++r) { 1879 PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], point, r, &pNew)); 1880 PetscCall(DMPlexTransformLabelProducedPoint_Private(tr, labelNew, point, ct, pNew, rct[n], r, values[val])); 1881 } 1882 } 1883 } 1884 PetscCall(ISRestoreIndices(pointIS, &points)); 1885 PetscCall(ISDestroy(&pointIS)); 1886 } 1887 PetscCall(ISRestoreIndices(valueIS, &values)); 1888 PetscCall(ISDestroy(&valueIS)); 1889 PetscFunctionReturn(PETSC_SUCCESS); 1890 } 1891 1892 static PetscErrorCode DMPlexTransformCreateLabels(DMPlexTransform tr, DM rdm) 1893 { 1894 DM dm; 1895 PetscInt numLabels, l; 1896 1897 PetscFunctionBegin; 1898 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1899 PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_CreateLabels, tr, dm, 0, 0)); 1900 PetscCall(DMGetNumLabels(dm, &numLabels)); 1901 for (l = 0; l < numLabels; ++l) { 1902 DMLabel label, labelNew; 1903 const char *lname; 1904 PetscBool isDepth, isCellType; 1905 1906 PetscCall(DMGetLabelName(dm, l, &lname)); 1907 PetscCall(PetscStrcmp(lname, "depth", &isDepth)); 1908 if (isDepth) continue; 1909 PetscCall(PetscStrcmp(lname, "celltype", &isCellType)); 1910 if (isCellType) continue; 1911 PetscCall(DMCreateLabel(rdm, lname)); 1912 PetscCall(DMGetLabel(dm, lname, &label)); 1913 PetscCall(DMGetLabel(rdm, lname, &labelNew)); 1914 PetscCall(RefineLabel_Internal(tr, label, labelNew)); 1915 } 1916 PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_CreateLabels, tr, dm, 0, 0)); 1917 PetscFunctionReturn(PETSC_SUCCESS); 1918 } 1919 1920 /* This refines the labels which define regions for fields and DSes since they are not in the list of labels for the DM */ 1921 PetscErrorCode DMPlexTransformCreateDiscLabels(DMPlexTransform tr, DM rdm) 1922 { 1923 DM dm; 1924 PetscInt Nf, f, Nds, s; 1925 1926 PetscFunctionBegin; 1927 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1928 PetscCall(DMGetNumFields(dm, &Nf)); 1929 for (f = 0; f < Nf; ++f) { 1930 DMLabel label, labelNew; 1931 PetscObject obj; 1932 const char *lname; 1933 1934 PetscCall(DMGetField(rdm, f, &label, &obj)); 1935 if (!label) continue; 1936 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 1937 PetscCall(DMLabelCreate(PETSC_COMM_SELF, lname, &labelNew)); 1938 PetscCall(RefineLabel_Internal(tr, label, labelNew)); 1939 PetscCall(DMSetField_Internal(rdm, f, labelNew, obj)); 1940 PetscCall(DMLabelDestroy(&labelNew)); 1941 } 1942 PetscCall(DMGetNumDS(dm, &Nds)); 1943 for (s = 0; s < Nds; ++s) { 1944 DMLabel label, labelNew; 1945 const char *lname; 1946 1947 PetscCall(DMGetRegionNumDS(rdm, s, &label, NULL, NULL, NULL)); 1948 if (!label) continue; 1949 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 1950 PetscCall(DMLabelCreate(PETSC_COMM_SELF, lname, &labelNew)); 1951 PetscCall(RefineLabel_Internal(tr, label, labelNew)); 1952 PetscCall(DMSetRegionNumDS(rdm, s, labelNew, NULL, NULL, NULL)); 1953 PetscCall(DMLabelDestroy(&labelNew)); 1954 } 1955 PetscFunctionReturn(PETSC_SUCCESS); 1956 } 1957 1958 static PetscErrorCode DMPlexTransformCreateSF(DMPlexTransform tr, DM rdm) 1959 { 1960 DM dm; 1961 PetscSF sf, sfNew; 1962 PetscInt numRoots, numLeaves, numLeavesNew = 0, l, m; 1963 const PetscInt *localPoints; 1964 const PetscSFNode *remotePoints; 1965 PetscInt *localPointsNew; 1966 PetscSFNode *remotePointsNew; 1967 PetscInt pStartNew, pEndNew, pNew; 1968 /* Brute force algorithm */ 1969 PetscSF rsf; 1970 PetscSection s; 1971 const PetscInt *rootdegree; 1972 PetscInt *rootPointsNew, *remoteOffsets; 1973 PetscInt numPointsNew, pStart, pEnd, p; 1974 1975 PetscFunctionBegin; 1976 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1977 PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_CreateSF, tr, dm, 0, 0)); 1978 PetscCall(DMPlexGetChart(rdm, &pStartNew, &pEndNew)); 1979 PetscCall(DMGetPointSF(dm, &sf)); 1980 PetscCall(DMGetPointSF(rdm, &sfNew)); 1981 /* Calculate size of new SF */ 1982 PetscCall(PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints)); 1983 if (numRoots < 0) { 1984 PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_CreateSF, tr, dm, 0, 0)); 1985 PetscFunctionReturn(PETSC_SUCCESS); 1986 } 1987 for (l = 0; l < numLeaves; ++l) { 1988 const PetscInt p = localPoints[l]; 1989 DMPolytopeType ct; 1990 DMPolytopeType *rct; 1991 PetscInt *rsize, *rcone, *rornt; 1992 PetscInt Nct, n; 1993 1994 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1995 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 1996 for (n = 0; n < Nct; ++n) numLeavesNew += rsize[n]; 1997 } 1998 /* Send new root point numbers 1999 It is possible to optimize for regular transforms by sending only the cell type offsets, but it seems a needless complication 2000 */ 2001 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 2002 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &s)); 2003 PetscCall(PetscSectionSetChart(s, pStart, pEnd)); 2004 for (p = pStart; p < pEnd; ++p) { 2005 DMPolytopeType ct; 2006 DMPolytopeType *rct; 2007 PetscInt *rsize, *rcone, *rornt; 2008 PetscInt Nct, n; 2009 2010 PetscCall(DMPlexGetCellType(dm, p, &ct)); 2011 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 2012 for (n = 0; n < Nct; ++n) PetscCall(PetscSectionAddDof(s, p, rsize[n])); 2013 } 2014 PetscCall(PetscSectionSetUp(s)); 2015 PetscCall(PetscSectionGetStorageSize(s, &numPointsNew)); 2016 PetscCall(PetscSFCreateRemoteOffsets(sf, s, s, &remoteOffsets)); 2017 PetscCall(PetscSFCreateSectionSF(sf, s, remoteOffsets, s, &rsf)); 2018 PetscCall(PetscFree(remoteOffsets)); 2019 PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree)); 2020 PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree)); 2021 PetscCall(PetscMalloc1(numPointsNew, &rootPointsNew)); 2022 for (p = 0; p < numPointsNew; ++p) rootPointsNew[p] = -1; 2023 for (p = pStart; p < pEnd; ++p) { 2024 DMPolytopeType ct; 2025 DMPolytopeType *rct; 2026 PetscInt *rsize, *rcone, *rornt; 2027 PetscInt Nct, n, r, off; 2028 2029 if (!rootdegree[p - pStart]) continue; 2030 PetscCall(PetscSectionGetOffset(s, p, &off)); 2031 PetscCall(DMPlexGetCellType(dm, p, &ct)); 2032 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 2033 for (n = 0, m = 0; n < Nct; ++n) { 2034 for (r = 0; r < rsize[n]; ++r, ++m) { 2035 PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew)); 2036 rootPointsNew[off + m] = pNew; 2037 } 2038 } 2039 } 2040 PetscCall(PetscSFBcastBegin(rsf, MPIU_INT, rootPointsNew, rootPointsNew, MPI_REPLACE)); 2041 PetscCall(PetscSFBcastEnd(rsf, MPIU_INT, rootPointsNew, rootPointsNew, MPI_REPLACE)); 2042 PetscCall(PetscSFDestroy(&rsf)); 2043 PetscCall(PetscMalloc1(numLeavesNew, &localPointsNew)); 2044 PetscCall(PetscMalloc1(numLeavesNew, &remotePointsNew)); 2045 for (l = 0, m = 0; l < numLeaves; ++l) { 2046 const PetscInt p = localPoints[l]; 2047 DMPolytopeType ct; 2048 DMPolytopeType *rct; 2049 PetscInt *rsize, *rcone, *rornt; 2050 PetscInt Nct, n, r, q, off; 2051 2052 PetscCall(PetscSectionGetOffset(s, p, &off)); 2053 PetscCall(DMPlexGetCellType(dm, p, &ct)); 2054 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 2055 for (n = 0, q = 0; n < Nct; ++n) { 2056 for (r = 0; r < rsize[n]; ++r, ++m, ++q) { 2057 PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew)); 2058 localPointsNew[m] = pNew; 2059 remotePointsNew[m].index = rootPointsNew[off + q]; 2060 remotePointsNew[m].rank = remotePoints[l].rank; 2061 } 2062 } 2063 } 2064 PetscCall(PetscSectionDestroy(&s)); 2065 PetscCall(PetscFree(rootPointsNew)); 2066 /* SF needs sorted leaves to correctly calculate Gather */ 2067 { 2068 PetscSFNode *rp, *rtmp; 2069 PetscInt *lp, *idx, *ltmp, i; 2070 2071 PetscCall(PetscMalloc1(numLeavesNew, &idx)); 2072 PetscCall(PetscMalloc1(numLeavesNew, &lp)); 2073 PetscCall(PetscMalloc1(numLeavesNew, &rp)); 2074 for (i = 0; i < numLeavesNew; ++i) { 2075 PetscCheck(!(localPointsNew[i] < pStartNew) && !(localPointsNew[i] >= pEndNew), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local SF point %" PetscInt_FMT " (%" PetscInt_FMT ") not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", localPointsNew[i], i, pStartNew, pEndNew); 2076 idx[i] = i; 2077 } 2078 PetscCall(PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx)); 2079 for (i = 0; i < numLeavesNew; ++i) { 2080 lp[i] = localPointsNew[idx[i]]; 2081 rp[i] = remotePointsNew[idx[i]]; 2082 } 2083 ltmp = localPointsNew; 2084 localPointsNew = lp; 2085 rtmp = remotePointsNew; 2086 remotePointsNew = rp; 2087 PetscCall(PetscFree(idx)); 2088 PetscCall(PetscFree(ltmp)); 2089 PetscCall(PetscFree(rtmp)); 2090 } 2091 PetscCall(PetscSFSetGraph(sfNew, pEndNew - pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER)); 2092 PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_CreateSF, tr, dm, 0, 0)); 2093 PetscFunctionReturn(PETSC_SUCCESS); 2094 } 2095 2096 /* 2097 DMPlexCellRefinerMapLocalizedCoordinates - Given a cell of `DMPolytopeType` `ct` with localized coordinates `x`, generate localized coordinates `xr` for subcell `r` of type `rct`. 2098 2099 Not Collective 2100 2101 Input Parameters: 2102 + tr - The `DMPlexTransform` 2103 . ct - The type of the parent cell 2104 . rct - The type of the produced cell 2105 . r - The index of the produced cell 2106 - x - The localized coordinates for the parent cell 2107 2108 Output Parameter: 2109 . xr - The localized coordinates for the produced cell 2110 2111 Level: developer 2112 2113 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexCellRefinerSetCoordinates()` 2114 */ 2115 static PetscErrorCode DMPlexTransformMapLocalizedCoordinates(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType rct, PetscInt r, const PetscScalar x[], PetscScalar xr[]) 2116 { 2117 PetscFE fe = NULL; 2118 PetscInt cdim, v, *subcellV; 2119 2120 PetscFunctionBegin; 2121 PetscCall(DMPlexTransformGetCoordinateFE(tr, ct, &fe)); 2122 PetscCall(DMPlexTransformGetSubcellVertices(tr, ct, rct, r, &subcellV)); 2123 PetscCall(PetscFEGetNumComponents(fe, &cdim)); 2124 for (v = 0; v < DMPolytopeTypeGetNumVertices(rct); ++v) PetscCall(PetscFEInterpolate_Static(fe, x, tr->refGeom[ct], subcellV[v], &xr[v * cdim])); 2125 PetscFunctionReturn(PETSC_SUCCESS); 2126 } 2127 2128 static PetscErrorCode DMPlexTransformSetCoordinates(DMPlexTransform tr, DM rdm) 2129 { 2130 DM dm, cdm, cdmCell, cdmNew, cdmCellNew; 2131 PetscSection coordSection, coordSectionNew, coordSectionCell, coordSectionCellNew; 2132 Vec coordsLocal, coordsLocalNew, coordsLocalCell = NULL, coordsLocalCellNew; 2133 const PetscScalar *coords; 2134 PetscScalar *coordsNew; 2135 const PetscReal *maxCell, *Lstart, *L; 2136 PetscBool localized, localizeVertices = PETSC_FALSE, localizeCells = PETSC_FALSE; 2137 PetscInt dE, dEo, d, cStart, cEnd, c, cStartNew, cEndNew, vStartNew, vEndNew, v, pStart, pEnd, p; 2138 2139 PetscFunctionBegin; 2140 // Need to clear the DMField for coordinates 2141 PetscCall(DMSetCoordinateField(rdm, NULL)); 2142 PetscCall(DMPlexTransformGetDM(tr, &dm)); 2143 PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetCoordinates, tr, dm, 0, 0)); 2144 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2145 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 2146 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 2147 PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L)); 2148 if (localized) { 2149 /* Localize coordinates of new vertices */ 2150 localizeVertices = PETSC_TRUE; 2151 /* If we do not have a mechanism for automatically localizing cell coordinates, we need to compute them explicitly for every divided cell */ 2152 if (!maxCell) localizeCells = PETSC_TRUE; 2153 } 2154 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 2155 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &dEo)); 2156 if (maxCell) { 2157 PetscReal maxCellNew[3]; 2158 2159 for (d = 0; d < dEo; ++d) maxCellNew[d] = maxCell[d] / 2.0; 2160 PetscCall(DMSetPeriodicity(rdm, maxCellNew, Lstart, L)); 2161 } 2162 PetscCall(DMGetCoordinateDim(rdm, &dE)); 2163 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)rdm), &coordSectionNew)); 2164 PetscCall(PetscSectionSetNumFields(coordSectionNew, 1)); 2165 PetscCall(PetscSectionSetFieldComponents(coordSectionNew, 0, dE)); 2166 PetscCall(DMPlexGetDepthStratum(rdm, 0, &vStartNew, &vEndNew)); 2167 PetscCall(PetscSectionSetChart(coordSectionNew, vStartNew, vEndNew)); 2168 /* Localization should be inherited */ 2169 /* Stefano calculates parent cells for each new cell for localization */ 2170 /* Localized cells need coordinates of closure */ 2171 for (v = vStartNew; v < vEndNew; ++v) { 2172 PetscCall(PetscSectionSetDof(coordSectionNew, v, dE)); 2173 PetscCall(PetscSectionSetFieldDof(coordSectionNew, v, 0, dE)); 2174 } 2175 PetscCall(PetscSectionSetUp(coordSectionNew)); 2176 PetscCall(DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew)); 2177 2178 if (localizeCells) { 2179 PetscCall(DMGetCoordinateDM(rdm, &cdmNew)); 2180 PetscCall(DMClone(cdmNew, &cdmCellNew)); 2181 PetscCall(DMSetCellCoordinateDM(rdm, cdmCellNew)); 2182 PetscCall(DMDestroy(&cdmCellNew)); 2183 2184 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)rdm), &coordSectionCellNew)); 2185 PetscCall(PetscSectionSetNumFields(coordSectionCellNew, 1)); 2186 PetscCall(PetscSectionSetFieldComponents(coordSectionCellNew, 0, dE)); 2187 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStartNew, &cEndNew)); 2188 PetscCall(PetscSectionSetChart(coordSectionCellNew, cStartNew, cEndNew)); 2189 2190 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 2191 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2192 for (c = cStart; c < cEnd; ++c) { 2193 PetscInt dof; 2194 2195 PetscCall(PetscSectionGetDof(coordSectionCell, c, &dof)); 2196 if (dof) { 2197 DMPolytopeType ct; 2198 DMPolytopeType *rct; 2199 PetscInt *rsize, *rcone, *rornt; 2200 PetscInt dim, cNew, Nct, n, r; 2201 2202 PetscCall(DMPlexGetCellType(dm, c, &ct)); 2203 dim = DMPolytopeTypeGetDim(ct); 2204 PetscCall(DMPlexTransformCellTransform(tr, ct, c, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 2205 /* This allows for different cell types */ 2206 for (n = 0; n < Nct; ++n) { 2207 if (dim != DMPolytopeTypeGetDim(rct[n])) continue; 2208 for (r = 0; r < rsize[n]; ++r) { 2209 PetscInt *closure = NULL; 2210 PetscInt clSize, cl, Nv = 0; 2211 2212 PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], c, r, &cNew)); 2213 PetscCall(DMPlexGetTransitiveClosure(rdm, cNew, PETSC_TRUE, &clSize, &closure)); 2214 for (cl = 0; cl < clSize * 2; cl += 2) { 2215 if ((closure[cl] >= vStartNew) && (closure[cl] < vEndNew)) ++Nv; 2216 } 2217 PetscCall(DMPlexRestoreTransitiveClosure(rdm, cNew, PETSC_TRUE, &clSize, &closure)); 2218 PetscCall(PetscSectionSetDof(coordSectionCellNew, cNew, Nv * dE)); 2219 PetscCall(PetscSectionSetFieldDof(coordSectionCellNew, cNew, 0, Nv * dE)); 2220 } 2221 } 2222 } 2223 } 2224 PetscCall(PetscSectionSetUp(coordSectionCellNew)); 2225 PetscCall(DMSetCellCoordinateSection(rdm, PETSC_DETERMINE, coordSectionCellNew)); 2226 } 2227 PetscCall(DMViewFromOptions(dm, NULL, "-coarse_dm_view")); 2228 { 2229 VecType vtype; 2230 PetscInt coordSizeNew, bs; 2231 const char *name; 2232 2233 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 2234 PetscCall(VecCreate(PETSC_COMM_SELF, &coordsLocalNew)); 2235 PetscCall(PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew)); 2236 PetscCall(VecSetSizes(coordsLocalNew, coordSizeNew, PETSC_DETERMINE)); 2237 PetscCall(PetscObjectGetName((PetscObject)coordsLocal, &name)); 2238 PetscCall(PetscObjectSetName((PetscObject)coordsLocalNew, name)); 2239 PetscCall(VecGetBlockSize(coordsLocal, &bs)); 2240 PetscCall(VecSetBlockSize(coordsLocalNew, dEo == dE ? bs : dE)); 2241 PetscCall(VecGetType(coordsLocal, &vtype)); 2242 PetscCall(VecSetType(coordsLocalNew, vtype)); 2243 } 2244 PetscCall(VecGetArrayRead(coordsLocal, &coords)); 2245 PetscCall(VecGetArray(coordsLocalNew, &coordsNew)); 2246 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 2247 /* First set coordinates for vertices */ 2248 for (p = pStart; p < pEnd; ++p) { 2249 DMPolytopeType ct; 2250 DMPolytopeType *rct; 2251 PetscInt *rsize, *rcone, *rornt; 2252 PetscInt Nct, n, r; 2253 PetscBool hasVertex = PETSC_FALSE; 2254 2255 PetscCall(DMPlexGetCellType(dm, p, &ct)); 2256 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 2257 for (n = 0; n < Nct; ++n) { 2258 if (rct[n] == DM_POLYTOPE_POINT) { 2259 hasVertex = PETSC_TRUE; 2260 break; 2261 } 2262 } 2263 if (hasVertex) { 2264 const PetscScalar *icoords = NULL; 2265 const PetscScalar *array = NULL; 2266 PetscScalar *pcoords = NULL; 2267 PetscBool isDG; 2268 PetscInt Nc, Nv, v, d; 2269 2270 PetscCall(DMPlexGetCellCoordinates(dm, p, &isDG, &Nc, &array, &pcoords)); 2271 2272 icoords = pcoords; 2273 Nv = Nc / dEo; 2274 if (ct != DM_POLYTOPE_POINT) { 2275 if (localizeVertices && maxCell) { 2276 PetscScalar anchor[3]; 2277 2278 for (d = 0; d < dEo; ++d) anchor[d] = pcoords[d]; 2279 for (v = 0; v < Nv; ++v) PetscCall(DMLocalizeCoordinate_Internal(dm, dEo, anchor, &pcoords[v * dEo], &pcoords[v * dEo])); 2280 } 2281 } 2282 for (n = 0; n < Nct; ++n) { 2283 if (rct[n] != DM_POLYTOPE_POINT) continue; 2284 for (r = 0; r < rsize[n]; ++r) { 2285 PetscScalar vcoords[3]; 2286 PetscInt vNew, off; 2287 2288 PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &vNew)); 2289 PetscCall(PetscSectionGetOffset(coordSectionNew, vNew, &off)); 2290 PetscCall(DMPlexTransformMapCoordinates(tr, ct, rct[n], p, r, Nv, dEo, icoords, vcoords)); 2291 PetscCall(DMSnapToGeomModel(dm, p, dE, vcoords, &coordsNew[off])); 2292 } 2293 } 2294 PetscCall(DMPlexRestoreCellCoordinates(dm, p, &isDG, &Nc, &array, &pcoords)); 2295 } 2296 } 2297 PetscCall(VecRestoreArrayRead(coordsLocal, &coords)); 2298 PetscCall(VecRestoreArray(coordsLocalNew, &coordsNew)); 2299 PetscCall(DMSetCoordinatesLocal(rdm, coordsLocalNew)); 2300 PetscCall(VecDestroy(&coordsLocalNew)); 2301 PetscCall(PetscSectionDestroy(&coordSectionNew)); 2302 /* Then set coordinates for cells by localizing */ 2303 if (!localizeCells) PetscCall(DMLocalizeCoordinates(rdm)); 2304 else { 2305 VecType vtype; 2306 PetscInt coordSizeNew, bs; 2307 const char *name; 2308 2309 PetscCall(DMGetCellCoordinatesLocal(dm, &coordsLocalCell)); 2310 PetscCall(VecCreate(PETSC_COMM_SELF, &coordsLocalCellNew)); 2311 PetscCall(PetscSectionGetStorageSize(coordSectionCellNew, &coordSizeNew)); 2312 PetscCall(VecSetSizes(coordsLocalCellNew, coordSizeNew, PETSC_DETERMINE)); 2313 PetscCall(PetscObjectGetName((PetscObject)coordsLocalCell, &name)); 2314 PetscCall(PetscObjectSetName((PetscObject)coordsLocalCellNew, name)); 2315 PetscCall(VecGetBlockSize(coordsLocalCell, &bs)); 2316 PetscCall(VecSetBlockSize(coordsLocalCellNew, dEo == dE ? bs : dE)); 2317 PetscCall(VecGetType(coordsLocalCell, &vtype)); 2318 PetscCall(VecSetType(coordsLocalCellNew, vtype)); 2319 PetscCall(VecGetArrayRead(coordsLocalCell, &coords)); 2320 PetscCall(VecGetArray(coordsLocalCellNew, &coordsNew)); 2321 2322 for (p = pStart; p < pEnd; ++p) { 2323 DMPolytopeType ct; 2324 DMPolytopeType *rct; 2325 PetscInt *rsize, *rcone, *rornt; 2326 PetscInt dof = 0, Nct, n, r; 2327 2328 PetscCall(DMPlexGetCellType(dm, p, &ct)); 2329 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 2330 if (p >= cStart && p < cEnd) PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 2331 if (dof) { 2332 const PetscScalar *pcoords; 2333 2334 PetscCall(DMPlexPointLocalRead(cdmCell, p, coords, &pcoords)); 2335 for (n = 0; n < Nct; ++n) { 2336 const PetscInt Nr = rsize[n]; 2337 2338 if (DMPolytopeTypeGetDim(ct) != DMPolytopeTypeGetDim(rct[n])) continue; 2339 for (r = 0; r < Nr; ++r) { 2340 PetscInt pNew, offNew; 2341 2342 /* It looks like Stefano and Lisandro are allowing localized coordinates without defining the periodic boundary, which means that 2343 DMLocalizeCoordinate_Internal() will not work. Localized coordinates will have to have obtained by the affine map of the larger 2344 cell to the ones it produces. */ 2345 PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew)); 2346 PetscCall(PetscSectionGetOffset(coordSectionCellNew, pNew, &offNew)); 2347 PetscCall(DMPlexTransformMapLocalizedCoordinates(tr, ct, rct[n], r, pcoords, &coordsNew[offNew])); 2348 } 2349 } 2350 } 2351 } 2352 PetscCall(VecRestoreArrayRead(coordsLocalCell, &coords)); 2353 PetscCall(VecRestoreArray(coordsLocalCellNew, &coordsNew)); 2354 PetscCall(DMSetCellCoordinatesLocal(rdm, coordsLocalCellNew)); 2355 PetscCall(VecDestroy(&coordsLocalCellNew)); 2356 PetscCall(PetscSectionDestroy(&coordSectionCellNew)); 2357 } 2358 PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetCoordinates, tr, dm, 0, 0)); 2359 PetscFunctionReturn(PETSC_SUCCESS); 2360 } 2361 2362 /*@ 2363 DMPlexTransformApply - Execute the transformation, producing another `DM` 2364 2365 Collective 2366 2367 Input Parameters: 2368 + tr - The `DMPlexTransform` object 2369 - dm - The original `DM` 2370 2371 Output Parameter: 2372 . tdm - The transformed `DM` 2373 2374 Level: intermediate 2375 2376 Options Database Keys: 2377 + -dm_plex_transform_label_match_strata - Only label points of the same stratum as the producing point 2378 . -dm_plex_transform_label_replica_inc <num> - Increment for the label value to be multiplied by the replica number 2379 - -dm_plex_transform_active <name> - Name for active mesh label 2380 2381 .seealso: [](plex_transform_table), [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformCreate()`, `DMPlexTransformSetDM()` 2382 @*/ 2383 PetscErrorCode DMPlexTransformApply(DMPlexTransform tr, DM dm, DM *tdm) 2384 { 2385 DM rdm; 2386 DMPlexInterpolatedFlag interp; 2387 PetscInt pStart, pEnd; 2388 2389 PetscFunctionBegin; 2390 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 2391 PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 2392 PetscAssertPointer(tdm, 3); 2393 PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_Apply, tr, dm, 0, 0)); 2394 PetscCall(DMPlexTransformSetDM(tr, dm)); 2395 2396 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &rdm)); 2397 PetscCall(DMSetType(rdm, DMPLEX)); 2398 PetscCall(DMPlexTransformSetDimensions(tr, dm, rdm)); 2399 /* Calculate number of new points of each depth */ 2400 PetscCall(DMPlexIsInterpolatedCollective(dm, &interp)); 2401 PetscCheck(interp == DMPLEX_INTERPOLATED_FULL, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mesh must be fully interpolated for regular refinement"); 2402 /* Step 1: Set chart */ 2403 PetscCall(DMPlexTransformGetChart(tr, &pStart, &pEnd)); 2404 PetscCall(DMPlexSetChart(rdm, pStart, pEnd)); 2405 /* Step 2: Set cone/support sizes (automatically stratifies) */ 2406 PetscCall(DMPlexTransformSetConeSizes(tr, rdm)); 2407 /* Step 3: Setup refined DM */ 2408 PetscCall(DMSetUp(rdm)); 2409 /* Step 4: Set cones and supports (automatically symmetrizes) */ 2410 PetscCall(DMPlexTransformSetCones(tr, rdm)); 2411 /* Step 5: Create pointSF */ 2412 PetscCall(DMPlexTransformCreateSF(tr, rdm)); 2413 /* Step 6: Create labels */ 2414 PetscCall(DMPlexTransformCreateLabels(tr, rdm)); 2415 /* Step 7: Set coordinates */ 2416 PetscCall(DMPlexTransformSetCoordinates(tr, rdm)); 2417 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, rdm)); 2418 // If the original DM was configured from options, the transformed DM should be as well 2419 rdm->setfromoptionscalled = dm->setfromoptionscalled; 2420 PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_Apply, tr, dm, 0, 0)); 2421 *tdm = rdm; 2422 PetscFunctionReturn(PETSC_SUCCESS); 2423 } 2424 2425 PetscErrorCode DMPlexTransformAdaptLabel(DM dm, PETSC_UNUSED Vec metric, DMLabel adaptLabel, PETSC_UNUSED DMLabel rgLabel, DM *rdm) 2426 { 2427 DMPlexTransform tr; 2428 DM cdm, rcdm; 2429 const char *prefix; 2430 PetscBool save; 2431 2432 PetscFunctionBegin; 2433 PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), &tr)); 2434 PetscCall(PetscObjectSetName((PetscObject)tr, "Adapt Label Transform")); 2435 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 2436 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tr, prefix)); 2437 PetscCall(DMPlexTransformSetDM(tr, dm)); 2438 PetscCall(DMPlexTransformSetFromOptions(tr)); 2439 if (adaptLabel) PetscCall(DMPlexTransformSetActive(tr, adaptLabel)); 2440 PetscCall(DMPlexTransformSetUp(tr)); 2441 PetscCall(PetscObjectViewFromOptions((PetscObject)tr, NULL, "-dm_plex_transform_view")); 2442 PetscCall(DMPlexTransformApply(tr, dm, rdm)); 2443 PetscCall(DMCopyDisc(dm, *rdm)); 2444 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2445 PetscCall(DMGetCoordinateDM(*rdm, &rcdm)); 2446 PetscCall(DMCopyDisc(cdm, rcdm)); 2447 PetscCall(DMPlexTransformCreateDiscLabels(tr, *rdm)); 2448 PetscCall(DMCopyDisc(dm, *rdm)); 2449 PetscCall(DMPlexGetSaveTransform(dm, &save)); 2450 if (save) PetscCall(DMPlexSetTransform(*rdm, tr)); 2451 PetscCall(DMPlexTransformDestroy(&tr)); 2452 ((DM_Plex *)(*rdm)->data)->useHashLocation = ((DM_Plex *)dm->data)->useHashLocation; 2453 PetscFunctionReturn(PETSC_SUCCESS); 2454 } 2455