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 . trdm - 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 trdm) 878 { 879 PetscFunctionBegin; 880 PetscUseTypeMethod(tr, setdimensions, dm, trdm); 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 DMPolytopeType *newft = NULL; 1446 PetscInt c, coff = *coneoff, ooff = *orntoff; 1447 PetscInt dim, cr = 0, co = 0, nr, no; 1448 1449 PetscFunctionBegin; 1450 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1451 PetscCall(DMPlexGetOrientedCone(dm, p, &cone, NULL)); 1452 // Check if we have to permute this cell 1453 PetscCall(DMGetDimension(dm, &dim)); 1454 if (DMPolytopeTypeGetDim(ctNew) == dim && DMPolytopeTypeGetDim(ct) == dim - 1) { 1455 PetscCall(DMPlexTransformGetSubcellOrientation(tr, ct, p, o, ctNew, cr, co, &nr, &no)); 1456 if (cr != nr || co != no) PetscCall(DMGetWorkArray(dm, csizeNew, MPIU_INT, &newft)); 1457 } 1458 for (c = 0; c < csizeNew; ++c) { 1459 PetscInt ppp = -1; /* Parent Parent point: Parent of point pp */ 1460 PetscInt pp = p; /* Parent point: Point in the original mesh producing new cone point */ 1461 PetscInt po = 0; /* Orientation of parent point pp in parent parent point ppp */ 1462 DMPolytopeType pct = ct; /* Parent type: Cell type for parent of new cone point */ 1463 const PetscInt *pcone = cone; /* Parent cone: Cone of parent point pp */ 1464 PetscInt pr = -1; /* Replica number of pp that produces new cone point */ 1465 const DMPolytopeType ft = (DMPolytopeType)rcone[coff++]; /* Cell type for new cone point of pNew */ 1466 const PetscInt fn = rcone[coff++]; /* Number of cones of p that need to be taken when producing new cone point */ 1467 PetscInt fo = rornt[ooff++]; /* Orientation of new cone point in pNew */ 1468 PetscInt lc; 1469 1470 /* Get the type (pct) and point number (pp) of the parent point in the original mesh which produces this cone point */ 1471 for (lc = 0; lc < fn; ++lc) { 1472 const PetscInt *parr = DMPolytopeTypeGetArrangement(pct, po); 1473 const PetscInt acp = rcone[coff++]; 1474 const PetscInt pcp = parr[acp * 2]; 1475 const PetscInt pco = parr[acp * 2 + 1]; 1476 const PetscInt *ppornt; 1477 1478 ppp = pp; 1479 pp = pcone[pcp]; 1480 PetscCall(DMPlexGetCellType(dm, pp, &pct)); 1481 // Restore the parent cone from the last iterate 1482 if (lc) PetscCall(DMPlexRestoreOrientedCone(dm, ppp, &pcone, NULL)); 1483 PetscCall(DMPlexGetOrientedCone(dm, pp, &pcone, NULL)); 1484 PetscCall(DMPlexGetOrientedCone(dm, ppp, NULL, &ppornt)); 1485 po = DMPolytopeTypeComposeOrientation(pct, ppornt[pcp], pco); 1486 PetscCall(DMPlexRestoreOrientedCone(dm, ppp, NULL, &ppornt)); 1487 } 1488 if (lc) PetscCall(DMPlexRestoreOrientedCone(dm, pp, &pcone, NULL)); 1489 pr = rcone[coff++]; 1490 /* Orientation po of pp maps (pr, fo) -> (pr', fo') */ 1491 PetscCall(DMPlexTransformGetSubcellOrientation(tr, pct, pp, fn ? po : o, ft, pr, fo, &pr, &fo)); 1492 PetscCall(DMPlexTransformGetTargetPoint(tr, pct, ft, pp, pr, &coneNew[c])); 1493 orntNew[c] = fo; 1494 if (newft) newft[c] = ft; 1495 } 1496 PetscCall(DMPlexRestoreOrientedCone(dm, p, &cone, NULL)); 1497 if (newft) { 1498 const PetscInt *arr; 1499 PetscInt *newcone, *newornt; 1500 1501 arr = DMPolytopeTypeGetArrangement(ctNew, no); 1502 PetscCall(DMGetWorkArray(dm, csizeNew, MPIU_INT, &newcone)); 1503 PetscCall(DMGetWorkArray(dm, csizeNew, MPIU_INT, &newornt)); 1504 for (PetscInt c = 0; c < csizeNew; ++c) { 1505 DMPolytopeType ft = newft[c]; 1506 PetscInt nO; 1507 1508 nO = DMPolytopeTypeGetNumArrangements(ft) / 2; 1509 newcone[c] = coneNew[arr[c * 2 + 0]]; 1510 newornt[c] = DMPolytopeTypeComposeOrientation(ft, arr[c * 2 + 1], orntNew[arr[c * 2 + 0]]); 1511 PetscCheck(!newornt[c] || !(newornt[c] >= nO || newornt[c] < -nO), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid orientation %" PetscInt_FMT " not in [%" PetscInt_FMT ",%" PetscInt_FMT ") for %s %" PetscInt_FMT, newornt[c], -nO, nO, DMPolytopeTypes[ft], coneNew[c]); 1512 } 1513 for (PetscInt c = 0; c < csizeNew; ++c) { 1514 coneNew[c] = newcone[c]; 1515 orntNew[c] = newornt[c]; 1516 } 1517 PetscCall(DMRestoreWorkArray(dm, csizeNew, MPIU_INT, &newcone)); 1518 PetscCall(DMRestoreWorkArray(dm, csizeNew, MPIU_INT, &newornt)); 1519 PetscCall(DMRestoreWorkArray(dm, csizeNew, MPIU_INT, &newft)); 1520 } 1521 *coneoff = coff; 1522 *orntoff = ooff; 1523 PetscFunctionReturn(PETSC_SUCCESS); 1524 } 1525 1526 static PetscErrorCode DMPlexTransformSetCones(DMPlexTransform tr, DM rdm) 1527 { 1528 DM dm; 1529 DMPolytopeType ct; 1530 PetscInt *coneNew, *orntNew; 1531 PetscInt maxConeSize = 0, pStart, pEnd, p, pNew; 1532 1533 PetscFunctionBegin; 1534 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1535 PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetCones, tr, dm, 0, 0)); 1536 for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p)); 1537 PetscCall(DMGetWorkArray(rdm, maxConeSize, MPIU_INT, &coneNew)); 1538 PetscCall(DMGetWorkArray(rdm, maxConeSize, MPIU_INT, &orntNew)); 1539 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 1540 for (p = pStart; p < pEnd; ++p) { 1541 PetscInt coff, ooff; 1542 DMPolytopeType *rct; 1543 PetscInt *rsize, *rcone, *rornt; 1544 PetscInt Nct, n, r; 1545 1546 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1547 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 1548 for (n = 0, coff = 0, ooff = 0; n < Nct; ++n) { 1549 const DMPolytopeType ctNew = rct[n]; 1550 1551 for (r = 0; r < rsize[n]; ++r) { 1552 PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew)); 1553 PetscCall(DMPlexTransformGetCone_Internal(tr, p, 0, ct, ctNew, rcone, &coff, rornt, &ooff, coneNew, orntNew)); 1554 PetscCall(DMPlexSetCone(rdm, pNew, coneNew)); 1555 PetscCall(DMPlexSetConeOrientation(rdm, pNew, orntNew)); 1556 } 1557 } 1558 } 1559 PetscCall(DMRestoreWorkArray(rdm, maxConeSize, MPIU_INT, &coneNew)); 1560 PetscCall(DMRestoreWorkArray(rdm, maxConeSize, MPIU_INT, &orntNew)); 1561 PetscCall(DMViewFromOptions(rdm, NULL, "-rdm_view")); 1562 PetscCall(DMPlexSymmetrize(rdm)); 1563 PetscCall(DMPlexStratify(rdm)); 1564 PetscTryTypeMethod(tr, ordersupports, dm, rdm); 1565 PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetCones, tr, dm, 0, 0)); 1566 PetscFunctionReturn(PETSC_SUCCESS); 1567 } 1568 1569 PetscErrorCode DMPlexTransformGetConeOriented(DMPlexTransform tr, PetscInt q, PetscInt po, const PetscInt *cone[], const PetscInt *ornt[]) 1570 { 1571 DM dm; 1572 DMPolytopeType ct, qct; 1573 DMPolytopeType *rct; 1574 PetscInt *rsize, *rcone, *rornt, *qcone, *qornt; 1575 PetscInt maxConeSize = 0, Nct, p, r, n, nr, coff = 0, ooff = 0; 1576 1577 PetscFunctionBegin; 1578 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 1579 PetscAssertPointer(cone, 4); 1580 PetscAssertPointer(ornt, 5); 1581 for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p)); 1582 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1583 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qcone)); 1584 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qornt)); 1585 PetscCall(DMPlexTransformGetSourcePoint(tr, q, &ct, &qct, &p, &r)); 1586 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 1587 for (n = 0; n < Nct; ++n) { 1588 const DMPolytopeType ctNew = rct[n]; 1589 const PetscInt csizeNew = DMPolytopeTypeGetConeSize(ctNew); 1590 PetscInt Nr = rsize[n], fn, c; 1591 1592 if (ctNew == qct) Nr = r; 1593 for (nr = 0; nr < Nr; ++nr) { 1594 for (c = 0; c < csizeNew; ++c) { 1595 ++coff; /* Cell type of new cone point */ 1596 fn = rcone[coff++]; /* Number of cones of p that need to be taken when producing new cone point */ 1597 coff += fn; 1598 ++coff; /* Replica number of new cone point */ 1599 ++ooff; /* Orientation of new cone point */ 1600 } 1601 } 1602 if (ctNew == qct) break; 1603 } 1604 PetscCall(DMPlexTransformGetCone_Internal(tr, p, po, ct, qct, rcone, &coff, rornt, &ooff, qcone, qornt)); 1605 *cone = qcone; 1606 *ornt = qornt; 1607 PetscFunctionReturn(PETSC_SUCCESS); 1608 } 1609 1610 PetscErrorCode DMPlexTransformGetCone(DMPlexTransform tr, PetscInt q, const PetscInt *cone[], const PetscInt *ornt[]) 1611 { 1612 DM dm; 1613 DMPolytopeType ct, qct; 1614 DMPolytopeType *rct; 1615 PetscInt *rsize, *rcone, *rornt, *qcone, *qornt; 1616 PetscInt maxConeSize = 0, Nct, p, r, n, nr, coff = 0, ooff = 0; 1617 1618 PetscFunctionBegin; 1619 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 1620 if (cone) PetscAssertPointer(cone, 3); 1621 if (ornt) PetscAssertPointer(ornt, 4); 1622 for (p = 0; p < DM_NUM_POLYTOPES; ++p) maxConeSize = PetscMax(maxConeSize, DMPolytopeTypeGetConeSize((DMPolytopeType)p)); 1623 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1624 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qcone)); 1625 PetscCall(DMGetWorkArray(dm, maxConeSize, MPIU_INT, &qornt)); 1626 PetscCall(DMPlexTransformGetSourcePoint(tr, q, &ct, &qct, &p, &r)); 1627 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 1628 for (n = 0; n < Nct; ++n) { 1629 const DMPolytopeType ctNew = rct[n]; 1630 const PetscInt csizeNew = DMPolytopeTypeGetConeSize(ctNew); 1631 PetscInt Nr = rsize[n], fn, c; 1632 1633 if (ctNew == qct) Nr = r; 1634 for (nr = 0; nr < Nr; ++nr) { 1635 for (c = 0; c < csizeNew; ++c) { 1636 ++coff; /* Cell type of new cone point */ 1637 fn = rcone[coff++]; /* Number of cones of p that need to be taken when producing new cone point */ 1638 coff += fn; 1639 ++coff; /* Replica number of new cone point */ 1640 ++ooff; /* Orientation of new cone point */ 1641 } 1642 } 1643 if (ctNew == qct) break; 1644 } 1645 PetscCall(DMPlexTransformGetCone_Internal(tr, p, 0, ct, qct, rcone, &coff, rornt, &ooff, qcone, qornt)); 1646 if (cone) *cone = qcone; 1647 else PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &qcone)); 1648 if (ornt) *ornt = qornt; 1649 else PetscCall(DMRestoreWorkArray(dm, maxConeSize, MPIU_INT, &qornt)); 1650 PetscFunctionReturn(PETSC_SUCCESS); 1651 } 1652 1653 PetscErrorCode DMPlexTransformRestoreCone(DMPlexTransform tr, PetscInt q, const PetscInt *cone[], const PetscInt *ornt[]) 1654 { 1655 DM dm; 1656 1657 PetscFunctionBegin; 1658 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 1659 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1660 if (cone) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, cone)); 1661 if (ornt) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_INT, ornt)); 1662 PetscFunctionReturn(PETSC_SUCCESS); 1663 } 1664 1665 static PetscErrorCode DMPlexTransformCreateCellVertices_Internal(DMPlexTransform tr) 1666 { 1667 PetscInt ict; 1668 1669 PetscFunctionBegin; 1670 PetscCall(PetscCalloc3(DM_NUM_POLYTOPES, &tr->trNv, DM_NUM_POLYTOPES, &tr->trVerts, DM_NUM_POLYTOPES, &tr->trSubVerts)); 1671 for (ict = DM_POLYTOPE_POINT; ict < DM_NUM_POLYTOPES; ++ict) { 1672 const DMPolytopeType ct = (DMPolytopeType)ict; 1673 DMPlexTransform reftr; 1674 DM refdm, trdm; 1675 Vec coordinates; 1676 const PetscScalar *coords; 1677 DMPolytopeType *rct; 1678 PetscInt *rsize, *rcone, *rornt; 1679 PetscInt Nct, n, r, pNew = 0; 1680 PetscInt trdim, vStart, vEnd, Nc; 1681 const PetscInt debug = 0; 1682 const char *typeName; 1683 1684 /* Since points are 0-dimensional, coordinates make no sense */ 1685 if (DMPolytopeTypeGetDim(ct) <= 0 || ct == DM_POLYTOPE_UNKNOWN_CELL || ct == DM_POLYTOPE_UNKNOWN_FACE) continue; 1686 PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, ct, &refdm)); 1687 PetscCall(DMPlexTransformCreate(PETSC_COMM_SELF, &reftr)); 1688 PetscCall(DMPlexTransformSetDM(reftr, refdm)); 1689 PetscCall(DMPlexTransformGetType(tr, &typeName)); 1690 PetscCall(DMPlexTransformSetType(reftr, typeName)); 1691 PetscCall(DMPlexTransformSetUp(reftr)); 1692 PetscCall(DMPlexTransformApply(reftr, refdm, &trdm)); 1693 1694 PetscCall(DMGetDimension(trdm, &trdim)); 1695 PetscCall(DMPlexGetDepthStratum(trdm, 0, &vStart, &vEnd)); 1696 tr->trNv[ct] = vEnd - vStart; 1697 PetscCall(DMGetCoordinatesLocal(trdm, &coordinates)); 1698 PetscCall(VecGetLocalSize(coordinates, &Nc)); 1699 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); 1700 PetscCall(PetscCalloc1(Nc, &tr->trVerts[ct])); 1701 PetscCall(VecGetArrayRead(coordinates, &coords)); 1702 PetscCall(PetscArraycpy(tr->trVerts[ct], coords, Nc)); 1703 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 1704 1705 PetscCall(PetscCalloc1(DM_NUM_POLYTOPES, &tr->trSubVerts[ct])); 1706 PetscCall(DMPlexTransformCellTransform(reftr, ct, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 1707 for (n = 0; n < Nct; ++n) { 1708 /* Since points are 0-dimensional, coordinates make no sense */ 1709 if (rct[n] == DM_POLYTOPE_POINT) continue; 1710 PetscCall(PetscCalloc1(rsize[n], &tr->trSubVerts[ct][rct[n]])); 1711 for (r = 0; r < rsize[n]; ++r) { 1712 PetscInt *closure = NULL; 1713 PetscInt clSize, cl, Nv = 0; 1714 1715 PetscCall(PetscCalloc1(DMPolytopeTypeGetNumVertices(rct[n]), &tr->trSubVerts[ct][rct[n]][r])); 1716 PetscCall(DMPlexTransformGetTargetPoint(reftr, ct, rct[n], 0, r, &pNew)); 1717 PetscCall(DMPlexGetTransitiveClosure(trdm, pNew, PETSC_TRUE, &clSize, &closure)); 1718 for (cl = 0; cl < clSize * 2; cl += 2) { 1719 const PetscInt sv = closure[cl]; 1720 1721 if ((sv >= vStart) && (sv < vEnd)) tr->trSubVerts[ct][rct[n]][r][Nv++] = sv - vStart; 1722 } 1723 PetscCall(DMPlexRestoreTransitiveClosure(trdm, pNew, PETSC_TRUE, &clSize, &closure)); 1724 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]); 1725 } 1726 } 1727 if (debug) { 1728 DMPolytopeType *rct; 1729 PetscInt *rsize, *rcone, *rornt; 1730 PetscInt v, dE = trdim, d, off = 0; 1731 1732 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s: %" PetscInt_FMT " vertices\n", DMPolytopeTypes[ct], tr->trNv[ct])); 1733 for (v = 0; v < tr->trNv[ct]; ++v) { 1734 PetscCall(PetscPrintf(PETSC_COMM_SELF, " ")); 1735 for (d = 0; d < dE; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g ", (double)PetscRealPart(tr->trVerts[ct][off++]))); 1736 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 1737 } 1738 1739 PetscCall(DMPlexTransformCellTransform(reftr, ct, 0, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 1740 for (n = 0; n < Nct; ++n) { 1741 if (rct[n] == DM_POLYTOPE_POINT) continue; 1742 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%s: %s subvertices %" PetscInt_FMT "\n", DMPolytopeTypes[ct], DMPolytopeTypes[rct[n]], tr->trNv[ct])); 1743 for (r = 0; r < rsize[n]; ++r) { 1744 PetscCall(PetscPrintf(PETSC_COMM_SELF, " ")); 1745 for (v = 0; v < DMPolytopeTypeGetNumVertices(rct[n]); ++v) PetscCall(PetscPrintf(PETSC_COMM_SELF, "%" PetscInt_FMT " ", tr->trSubVerts[ct][rct[n]][r][v])); 1746 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 1747 } 1748 } 1749 } 1750 PetscCall(DMDestroy(&refdm)); 1751 PetscCall(DMDestroy(&trdm)); 1752 PetscCall(DMPlexTransformDestroy(&reftr)); 1753 } 1754 PetscFunctionReturn(PETSC_SUCCESS); 1755 } 1756 1757 /*@C 1758 DMPlexTransformGetCellVertices - Get the set of transformed vertices lying in the closure of a reference cell of given type 1759 1760 Input Parameters: 1761 + tr - The `DMPlexTransform` object 1762 - ct - The cell type 1763 1764 Output Parameters: 1765 + Nv - The number of transformed vertices in the closure of the reference cell of given type 1766 - trVerts - The coordinates of these vertices in the reference cell 1767 1768 Level: developer 1769 1770 .seealso: `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetSubcellVertices()` 1771 @*/ 1772 PetscErrorCode DMPlexTransformGetCellVertices(DMPlexTransform tr, DMPolytopeType ct, PetscInt *Nv, PetscScalar *trVerts[]) 1773 { 1774 PetscFunctionBegin; 1775 if (!tr->trNv) PetscCall(DMPlexTransformCreateCellVertices_Internal(tr)); 1776 if (Nv) *Nv = tr->trNv[ct]; 1777 if (trVerts) *trVerts = tr->trVerts[ct]; 1778 PetscFunctionReturn(PETSC_SUCCESS); 1779 } 1780 1781 /*@C 1782 DMPlexTransformGetSubcellVertices - Get the set of transformed vertices defining a subcell in the reference cell of given type 1783 1784 Input Parameters: 1785 + tr - The `DMPlexTransform` object 1786 . ct - The cell type 1787 . rct - The subcell type 1788 - r - The subcell index 1789 1790 Output Parameter: 1791 . subVerts - The indices of these vertices in the set of vertices returned by `DMPlexTransformGetCellVertices()` 1792 1793 Level: developer 1794 1795 .seealso: `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformGetCellVertices()` 1796 @*/ 1797 PetscErrorCode DMPlexTransformGetSubcellVertices(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType rct, PetscInt r, PetscInt *subVerts[]) 1798 { 1799 PetscFunctionBegin; 1800 if (!tr->trNv) PetscCall(DMPlexTransformCreateCellVertices_Internal(tr)); 1801 PetscCheck(tr->trSubVerts[ct][rct], PetscObjectComm((PetscObject)tr), PETSC_ERR_ARG_WRONG, "Cell type %s does not produce %s", DMPolytopeTypes[ct], DMPolytopeTypes[rct]); 1802 if (subVerts) *subVerts = tr->trSubVerts[ct][rct][r]; 1803 PetscFunctionReturn(PETSC_SUCCESS); 1804 } 1805 1806 /* Computes new vertex as the barycenter, or centroid */ 1807 PetscErrorCode DMPlexTransformMapCoordinatesBarycenter_Internal(DMPlexTransform tr, DMPolytopeType pct, DMPolytopeType ct, PetscInt p, PetscInt r, PetscInt Nv, PetscInt dE, const PetscScalar in[], PetscScalar out[]) 1808 { 1809 PetscInt v, d; 1810 1811 PetscFunctionBeginHot; 1812 PetscCheck(ct == DM_POLYTOPE_POINT, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for refined point type %s", DMPolytopeTypes[ct]); 1813 for (d = 0; d < dE; ++d) out[d] = 0.0; 1814 for (v = 0; v < Nv; ++v) 1815 for (d = 0; d < dE; ++d) out[d] += in[v * dE + d]; 1816 for (d = 0; d < dE; ++d) out[d] /= Nv; 1817 PetscFunctionReturn(PETSC_SUCCESS); 1818 } 1819 1820 /*@ 1821 DMPlexTransformMapCoordinates - Calculate new coordinates for produced points 1822 1823 Not collective 1824 1825 Input Parameters: 1826 + tr - The `DMPlexTransform` 1827 . pct - The cell type of the parent, from whom the new cell is being produced 1828 . ct - The type being produced 1829 . p - The original point 1830 . r - The replica number requested for the produced cell type 1831 . Nv - Number of vertices in the closure of the parent cell 1832 . dE - Spatial dimension 1833 - in - array of size Nv*dE, holding coordinates of the vertices in the closure of the parent cell 1834 1835 Output Parameter: 1836 . out - The coordinates of the new vertices 1837 1838 Level: intermediate 1839 1840 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexTransformApply()` 1841 @*/ 1842 PetscErrorCode DMPlexTransformMapCoordinates(DMPlexTransform tr, DMPolytopeType pct, DMPolytopeType ct, PetscInt p, PetscInt r, PetscInt Nv, PetscInt dE, const PetscScalar in[], PetscScalar out[]) 1843 { 1844 PetscFunctionBeginHot; 1845 if (Nv) PetscUseTypeMethod(tr, mapcoordinates, pct, ct, p, r, Nv, dE, in, out); 1846 PetscFunctionReturn(PETSC_SUCCESS); 1847 } 1848 1849 /* 1850 DMPlexTransformLabelProducedPoint_Private - Label a produced point based on its parent label 1851 1852 Not Collective 1853 1854 Input Parameters: 1855 + tr - The `DMPlexTransform` 1856 . label - The label in the transformed mesh 1857 . pp - The parent point in the original mesh 1858 . pct - The cell type of the parent point 1859 . p - The point in the transformed mesh 1860 . ct - The cell type of the point 1861 . r - The replica number of the point 1862 - val - The label value of the parent point 1863 1864 Level: developer 1865 1866 .seealso: `DMPlexTransformCreateLabels()`, `RefineLabel_Internal()` 1867 */ 1868 static PetscErrorCode DMPlexTransformLabelProducedPoint_Private(DMPlexTransform tr, DMLabel label, PetscInt pp, DMPolytopeType pct, PetscInt p, DMPolytopeType ct, PetscInt r, PetscInt val) 1869 { 1870 PetscFunctionBeginHot; 1871 if (tr->labelMatchStrata && pct != ct) PetscFunctionReturn(PETSC_SUCCESS); 1872 PetscCall(DMLabelSetValue(label, p, val + tr->labelReplicaInc * r)); 1873 PetscFunctionReturn(PETSC_SUCCESS); 1874 } 1875 1876 static PetscErrorCode RefineLabel_Internal(DMPlexTransform tr, DMLabel label, DMLabel labelNew) 1877 { 1878 DM dm; 1879 IS valueIS; 1880 const PetscInt *values; 1881 PetscInt defVal, Nv, val; 1882 1883 PetscFunctionBegin; 1884 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1885 PetscCall(DMLabelGetDefaultValue(label, &defVal)); 1886 PetscCall(DMLabelSetDefaultValue(labelNew, defVal)); 1887 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1888 PetscCall(ISGetLocalSize(valueIS, &Nv)); 1889 PetscCall(ISGetIndices(valueIS, &values)); 1890 for (val = 0; val < Nv; ++val) { 1891 IS pointIS; 1892 const PetscInt *points; 1893 PetscInt numPoints, p; 1894 1895 /* Ensure refined label is created with same number of strata as 1896 * original (even if no entries here). */ 1897 PetscCall(DMLabelAddStratum(labelNew, values[val])); 1898 PetscCall(DMLabelGetStratumIS(label, values[val], &pointIS)); 1899 PetscCall(ISGetLocalSize(pointIS, &numPoints)); 1900 PetscCall(ISGetIndices(pointIS, &points)); 1901 for (p = 0; p < numPoints; ++p) { 1902 const PetscInt point = points[p]; 1903 DMPolytopeType ct; 1904 DMPolytopeType *rct; 1905 PetscInt *rsize, *rcone, *rornt; 1906 PetscInt Nct, n, r, pNew = 0; 1907 1908 PetscCall(DMPlexGetCellType(dm, point, &ct)); 1909 PetscCall(DMPlexTransformCellTransform(tr, ct, point, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 1910 for (n = 0; n < Nct; ++n) { 1911 for (r = 0; r < rsize[n]; ++r) { 1912 PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], point, r, &pNew)); 1913 PetscCall(DMPlexTransformLabelProducedPoint_Private(tr, labelNew, point, ct, pNew, rct[n], r, values[val])); 1914 } 1915 } 1916 } 1917 PetscCall(ISRestoreIndices(pointIS, &points)); 1918 PetscCall(ISDestroy(&pointIS)); 1919 } 1920 PetscCall(ISRestoreIndices(valueIS, &values)); 1921 PetscCall(ISDestroy(&valueIS)); 1922 PetscFunctionReturn(PETSC_SUCCESS); 1923 } 1924 1925 static PetscErrorCode DMPlexTransformCreateLabels(DMPlexTransform tr, DM rdm) 1926 { 1927 DM dm; 1928 PetscInt numLabels, l; 1929 1930 PetscFunctionBegin; 1931 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1932 PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_CreateLabels, tr, dm, 0, 0)); 1933 PetscCall(DMGetNumLabels(dm, &numLabels)); 1934 for (l = 0; l < numLabels; ++l) { 1935 DMLabel label, labelNew; 1936 const char *lname; 1937 PetscBool isDepth, isCellType; 1938 1939 PetscCall(DMGetLabelName(dm, l, &lname)); 1940 PetscCall(PetscStrcmp(lname, "depth", &isDepth)); 1941 if (isDepth) continue; 1942 PetscCall(PetscStrcmp(lname, "celltype", &isCellType)); 1943 if (isCellType) continue; 1944 PetscCall(DMCreateLabel(rdm, lname)); 1945 PetscCall(DMGetLabel(dm, lname, &label)); 1946 PetscCall(DMGetLabel(rdm, lname, &labelNew)); 1947 PetscCall(RefineLabel_Internal(tr, label, labelNew)); 1948 } 1949 PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_CreateLabels, tr, dm, 0, 0)); 1950 PetscFunctionReturn(PETSC_SUCCESS); 1951 } 1952 1953 /* This refines the labels which define regions for fields and DSes since they are not in the list of labels for the DM */ 1954 PetscErrorCode DMPlexTransformCreateDiscLabels(DMPlexTransform tr, DM rdm) 1955 { 1956 DM dm; 1957 PetscInt Nf, f, Nds, s; 1958 1959 PetscFunctionBegin; 1960 PetscCall(DMPlexTransformGetDM(tr, &dm)); 1961 PetscCall(DMGetNumFields(dm, &Nf)); 1962 for (f = 0; f < Nf; ++f) { 1963 DMLabel label, labelNew; 1964 PetscObject obj; 1965 const char *lname; 1966 1967 PetscCall(DMGetField(rdm, f, &label, &obj)); 1968 if (!label) continue; 1969 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 1970 PetscCall(DMLabelCreate(PETSC_COMM_SELF, lname, &labelNew)); 1971 PetscCall(RefineLabel_Internal(tr, label, labelNew)); 1972 PetscCall(DMSetField_Internal(rdm, f, labelNew, obj)); 1973 PetscCall(DMLabelDestroy(&labelNew)); 1974 } 1975 PetscCall(DMGetNumDS(dm, &Nds)); 1976 for (s = 0; s < Nds; ++s) { 1977 DMLabel label, labelNew; 1978 const char *lname; 1979 1980 PetscCall(DMGetRegionNumDS(rdm, s, &label, NULL, NULL, NULL)); 1981 if (!label) continue; 1982 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 1983 PetscCall(DMLabelCreate(PETSC_COMM_SELF, lname, &labelNew)); 1984 PetscCall(RefineLabel_Internal(tr, label, labelNew)); 1985 PetscCall(DMSetRegionNumDS(rdm, s, labelNew, NULL, NULL, NULL)); 1986 PetscCall(DMLabelDestroy(&labelNew)); 1987 } 1988 PetscFunctionReturn(PETSC_SUCCESS); 1989 } 1990 1991 static PetscErrorCode DMPlexTransformCreateSF(DMPlexTransform tr, DM rdm) 1992 { 1993 DM dm; 1994 PetscSF sf, sfNew; 1995 PetscInt numRoots, numLeaves, numLeavesNew = 0, l, m; 1996 const PetscInt *localPoints; 1997 const PetscSFNode *remotePoints; 1998 PetscInt *localPointsNew; 1999 PetscSFNode *remotePointsNew; 2000 PetscInt pStartNew, pEndNew, pNew; 2001 /* Brute force algorithm */ 2002 PetscSF rsf; 2003 PetscSection s; 2004 const PetscInt *rootdegree; 2005 PetscInt *rootPointsNew, *remoteOffsets; 2006 PetscInt numPointsNew, pStart, pEnd, p; 2007 2008 PetscFunctionBegin; 2009 PetscCall(DMPlexTransformGetDM(tr, &dm)); 2010 PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_CreateSF, tr, dm, 0, 0)); 2011 PetscCall(DMPlexGetChart(rdm, &pStartNew, &pEndNew)); 2012 PetscCall(DMGetPointSF(dm, &sf)); 2013 PetscCall(DMGetPointSF(rdm, &sfNew)); 2014 /* Calculate size of new SF */ 2015 PetscCall(PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints)); 2016 if (numRoots < 0) { 2017 PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_CreateSF, tr, dm, 0, 0)); 2018 PetscFunctionReturn(PETSC_SUCCESS); 2019 } 2020 for (l = 0; l < numLeaves; ++l) { 2021 const PetscInt p = localPoints[l]; 2022 DMPolytopeType ct; 2023 DMPolytopeType *rct; 2024 PetscInt *rsize, *rcone, *rornt; 2025 PetscInt Nct, n; 2026 2027 PetscCall(DMPlexGetCellType(dm, p, &ct)); 2028 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 2029 for (n = 0; n < Nct; ++n) numLeavesNew += rsize[n]; 2030 } 2031 /* Send new root point numbers 2032 It is possible to optimize for regular transforms by sending only the cell type offsets, but it seems a needless complication 2033 */ 2034 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 2035 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &s)); 2036 PetscCall(PetscSectionSetChart(s, pStart, pEnd)); 2037 for (p = pStart; p < pEnd; ++p) { 2038 DMPolytopeType ct; 2039 DMPolytopeType *rct; 2040 PetscInt *rsize, *rcone, *rornt; 2041 PetscInt Nct, n; 2042 2043 PetscCall(DMPlexGetCellType(dm, p, &ct)); 2044 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 2045 for (n = 0; n < Nct; ++n) PetscCall(PetscSectionAddDof(s, p, rsize[n])); 2046 } 2047 PetscCall(PetscSectionSetUp(s)); 2048 PetscCall(PetscSectionGetStorageSize(s, &numPointsNew)); 2049 PetscCall(PetscSFCreateRemoteOffsets(sf, s, s, &remoteOffsets)); 2050 PetscCall(PetscSFCreateSectionSF(sf, s, remoteOffsets, s, &rsf)); 2051 PetscCall(PetscFree(remoteOffsets)); 2052 PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree)); 2053 PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree)); 2054 PetscCall(PetscMalloc1(numPointsNew, &rootPointsNew)); 2055 for (p = 0; p < numPointsNew; ++p) rootPointsNew[p] = -1; 2056 for (p = pStart; p < pEnd; ++p) { 2057 DMPolytopeType ct; 2058 DMPolytopeType *rct; 2059 PetscInt *rsize, *rcone, *rornt; 2060 PetscInt Nct, n, r, off; 2061 2062 if (!rootdegree[p - pStart]) continue; 2063 PetscCall(PetscSectionGetOffset(s, p, &off)); 2064 PetscCall(DMPlexGetCellType(dm, p, &ct)); 2065 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 2066 for (n = 0, m = 0; n < Nct; ++n) { 2067 for (r = 0; r < rsize[n]; ++r, ++m) { 2068 PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew)); 2069 rootPointsNew[off + m] = pNew; 2070 } 2071 } 2072 } 2073 PetscCall(PetscSFBcastBegin(rsf, MPIU_INT, rootPointsNew, rootPointsNew, MPI_REPLACE)); 2074 PetscCall(PetscSFBcastEnd(rsf, MPIU_INT, rootPointsNew, rootPointsNew, MPI_REPLACE)); 2075 PetscCall(PetscSFDestroy(&rsf)); 2076 PetscCall(PetscMalloc1(numLeavesNew, &localPointsNew)); 2077 PetscCall(PetscMalloc1(numLeavesNew, &remotePointsNew)); 2078 for (l = 0, m = 0; l < numLeaves; ++l) { 2079 const PetscInt p = localPoints[l]; 2080 DMPolytopeType ct; 2081 DMPolytopeType *rct; 2082 PetscInt *rsize, *rcone, *rornt; 2083 PetscInt Nct, n, r, q, off; 2084 2085 PetscCall(PetscSectionGetOffset(s, p, &off)); 2086 PetscCall(DMPlexGetCellType(dm, p, &ct)); 2087 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 2088 for (n = 0, q = 0; n < Nct; ++n) { 2089 for (r = 0; r < rsize[n]; ++r, ++m, ++q) { 2090 PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew)); 2091 localPointsNew[m] = pNew; 2092 remotePointsNew[m].index = rootPointsNew[off + q]; 2093 remotePointsNew[m].rank = remotePoints[l].rank; 2094 } 2095 } 2096 } 2097 PetscCall(PetscSectionDestroy(&s)); 2098 PetscCall(PetscFree(rootPointsNew)); 2099 /* SF needs sorted leaves to correctly calculate Gather */ 2100 { 2101 PetscSFNode *rp, *rtmp; 2102 PetscInt *lp, *idx, *ltmp, i; 2103 2104 PetscCall(PetscMalloc1(numLeavesNew, &idx)); 2105 PetscCall(PetscMalloc1(numLeavesNew, &lp)); 2106 PetscCall(PetscMalloc1(numLeavesNew, &rp)); 2107 for (i = 0; i < numLeavesNew; ++i) { 2108 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); 2109 idx[i] = i; 2110 } 2111 PetscCall(PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx)); 2112 for (i = 0; i < numLeavesNew; ++i) { 2113 lp[i] = localPointsNew[idx[i]]; 2114 rp[i] = remotePointsNew[idx[i]]; 2115 } 2116 ltmp = localPointsNew; 2117 localPointsNew = lp; 2118 rtmp = remotePointsNew; 2119 remotePointsNew = rp; 2120 PetscCall(PetscFree(idx)); 2121 PetscCall(PetscFree(ltmp)); 2122 PetscCall(PetscFree(rtmp)); 2123 } 2124 PetscCall(PetscSFSetGraph(sfNew, pEndNew - pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER)); 2125 PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_CreateSF, tr, dm, 0, 0)); 2126 PetscFunctionReturn(PETSC_SUCCESS); 2127 } 2128 2129 /* 2130 DMPlexCellRefinerMapLocalizedCoordinates - Given a cell of `DMPolytopeType` `ct` with localized coordinates `x`, generate localized coordinates `xr` for subcell `r` of type `rct`. 2131 2132 Not Collective 2133 2134 Input Parameters: 2135 + tr - The `DMPlexTransform` 2136 . ct - The type of the parent cell 2137 . rct - The type of the produced cell 2138 . r - The index of the produced cell 2139 - x - The localized coordinates for the parent cell 2140 2141 Output Parameter: 2142 . xr - The localized coordinates for the produced cell 2143 2144 Level: developer 2145 2146 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPolytopeType`, `DMPlexCellRefinerSetCoordinates()` 2147 */ 2148 static PetscErrorCode DMPlexTransformMapLocalizedCoordinates(DMPlexTransform tr, DMPolytopeType ct, DMPolytopeType rct, PetscInt r, const PetscScalar x[], PetscScalar xr[]) 2149 { 2150 PetscFE fe = NULL; 2151 PetscInt cdim, v, *subcellV; 2152 2153 PetscFunctionBegin; 2154 PetscCall(DMPlexTransformGetCoordinateFE(tr, ct, &fe)); 2155 PetscCall(DMPlexTransformGetSubcellVertices(tr, ct, rct, r, &subcellV)); 2156 PetscCall(PetscFEGetNumComponents(fe, &cdim)); 2157 for (v = 0; v < DMPolytopeTypeGetNumVertices(rct); ++v) PetscCall(PetscFEInterpolate_Static(fe, x, tr->refGeom[ct], subcellV[v], &xr[v * cdim])); 2158 PetscFunctionReturn(PETSC_SUCCESS); 2159 } 2160 2161 static PetscErrorCode DMPlexTransformSetCoordinates(DMPlexTransform tr, DM rdm) 2162 { 2163 DM dm, cdm, cdmCell, cdmNew, cdmCellNew; 2164 PetscSection coordSection, coordSectionNew, coordSectionCell, coordSectionCellNew; 2165 Vec coordsLocal, coordsLocalNew, coordsLocalCell = NULL, coordsLocalCellNew; 2166 const PetscScalar *coords; 2167 PetscScalar *coordsNew; 2168 const PetscReal *maxCell, *Lstart, *L; 2169 PetscBool localized, localizeVertices = PETSC_FALSE, localizeCells = PETSC_FALSE; 2170 PetscInt dE, dEo, d, cStart, cEnd, c, cStartNew, cEndNew, vStartNew, vEndNew, v, pStart, pEnd, p; 2171 2172 PetscFunctionBegin; 2173 // Need to clear the DMField for coordinates 2174 PetscCall(DMSetCoordinateField(rdm, NULL)); 2175 PetscCall(DMPlexTransformGetDM(tr, &dm)); 2176 PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_SetCoordinates, tr, dm, 0, 0)); 2177 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2178 PetscCall(DMGetCellCoordinateDM(dm, &cdmCell)); 2179 PetscCall(DMGetCoordinatesLocalized(dm, &localized)); 2180 PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L)); 2181 if (localized) { 2182 /* Localize coordinates of new vertices */ 2183 localizeVertices = PETSC_TRUE; 2184 /* If we do not have a mechanism for automatically localizing cell coordinates, we need to compute them explicitly for every divided cell */ 2185 if (!maxCell) localizeCells = PETSC_TRUE; 2186 } 2187 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 2188 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &dEo)); 2189 if (maxCell) { 2190 PetscReal maxCellNew[3]; 2191 2192 for (d = 0; d < dEo; ++d) maxCellNew[d] = maxCell[d] / 2.0; 2193 PetscCall(DMSetPeriodicity(rdm, maxCellNew, Lstart, L)); 2194 } 2195 PetscCall(DMGetCoordinateDim(rdm, &dE)); 2196 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)rdm), &coordSectionNew)); 2197 PetscCall(PetscSectionSetNumFields(coordSectionNew, 1)); 2198 PetscCall(PetscSectionSetFieldComponents(coordSectionNew, 0, dE)); 2199 PetscCall(DMPlexGetDepthStratum(rdm, 0, &vStartNew, &vEndNew)); 2200 PetscCall(PetscSectionSetChart(coordSectionNew, vStartNew, vEndNew)); 2201 /* Localization should be inherited */ 2202 /* Stefano calculates parent cells for each new cell for localization */ 2203 /* Localized cells need coordinates of closure */ 2204 for (v = vStartNew; v < vEndNew; ++v) { 2205 PetscCall(PetscSectionSetDof(coordSectionNew, v, dE)); 2206 PetscCall(PetscSectionSetFieldDof(coordSectionNew, v, 0, dE)); 2207 } 2208 PetscCall(PetscSectionSetUp(coordSectionNew)); 2209 PetscCall(DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew)); 2210 2211 if (localizeCells) { 2212 PetscCall(DMGetCoordinateDM(rdm, &cdmNew)); 2213 PetscCall(DMClone(cdmNew, &cdmCellNew)); 2214 PetscCall(DMSetCellCoordinateDM(rdm, cdmCellNew)); 2215 PetscCall(DMDestroy(&cdmCellNew)); 2216 2217 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)rdm), &coordSectionCellNew)); 2218 PetscCall(PetscSectionSetNumFields(coordSectionCellNew, 1)); 2219 PetscCall(PetscSectionSetFieldComponents(coordSectionCellNew, 0, dE)); 2220 PetscCall(DMPlexGetHeightStratum(rdm, 0, &cStartNew, &cEndNew)); 2221 PetscCall(PetscSectionSetChart(coordSectionCellNew, cStartNew, cEndNew)); 2222 2223 PetscCall(DMGetCellCoordinateSection(dm, &coordSectionCell)); 2224 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 2225 for (c = cStart; c < cEnd; ++c) { 2226 PetscInt dof; 2227 2228 PetscCall(PetscSectionGetDof(coordSectionCell, c, &dof)); 2229 if (dof) { 2230 DMPolytopeType ct; 2231 DMPolytopeType *rct; 2232 PetscInt *rsize, *rcone, *rornt; 2233 PetscInt dim, cNew, Nct, n, r; 2234 2235 PetscCall(DMPlexGetCellType(dm, c, &ct)); 2236 dim = DMPolytopeTypeGetDim(ct); 2237 PetscCall(DMPlexTransformCellTransform(tr, ct, c, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 2238 /* This allows for different cell types */ 2239 for (n = 0; n < Nct; ++n) { 2240 if (dim != DMPolytopeTypeGetDim(rct[n])) continue; 2241 for (r = 0; r < rsize[n]; ++r) { 2242 PetscInt *closure = NULL; 2243 PetscInt clSize, cl, Nv = 0; 2244 2245 PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], c, r, &cNew)); 2246 PetscCall(DMPlexGetTransitiveClosure(rdm, cNew, PETSC_TRUE, &clSize, &closure)); 2247 for (cl = 0; cl < clSize * 2; cl += 2) { 2248 if ((closure[cl] >= vStartNew) && (closure[cl] < vEndNew)) ++Nv; 2249 } 2250 PetscCall(DMPlexRestoreTransitiveClosure(rdm, cNew, PETSC_TRUE, &clSize, &closure)); 2251 PetscCall(PetscSectionSetDof(coordSectionCellNew, cNew, Nv * dE)); 2252 PetscCall(PetscSectionSetFieldDof(coordSectionCellNew, cNew, 0, Nv * dE)); 2253 } 2254 } 2255 } 2256 } 2257 PetscCall(PetscSectionSetUp(coordSectionCellNew)); 2258 PetscCall(DMSetCellCoordinateSection(rdm, PETSC_DETERMINE, coordSectionCellNew)); 2259 } 2260 PetscCall(DMViewFromOptions(dm, NULL, "-coarse_dm_view")); 2261 { 2262 VecType vtype; 2263 PetscInt coordSizeNew, bs; 2264 const char *name; 2265 2266 PetscCall(DMGetCoordinatesLocal(dm, &coordsLocal)); 2267 PetscCall(VecCreate(PETSC_COMM_SELF, &coordsLocalNew)); 2268 PetscCall(PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew)); 2269 PetscCall(VecSetSizes(coordsLocalNew, coordSizeNew, PETSC_DETERMINE)); 2270 PetscCall(PetscObjectGetName((PetscObject)coordsLocal, &name)); 2271 PetscCall(PetscObjectSetName((PetscObject)coordsLocalNew, name)); 2272 PetscCall(VecGetBlockSize(coordsLocal, &bs)); 2273 PetscCall(VecSetBlockSize(coordsLocalNew, dEo == dE ? bs : dE)); 2274 PetscCall(VecGetType(coordsLocal, &vtype)); 2275 PetscCall(VecSetType(coordsLocalNew, vtype)); 2276 } 2277 PetscCall(VecGetArrayRead(coordsLocal, &coords)); 2278 PetscCall(VecGetArray(coordsLocalNew, &coordsNew)); 2279 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 2280 /* First set coordinates for vertices */ 2281 for (p = pStart; p < pEnd; ++p) { 2282 DMPolytopeType ct; 2283 DMPolytopeType *rct; 2284 PetscInt *rsize, *rcone, *rornt; 2285 PetscInt Nct, n, r; 2286 PetscBool hasVertex = PETSC_FALSE; 2287 2288 PetscCall(DMPlexGetCellType(dm, p, &ct)); 2289 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 2290 for (n = 0; n < Nct; ++n) { 2291 if (rct[n] == DM_POLYTOPE_POINT) { 2292 hasVertex = PETSC_TRUE; 2293 break; 2294 } 2295 } 2296 if (hasVertex) { 2297 const PetscScalar *icoords = NULL; 2298 const PetscScalar *array = NULL; 2299 PetscScalar *pcoords = NULL; 2300 PetscBool isDG; 2301 PetscInt Nc, Nv, v, d; 2302 2303 PetscCall(DMPlexGetCellCoordinates(dm, p, &isDG, &Nc, &array, &pcoords)); 2304 2305 icoords = pcoords; 2306 Nv = Nc / dEo; 2307 if (ct != DM_POLYTOPE_POINT) { 2308 if (localizeVertices && maxCell) { 2309 PetscScalar anchor[3]; 2310 2311 for (d = 0; d < dEo; ++d) anchor[d] = pcoords[d]; 2312 for (v = 0; v < Nv; ++v) PetscCall(DMLocalizeCoordinate_Internal(dm, dEo, anchor, &pcoords[v * dEo], &pcoords[v * dEo])); 2313 } 2314 } 2315 for (n = 0; n < Nct; ++n) { 2316 if (rct[n] != DM_POLYTOPE_POINT) continue; 2317 for (r = 0; r < rsize[n]; ++r) { 2318 PetscScalar vcoords[3]; 2319 PetscInt vNew, off; 2320 2321 PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &vNew)); 2322 PetscCall(PetscSectionGetOffset(coordSectionNew, vNew, &off)); 2323 PetscCall(DMPlexTransformMapCoordinates(tr, ct, rct[n], p, r, Nv, dEo, icoords, vcoords)); 2324 PetscCall(DMSnapToGeomModel(dm, p, dE, vcoords, &coordsNew[off])); 2325 } 2326 } 2327 PetscCall(DMPlexRestoreCellCoordinates(dm, p, &isDG, &Nc, &array, &pcoords)); 2328 } 2329 } 2330 PetscCall(VecRestoreArrayRead(coordsLocal, &coords)); 2331 PetscCall(VecRestoreArray(coordsLocalNew, &coordsNew)); 2332 PetscCall(DMSetCoordinatesLocal(rdm, coordsLocalNew)); 2333 PetscCall(VecDestroy(&coordsLocalNew)); 2334 PetscCall(PetscSectionDestroy(&coordSectionNew)); 2335 /* Then set coordinates for cells by localizing */ 2336 if (!localizeCells) PetscCall(DMLocalizeCoordinates(rdm)); 2337 else { 2338 VecType vtype; 2339 PetscInt coordSizeNew, bs; 2340 const char *name; 2341 2342 PetscCall(DMGetCellCoordinatesLocal(dm, &coordsLocalCell)); 2343 PetscCall(VecCreate(PETSC_COMM_SELF, &coordsLocalCellNew)); 2344 PetscCall(PetscSectionGetStorageSize(coordSectionCellNew, &coordSizeNew)); 2345 PetscCall(VecSetSizes(coordsLocalCellNew, coordSizeNew, PETSC_DETERMINE)); 2346 PetscCall(PetscObjectGetName((PetscObject)coordsLocalCell, &name)); 2347 PetscCall(PetscObjectSetName((PetscObject)coordsLocalCellNew, name)); 2348 PetscCall(VecGetBlockSize(coordsLocalCell, &bs)); 2349 PetscCall(VecSetBlockSize(coordsLocalCellNew, dEo == dE ? bs : dE)); 2350 PetscCall(VecGetType(coordsLocalCell, &vtype)); 2351 PetscCall(VecSetType(coordsLocalCellNew, vtype)); 2352 PetscCall(VecGetArrayRead(coordsLocalCell, &coords)); 2353 PetscCall(VecGetArray(coordsLocalCellNew, &coordsNew)); 2354 2355 for (p = pStart; p < pEnd; ++p) { 2356 DMPolytopeType ct; 2357 DMPolytopeType *rct; 2358 PetscInt *rsize, *rcone, *rornt; 2359 PetscInt dof = 0, Nct, n, r; 2360 2361 PetscCall(DMPlexGetCellType(dm, p, &ct)); 2362 PetscCall(DMPlexTransformCellTransform(tr, ct, p, NULL, &Nct, &rct, &rsize, &rcone, &rornt)); 2363 if (p >= cStart && p < cEnd) PetscCall(PetscSectionGetDof(coordSectionCell, p, &dof)); 2364 if (dof) { 2365 const PetscScalar *pcoords; 2366 2367 PetscCall(DMPlexPointLocalRead(cdmCell, p, coords, &pcoords)); 2368 for (n = 0; n < Nct; ++n) { 2369 const PetscInt Nr = rsize[n]; 2370 2371 if (DMPolytopeTypeGetDim(ct) != DMPolytopeTypeGetDim(rct[n])) continue; 2372 for (r = 0; r < Nr; ++r) { 2373 PetscInt pNew, offNew; 2374 2375 /* It looks like Stefano and Lisandro are allowing localized coordinates without defining the periodic boundary, which means that 2376 DMLocalizeCoordinate_Internal() will not work. Localized coordinates will have to have obtained by the affine map of the larger 2377 cell to the ones it produces. */ 2378 PetscCall(DMPlexTransformGetTargetPoint(tr, ct, rct[n], p, r, &pNew)); 2379 PetscCall(PetscSectionGetOffset(coordSectionCellNew, pNew, &offNew)); 2380 PetscCall(DMPlexTransformMapLocalizedCoordinates(tr, ct, rct[n], r, pcoords, &coordsNew[offNew])); 2381 } 2382 } 2383 } 2384 } 2385 PetscCall(VecRestoreArrayRead(coordsLocalCell, &coords)); 2386 PetscCall(VecRestoreArray(coordsLocalCellNew, &coordsNew)); 2387 PetscCall(DMSetCellCoordinatesLocal(rdm, coordsLocalCellNew)); 2388 PetscCall(VecDestroy(&coordsLocalCellNew)); 2389 PetscCall(PetscSectionDestroy(&coordSectionCellNew)); 2390 } 2391 PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_SetCoordinates, tr, dm, 0, 0)); 2392 PetscFunctionReturn(PETSC_SUCCESS); 2393 } 2394 2395 /*@ 2396 DMPlexTransformApply - Execute the transformation, producing another `DM` 2397 2398 Collective 2399 2400 Input Parameters: 2401 + tr - The `DMPlexTransform` object 2402 - dm - The original `DM` 2403 2404 Output Parameter: 2405 . trdm - The transformed `DM` 2406 2407 Level: intermediate 2408 2409 Options Database Keys: 2410 + -dm_plex_transform_label_match_strata - Only label points of the same stratum as the producing point 2411 . -dm_plex_transform_label_replica_inc <num> - Increment for the label value to be multiplied by the replica number 2412 - -dm_plex_transform_active <name> - Name for active mesh label 2413 2414 .seealso: [](plex_transform_table), [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexTransform`, `DMPlexTransformCreate()`, `DMPlexTransformSetDM()` 2415 @*/ 2416 PetscErrorCode DMPlexTransformApply(DMPlexTransform tr, DM dm, DM *trdm) 2417 { 2418 DM rdm; 2419 DMPlexInterpolatedFlag interp; 2420 PetscInt pStart, pEnd; 2421 2422 PetscFunctionBegin; 2423 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 2424 PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 2425 PetscAssertPointer(trdm, 3); 2426 PetscCall(PetscLogEventBegin(DMPLEXTRANSFORM_Apply, tr, dm, 0, 0)); 2427 PetscCall(DMPlexTransformSetDM(tr, dm)); 2428 2429 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &rdm)); 2430 PetscCall(DMSetType(rdm, DMPLEX)); 2431 PetscCall(DMPlexTransformSetDimensions(tr, dm, rdm)); 2432 /* Calculate number of new points of each depth */ 2433 PetscCall(DMPlexIsInterpolatedCollective(dm, &interp)); 2434 PetscCheck(interp == DMPLEX_INTERPOLATED_FULL, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mesh must be fully interpolated for regular refinement"); 2435 /* Step 1: Set chart */ 2436 PetscCall(DMPlexTransformGetChart(tr, &pStart, &pEnd)); 2437 PetscCall(DMPlexSetChart(rdm, pStart, pEnd)); 2438 /* Step 2: Set cone/support sizes (automatically stratifies) */ 2439 PetscCall(DMPlexTransformSetConeSizes(tr, rdm)); 2440 /* Step 3: Setup refined DM */ 2441 PetscCall(DMSetUp(rdm)); 2442 /* Step 4: Set cones and supports (automatically symmetrizes) */ 2443 PetscCall(DMPlexTransformSetCones(tr, rdm)); 2444 /* Step 5: Create pointSF */ 2445 PetscCall(DMPlexTransformCreateSF(tr, rdm)); 2446 /* Step 6: Create labels */ 2447 PetscCall(DMPlexTransformCreateLabels(tr, rdm)); 2448 /* Step 7: Set coordinates */ 2449 PetscCall(DMPlexTransformSetCoordinates(tr, rdm)); 2450 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, rdm)); 2451 // If the original DM was configured from options, the transformed DM should be as well 2452 rdm->setfromoptionscalled = dm->setfromoptionscalled; 2453 PetscCall(PetscLogEventEnd(DMPLEXTRANSFORM_Apply, tr, dm, 0, 0)); 2454 *trdm = rdm; 2455 PetscFunctionReturn(PETSC_SUCCESS); 2456 } 2457 2458 PetscErrorCode DMPlexTransformAdaptLabel(DM dm, PETSC_UNUSED Vec metric, DMLabel adaptLabel, PETSC_UNUSED DMLabel rgLabel, DM *rdm) 2459 { 2460 DMPlexTransform tr; 2461 DM cdm, rcdm; 2462 const char *prefix; 2463 PetscBool save; 2464 2465 PetscFunctionBegin; 2466 PetscCall(DMPlexTransformCreate(PetscObjectComm((PetscObject)dm), &tr)); 2467 PetscCall(PetscObjectSetName((PetscObject)tr, "Adapt Label Transform")); 2468 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 2469 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)tr, prefix)); 2470 PetscCall(DMPlexTransformSetDM(tr, dm)); 2471 PetscCall(DMPlexTransformSetFromOptions(tr)); 2472 if (adaptLabel) PetscCall(DMPlexTransformSetActive(tr, adaptLabel)); 2473 PetscCall(DMPlexTransformSetUp(tr)); 2474 PetscCall(PetscObjectViewFromOptions((PetscObject)tr, NULL, "-dm_plex_transform_view")); 2475 PetscCall(DMPlexTransformApply(tr, dm, rdm)); 2476 PetscCall(DMCopyDisc(dm, *rdm)); 2477 PetscCall(DMGetCoordinateDM(dm, &cdm)); 2478 PetscCall(DMGetCoordinateDM(*rdm, &rcdm)); 2479 PetscCall(DMCopyDisc(cdm, rcdm)); 2480 PetscCall(DMPlexTransformCreateDiscLabels(tr, *rdm)); 2481 PetscCall(DMCopyDisc(dm, *rdm)); 2482 PetscCall(DMPlexGetSaveTransform(dm, &save)); 2483 if (save) PetscCall(DMPlexSetTransform(*rdm, tr)); 2484 PetscCall(DMPlexTransformDestroy(&tr)); 2485 ((DM_Plex *)(*rdm)->data)->useHashLocation = ((DM_Plex *)dm->data)->useHashLocation; 2486 PetscFunctionReturn(PETSC_SUCCESS); 2487 } 2488