1 #include <petsc/private/dmplextransformimpl.h> /*I "petscdmplextransform.h" I*/ 2 3 static PetscErrorCode DMPlexTransformView_Extrude(DMPlexTransform tr, PetscViewer viewer) 4 { 5 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 6 PetscBool isascii; 7 8 PetscFunctionBegin; 9 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 10 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 11 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 12 if (isascii) { 13 DM dm; 14 DMLabel active; 15 PetscInt dim; 16 const char *name; 17 char normal[PETSC_MAX_PATH_LEN]; 18 19 PetscCall(PetscObjectGetName((PetscObject)tr, &name)); 20 PetscCall(DMPlexTransformGetDM(tr, &dm)); 21 PetscCall(DMGetDimension(dm, &dim)); 22 PetscCall(DMPlexTransformGetActive(tr, &active)); 23 if (ex->normalFunc) PetscCall(PetscSNPrintf(normal, PETSC_MAX_PATH_LEN, "User function")); 24 else if (dim != ex->cdim && !ex->useNormal) PetscCall(PetscSNPrintf(normal, PETSC_MAX_PATH_LEN, "Compute normal from star")); 25 else if (ex->useNormal) PetscCall(PetscSNPrintf(normal, PETSC_MAX_PATH_LEN, "Input normal")); 26 else if (active) PetscCall(PetscSNPrintf(normal, PETSC_MAX_PATH_LEN, "Compute normal from star of active point")); 27 else PetscCall(PetscSNPrintf(normal, PETSC_MAX_PATH_LEN, "Default normal")); 28 29 PetscCall(PetscViewerASCIIPrintf(viewer, "Extrusion transformation %s\n", name ? name : "")); 30 PetscCall(PetscViewerASCIIPrintf(viewer, " number of layers: %" PetscInt_FMT "\n", ex->layers)); 31 PetscCall(PetscViewerASCIIPrintf(viewer, " create tensor cells: %s\n", ex->useTensor ? "YES" : "NO")); 32 if (ex->periodic) PetscCall(PetscViewerASCIIPrintf(viewer, " periodic\n")); 33 PetscCall(PetscViewerASCIIPrintf(viewer, " normal: %s\n", normal)); 34 } else { 35 SETERRQ(PetscObjectComm((PetscObject)tr), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMPlexTransform writing", ((PetscObject)viewer)->type_name); 36 } 37 PetscFunctionReturn(PETSC_SUCCESS); 38 } 39 40 static PetscErrorCode DMPlexTransformSetFromOptions_Extrude(DMPlexTransform tr, PetscOptionItems *PetscOptionsObject) 41 { 42 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 43 PetscReal th, normal[3], *thicknesses; 44 PetscInt nl, Nc; 45 PetscBool tensor, sym, per, flg; 46 char funcname[PETSC_MAX_PATH_LEN]; 47 48 PetscFunctionBegin; 49 PetscOptionsHeadBegin(PetscOptionsObject, "DMPlexTransform Extrusion Options"); 50 PetscCall(PetscOptionsBoundedInt("-dm_plex_transform_extrude_layers", "Number of layers to extrude", "", ex->layers, &nl, &flg, 1)); 51 if (flg) PetscCall(DMPlexTransformExtrudeSetLayers(tr, nl)); 52 PetscCall(PetscOptionsReal("-dm_plex_transform_extrude_thickness", "Total thickness of extruded layers", "", ex->thickness, &th, &flg)); 53 if (flg) PetscCall(DMPlexTransformExtrudeSetThickness(tr, th)); 54 PetscCall(PetscOptionsBool("-dm_plex_transform_extrude_use_tensor", "Create tensor cells", "", ex->useTensor, &tensor, &flg)); 55 if (flg) PetscCall(DMPlexTransformExtrudeSetTensor(tr, tensor)); 56 PetscCall(PetscOptionsBool("-dm_plex_transform_extrude_symmetric", "Extrude layers symmetrically about the surface", "", ex->symmetric, &sym, &flg)); 57 if (flg) PetscCall(DMPlexTransformExtrudeSetSymmetric(tr, sym)); 58 PetscCall(PetscOptionsBool("-dm_plex_transform_extrude_periodic", "Extrude layers periodically about the surface", "", ex->periodic, &per, &flg)); 59 if (flg) PetscCall(DMPlexTransformExtrudeSetPeriodic(tr, per)); 60 Nc = 3; 61 PetscCall(PetscOptionsRealArray("-dm_plex_transform_extrude_normal", "Input normal vector for extrusion", "DMPlexTransformExtrudeSetNormal", normal, &Nc, &flg)); 62 if (flg) { 63 // Extrusion dimension might not yet be determined 64 PetscCheck(!ex->cdimEx || Nc == ex->cdimEx, PetscObjectComm((PetscObject)tr), PETSC_ERR_ARG_SIZ, "Input normal has size %" PetscInt_FMT " != %" PetscInt_FMT " extruded coordinate dimension", Nc, ex->cdimEx); 65 PetscCall(DMPlexTransformExtrudeSetNormal(tr, normal)); 66 } 67 PetscCall(PetscOptionsString("-dm_plex_transform_extrude_normal_function", "Function to determine normal vector", "DMPlexTransformExtrudeSetNormalFunction", funcname, funcname, sizeof(funcname), &flg)); 68 if (flg) { 69 PetscSimplePointFn *normalFunc; 70 71 PetscCall(PetscDLSym(NULL, funcname, (void **)&normalFunc)); 72 PetscCall(DMPlexTransformExtrudeSetNormalFunction(tr, normalFunc)); 73 } 74 nl = ex->layers; 75 PetscCall(PetscMalloc1(nl, &thicknesses)); 76 PetscCall(PetscOptionsRealArray("-dm_plex_transform_extrude_thicknesses", "Thickness of each individual extruded layer", "", thicknesses, &nl, &flg)); 77 if (flg) { 78 PetscCheck(nl, PetscObjectComm((PetscObject)tr), PETSC_ERR_ARG_OUTOFRANGE, "Must give at least one thickness for -dm_plex_transform_extrude_thicknesses"); 79 PetscCall(DMPlexTransformExtrudeSetThicknesses(tr, nl, thicknesses)); 80 } 81 PetscCall(PetscFree(thicknesses)); 82 PetscOptionsHeadEnd(); 83 PetscFunctionReturn(PETSC_SUCCESS); 84 } 85 86 /* Determine the implicit dimension pre-extrusion (either the implicit dimension of the DM or of a point in the active set for the transform). 87 If that dimension is the same as the current coordinate dimension (ex->dim), the extruded mesh will have a coordinate dimension one greater; 88 Otherwise the coordinate dimension will be kept. */ 89 static PetscErrorCode DMPlexTransformExtrudeComputeExtrusionDim(DMPlexTransform tr) 90 { 91 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 92 DM dm; 93 DMLabel active; 94 PetscInt dim, dimExtPoint, dimExtPointG; 95 96 PetscFunctionBegin; 97 PetscCall(DMPlexTransformGetDM(tr, &dm)); 98 PetscCall(DMGetDimension(dm, &dim)); 99 PetscCall(DMPlexTransformGetActive(tr, &active)); 100 if (active) { 101 IS valueIS, pointIS; 102 const PetscInt *values, *points; 103 DMPolytopeType ct; 104 PetscInt Nv, Np; 105 106 dimExtPoint = 0; 107 PetscCall(DMLabelGetValueIS(active, &valueIS)); 108 PetscCall(ISGetLocalSize(valueIS, &Nv)); 109 PetscCall(ISGetIndices(valueIS, &values)); 110 for (PetscInt v = 0; v < Nv; ++v) { 111 PetscCall(DMLabelGetStratumIS(active, values[v], &pointIS)); 112 PetscCall(ISGetLocalSize(pointIS, &Np)); 113 PetscCall(ISGetIndices(pointIS, &points)); 114 for (PetscInt p = 0; p < Np; ++p) { 115 PetscCall(DMPlexGetCellType(dm, points[p], &ct)); 116 dimExtPoint = PetscMax(dimExtPoint, DMPolytopeTypeGetDim(ct)); 117 } 118 PetscCall(ISRestoreIndices(pointIS, &points)); 119 PetscCall(ISDestroy(&pointIS)); 120 } 121 PetscCall(ISRestoreIndices(valueIS, &values)); 122 PetscCall(ISDestroy(&valueIS)); 123 } else dimExtPoint = dim; 124 PetscCall(MPIU_Allreduce(&dimExtPoint, &dimExtPointG, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)tr))); 125 ex->dimEx = PetscMax(dim, dimExtPointG + 1); 126 ex->cdimEx = ex->cdim == dimExtPointG ? ex->cdim + 1 : ex->cdim; 127 PetscCheck(ex->dimEx <= 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Topological dimension for extruded mesh %" PetscInt_FMT " must not exceed 3", ex->dimEx); 128 PetscCheck(ex->cdimEx <= 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate dimension for extruded mesh %" PetscInt_FMT " must not exceed 3", ex->cdimEx); 129 PetscFunctionReturn(PETSC_SUCCESS); 130 } 131 132 static PetscErrorCode DMPlexTransformSetDimensions_Extrude(DMPlexTransform tr, DM dm, DM tdm) 133 { 134 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 135 PetscInt dim; 136 137 PetscFunctionBegin; 138 PetscCall(DMGetDimension(dm, &dim)); 139 PetscCall(DMSetDimension(tdm, ex->dimEx)); 140 PetscCall(DMSetCoordinateDim(tdm, ex->cdimEx)); 141 PetscFunctionReturn(PETSC_SUCCESS); 142 } 143 144 /* DM_POLYTOPE_POINT produces 145 Nl+1 points, or Nl points periodically and 146 Nl segments, or tensor segments 147 */ 148 static PetscErrorCode DMPlexTransformExtrudeSetUp_Point(DMPlexTransform_Extrude *ex, PetscInt Nl) 149 { 150 const DMPolytopeType ct = DM_POLYTOPE_POINT; 151 const PetscInt Np = ex->periodic ? Nl : Nl + 1; 152 PetscInt Nc, No; 153 154 PetscFunctionBegin; 155 ex->Nt[ct] = 2; 156 Nc = 6 * Nl; 157 No = 2 * Nl; 158 PetscCall(PetscMalloc4(ex->Nt[ct], &ex->target[ct], ex->Nt[ct], &ex->size[ct], Nc, &ex->cone[ct], No, &ex->ornt[ct])); 159 ex->target[ct][0] = DM_POLYTOPE_POINT; 160 ex->target[ct][1] = ex->useTensor ? DM_POLYTOPE_POINT_PRISM_TENSOR : DM_POLYTOPE_SEGMENT; 161 ex->size[ct][0] = Np; 162 ex->size[ct][1] = Nl; 163 /* cones for segments/tensor segments */ 164 for (PetscInt i = 0; i < Nl; ++i) { 165 ex->cone[ct][6 * i + 0] = DM_POLYTOPE_POINT; 166 ex->cone[ct][6 * i + 1] = 0; 167 ex->cone[ct][6 * i + 2] = i; 168 ex->cone[ct][6 * i + 3] = DM_POLYTOPE_POINT; 169 ex->cone[ct][6 * i + 4] = 0; 170 ex->cone[ct][6 * i + 5] = (i + 1) % Np; 171 } 172 for (PetscInt i = 0; i < No; ++i) ex->ornt[ct][i] = 0; 173 PetscFunctionReturn(PETSC_SUCCESS); 174 } 175 176 /* DM_POLYTOPE_SEGMENT produces 177 Nl+1 segments, or Nl segments periodically and 178 Nl quads, or tensor quads 179 */ 180 static PetscErrorCode DMPlexTransformExtrudeSetUp_Segment(DMPlexTransform_Extrude *ex, PetscInt Nl) 181 { 182 const DMPolytopeType ct = DM_POLYTOPE_SEGMENT; 183 const PetscInt Np = ex->periodic ? Nl : Nl + 1; 184 PetscInt Nc, No, coff, ooff; 185 186 PetscFunctionBegin; 187 ex->Nt[ct] = 2; 188 Nc = 8 * Np + 14 * Nl; 189 No = 2 * Np + 4 * Nl; 190 PetscCall(PetscMalloc4(ex->Nt[ct], &ex->target[ct], ex->Nt[ct], &ex->size[ct], Nc, &ex->cone[ct], No, &ex->ornt[ct])); 191 ex->target[ct][0] = DM_POLYTOPE_SEGMENT; 192 ex->target[ct][1] = ex->useTensor ? DM_POLYTOPE_SEG_PRISM_TENSOR : DM_POLYTOPE_QUADRILATERAL; 193 ex->size[ct][0] = Np; 194 ex->size[ct][1] = Nl; 195 /* cones for segments */ 196 for (PetscInt i = 0; i < Np; ++i) { 197 ex->cone[ct][8 * i + 0] = DM_POLYTOPE_POINT; 198 ex->cone[ct][8 * i + 1] = 1; 199 ex->cone[ct][8 * i + 2] = 0; 200 ex->cone[ct][8 * i + 3] = i; 201 ex->cone[ct][8 * i + 4] = DM_POLYTOPE_POINT; 202 ex->cone[ct][8 * i + 5] = 1; 203 ex->cone[ct][8 * i + 6] = 1; 204 ex->cone[ct][8 * i + 7] = i; 205 } 206 for (PetscInt i = 0; i < 2 * Np; ++i) ex->ornt[ct][i] = 0; 207 /* cones for quads/tensor quads */ 208 coff = 8 * Np; 209 ooff = 2 * Np; 210 for (PetscInt i = 0; i < Nl; ++i) { 211 if (ex->useTensor) { 212 ex->cone[ct][coff + 14 * i + 0] = DM_POLYTOPE_SEGMENT; 213 ex->cone[ct][coff + 14 * i + 1] = 0; 214 ex->cone[ct][coff + 14 * i + 2] = i; 215 ex->cone[ct][coff + 14 * i + 3] = DM_POLYTOPE_SEGMENT; 216 ex->cone[ct][coff + 14 * i + 4] = 0; 217 ex->cone[ct][coff + 14 * i + 5] = (i + 1) % Np; 218 ex->cone[ct][coff + 14 * i + 6] = DM_POLYTOPE_POINT_PRISM_TENSOR; 219 ex->cone[ct][coff + 14 * i + 7] = 1; 220 ex->cone[ct][coff + 14 * i + 8] = 0; 221 ex->cone[ct][coff + 14 * i + 9] = i; 222 ex->cone[ct][coff + 14 * i + 10] = DM_POLYTOPE_POINT_PRISM_TENSOR; 223 ex->cone[ct][coff + 14 * i + 11] = 1; 224 ex->cone[ct][coff + 14 * i + 12] = 1; 225 ex->cone[ct][coff + 14 * i + 13] = i; 226 ex->ornt[ct][ooff + 4 * i + 0] = 0; 227 ex->ornt[ct][ooff + 4 * i + 1] = 0; 228 ex->ornt[ct][ooff + 4 * i + 2] = 0; 229 ex->ornt[ct][ooff + 4 * i + 3] = 0; 230 } else { 231 ex->cone[ct][coff + 14 * i + 0] = DM_POLYTOPE_SEGMENT; 232 ex->cone[ct][coff + 14 * i + 1] = 0; 233 ex->cone[ct][coff + 14 * i + 2] = i; 234 ex->cone[ct][coff + 14 * i + 3] = DM_POLYTOPE_SEGMENT; 235 ex->cone[ct][coff + 14 * i + 4] = 1; 236 ex->cone[ct][coff + 14 * i + 5] = 1; 237 ex->cone[ct][coff + 14 * i + 6] = i; 238 ex->cone[ct][coff + 14 * i + 7] = DM_POLYTOPE_SEGMENT; 239 ex->cone[ct][coff + 14 * i + 8] = 0; 240 ex->cone[ct][coff + 14 * i + 9] = (i + 1) % Np; 241 ex->cone[ct][coff + 14 * i + 10] = DM_POLYTOPE_SEGMENT; 242 ex->cone[ct][coff + 14 * i + 11] = 1; 243 ex->cone[ct][coff + 14 * i + 12] = 0; 244 ex->cone[ct][coff + 14 * i + 13] = i; 245 ex->ornt[ct][ooff + 4 * i + 0] = 0; 246 ex->ornt[ct][ooff + 4 * i + 1] = 0; 247 ex->ornt[ct][ooff + 4 * i + 2] = -1; 248 ex->ornt[ct][ooff + 4 * i + 3] = -1; 249 } 250 } 251 PetscFunctionReturn(PETSC_SUCCESS); 252 } 253 254 /* DM_POLYTOPE_TRIANGLE produces 255 Nl+1 triangles, or Nl triangles periodically and 256 Nl triangular prisms/tensor triangular prisms 257 */ 258 static PetscErrorCode DMPlexTransformExtrudeSetUp_Triangle(DMPlexTransform_Extrude *ex, PetscInt Nl) 259 { 260 const DMPolytopeType ct = DM_POLYTOPE_TRIANGLE; 261 const PetscInt Np = ex->periodic ? Nl : Nl + 1; 262 PetscInt Nc, No, coff, ooff; 263 264 PetscFunctionBegin; 265 ex->Nt[ct] = 2; 266 Nc = 12 * Np + 18 * Nl; 267 No = 3 * Np + 5 * Nl; 268 PetscCall(PetscMalloc4(ex->Nt[ct], &ex->target[ct], ex->Nt[ct], &ex->size[ct], Nc, &ex->cone[ct], No, &ex->ornt[ct])); 269 ex->target[ct][0] = DM_POLYTOPE_TRIANGLE; 270 ex->target[ct][1] = ex->useTensor ? DM_POLYTOPE_TRI_PRISM_TENSOR : DM_POLYTOPE_TRI_PRISM; 271 ex->size[ct][0] = Np; 272 ex->size[ct][1] = Nl; 273 /* cones for triangles */ 274 for (PetscInt i = 0; i < Np; ++i) { 275 ex->cone[ct][12 * i + 0] = DM_POLYTOPE_SEGMENT; 276 ex->cone[ct][12 * i + 1] = 1; 277 ex->cone[ct][12 * i + 2] = 0; 278 ex->cone[ct][12 * i + 3] = i; 279 ex->cone[ct][12 * i + 4] = DM_POLYTOPE_SEGMENT; 280 ex->cone[ct][12 * i + 5] = 1; 281 ex->cone[ct][12 * i + 6] = 1; 282 ex->cone[ct][12 * i + 7] = i; 283 ex->cone[ct][12 * i + 8] = DM_POLYTOPE_SEGMENT; 284 ex->cone[ct][12 * i + 9] = 1; 285 ex->cone[ct][12 * i + 10] = 2; 286 ex->cone[ct][12 * i + 11] = i; 287 } 288 for (PetscInt i = 0; i < 3 * Np; ++i) ex->ornt[ct][i] = 0; 289 /* cones for triangular prisms/tensor triangular prisms */ 290 coff = 12 * Np; 291 ooff = 3 * Np; 292 for (PetscInt i = 0; i < Nl; ++i) { 293 if (ex->useTensor) { 294 ex->cone[ct][coff + 18 * i + 0] = DM_POLYTOPE_TRIANGLE; 295 ex->cone[ct][coff + 18 * i + 1] = 0; 296 ex->cone[ct][coff + 18 * i + 2] = i; 297 ex->cone[ct][coff + 18 * i + 3] = DM_POLYTOPE_TRIANGLE; 298 ex->cone[ct][coff + 18 * i + 4] = 0; 299 ex->cone[ct][coff + 18 * i + 5] = (i + 1) % Np; 300 ex->cone[ct][coff + 18 * i + 6] = DM_POLYTOPE_SEG_PRISM_TENSOR; 301 ex->cone[ct][coff + 18 * i + 7] = 1; 302 ex->cone[ct][coff + 18 * i + 8] = 0; 303 ex->cone[ct][coff + 18 * i + 9] = i; 304 ex->cone[ct][coff + 18 * i + 10] = DM_POLYTOPE_SEG_PRISM_TENSOR; 305 ex->cone[ct][coff + 18 * i + 11] = 1; 306 ex->cone[ct][coff + 18 * i + 12] = 1; 307 ex->cone[ct][coff + 18 * i + 13] = i; 308 ex->cone[ct][coff + 18 * i + 14] = DM_POLYTOPE_SEG_PRISM_TENSOR; 309 ex->cone[ct][coff + 18 * i + 15] = 1; 310 ex->cone[ct][coff + 18 * i + 16] = 2; 311 ex->cone[ct][coff + 18 * i + 17] = i; 312 ex->ornt[ct][ooff + 5 * i + 0] = 0; 313 ex->ornt[ct][ooff + 5 * i + 1] = 0; 314 ex->ornt[ct][ooff + 5 * i + 2] = 0; 315 ex->ornt[ct][ooff + 5 * i + 3] = 0; 316 ex->ornt[ct][ooff + 5 * i + 4] = 0; 317 } else { 318 ex->cone[ct][coff + 18 * i + 0] = DM_POLYTOPE_TRIANGLE; 319 ex->cone[ct][coff + 18 * i + 1] = 0; 320 ex->cone[ct][coff + 18 * i + 2] = i; 321 ex->cone[ct][coff + 18 * i + 3] = DM_POLYTOPE_TRIANGLE; 322 ex->cone[ct][coff + 18 * i + 4] = 0; 323 ex->cone[ct][coff + 18 * i + 5] = (i + 1) % Np; 324 ex->cone[ct][coff + 18 * i + 6] = DM_POLYTOPE_QUADRILATERAL; 325 ex->cone[ct][coff + 18 * i + 7] = 1; 326 ex->cone[ct][coff + 18 * i + 8] = 0; 327 ex->cone[ct][coff + 18 * i + 9] = i; 328 ex->cone[ct][coff + 18 * i + 10] = DM_POLYTOPE_QUADRILATERAL; 329 ex->cone[ct][coff + 18 * i + 11] = 1; 330 ex->cone[ct][coff + 18 * i + 12] = 1; 331 ex->cone[ct][coff + 18 * i + 13] = i; 332 ex->cone[ct][coff + 18 * i + 14] = DM_POLYTOPE_QUADRILATERAL; 333 ex->cone[ct][coff + 18 * i + 15] = 1; 334 ex->cone[ct][coff + 18 * i + 16] = 2; 335 ex->cone[ct][coff + 18 * i + 17] = i; 336 ex->ornt[ct][ooff + 5 * i + 0] = -2; 337 ex->ornt[ct][ooff + 5 * i + 1] = 0; 338 ex->ornt[ct][ooff + 5 * i + 2] = 0; 339 ex->ornt[ct][ooff + 5 * i + 3] = 0; 340 ex->ornt[ct][ooff + 5 * i + 4] = 0; 341 } 342 } 343 PetscFunctionReturn(PETSC_SUCCESS); 344 } 345 346 /* DM_POLYTOPE_QUADRILATERAL produces 347 Nl+1 quads, or Nl quads periodically and 348 Nl hexes/tensor hexes 349 */ 350 static PetscErrorCode DMPlexTransformExtrudeSetUp_Quadrilateral(DMPlexTransform_Extrude *ex, PetscInt Nl) 351 { 352 const DMPolytopeType ct = DM_POLYTOPE_QUADRILATERAL; 353 const PetscInt Np = ex->periodic ? Nl : Nl + 1; 354 PetscInt Nc, No, coff, ooff; 355 356 PetscFunctionBegin; 357 ex->Nt[ct] = 2; 358 Nc = 16 * Np + 22 * Nl; 359 No = 4 * Np + 6 * Nl; 360 PetscCall(PetscMalloc4(ex->Nt[ct], &ex->target[ct], ex->Nt[ct], &ex->size[ct], Nc, &ex->cone[ct], No, &ex->ornt[ct])); 361 ex->target[ct][0] = DM_POLYTOPE_QUADRILATERAL; 362 ex->target[ct][1] = ex->useTensor ? DM_POLYTOPE_QUAD_PRISM_TENSOR : DM_POLYTOPE_HEXAHEDRON; 363 ex->size[ct][0] = Np; 364 ex->size[ct][1] = Nl; 365 /* cones for quads */ 366 for (PetscInt i = 0; i < Np; ++i) { 367 ex->cone[ct][16 * i + 0] = DM_POLYTOPE_SEGMENT; 368 ex->cone[ct][16 * i + 1] = 1; 369 ex->cone[ct][16 * i + 2] = 0; 370 ex->cone[ct][16 * i + 3] = i; 371 ex->cone[ct][16 * i + 4] = DM_POLYTOPE_SEGMENT; 372 ex->cone[ct][16 * i + 5] = 1; 373 ex->cone[ct][16 * i + 6] = 1; 374 ex->cone[ct][16 * i + 7] = i; 375 ex->cone[ct][16 * i + 8] = DM_POLYTOPE_SEGMENT; 376 ex->cone[ct][16 * i + 9] = 1; 377 ex->cone[ct][16 * i + 10] = 2; 378 ex->cone[ct][16 * i + 11] = i; 379 ex->cone[ct][16 * i + 12] = DM_POLYTOPE_SEGMENT; 380 ex->cone[ct][16 * i + 13] = 1; 381 ex->cone[ct][16 * i + 14] = 3; 382 ex->cone[ct][16 * i + 15] = i; 383 } 384 for (PetscInt i = 0; i < 4 * Np; ++i) ex->ornt[ct][i] = 0; 385 /* cones for hexes/tensor hexes */ 386 coff = 16 * Np; 387 ooff = 4 * Np; 388 for (PetscInt i = 0; i < Nl; ++i) { 389 if (ex->useTensor) { 390 ex->cone[ct][coff + 22 * i + 0] = DM_POLYTOPE_QUADRILATERAL; 391 ex->cone[ct][coff + 22 * i + 1] = 0; 392 ex->cone[ct][coff + 22 * i + 2] = i; 393 ex->cone[ct][coff + 22 * i + 3] = DM_POLYTOPE_QUADRILATERAL; 394 ex->cone[ct][coff + 22 * i + 4] = 0; 395 ex->cone[ct][coff + 22 * i + 5] = (i + 1) % Np; 396 ex->cone[ct][coff + 22 * i + 6] = DM_POLYTOPE_SEG_PRISM_TENSOR; 397 ex->cone[ct][coff + 22 * i + 7] = 1; 398 ex->cone[ct][coff + 22 * i + 8] = 0; 399 ex->cone[ct][coff + 22 * i + 9] = i; 400 ex->cone[ct][coff + 22 * i + 10] = DM_POLYTOPE_SEG_PRISM_TENSOR; 401 ex->cone[ct][coff + 22 * i + 11] = 1; 402 ex->cone[ct][coff + 22 * i + 12] = 1; 403 ex->cone[ct][coff + 22 * i + 13] = i; 404 ex->cone[ct][coff + 22 * i + 14] = DM_POLYTOPE_SEG_PRISM_TENSOR; 405 ex->cone[ct][coff + 22 * i + 15] = 1; 406 ex->cone[ct][coff + 22 * i + 16] = 2; 407 ex->cone[ct][coff + 22 * i + 17] = i; 408 ex->cone[ct][coff + 22 * i + 18] = DM_POLYTOPE_SEG_PRISM_TENSOR; 409 ex->cone[ct][coff + 22 * i + 19] = 1; 410 ex->cone[ct][coff + 22 * i + 20] = 3; 411 ex->cone[ct][coff + 22 * i + 21] = i; 412 ex->ornt[ct][ooff + 6 * i + 0] = 0; 413 ex->ornt[ct][ooff + 6 * i + 1] = 0; 414 ex->ornt[ct][ooff + 6 * i + 2] = 0; 415 ex->ornt[ct][ooff + 6 * i + 3] = 0; 416 ex->ornt[ct][ooff + 6 * i + 4] = 0; 417 ex->ornt[ct][ooff + 6 * i + 5] = 0; 418 } else { 419 ex->cone[ct][coff + 22 * i + 0] = DM_POLYTOPE_QUADRILATERAL; 420 ex->cone[ct][coff + 22 * i + 1] = 0; 421 ex->cone[ct][coff + 22 * i + 2] = i; 422 ex->cone[ct][coff + 22 * i + 3] = DM_POLYTOPE_QUADRILATERAL; 423 ex->cone[ct][coff + 22 * i + 4] = 0; 424 ex->cone[ct][coff + 22 * i + 5] = (i + 1) % Np; 425 ex->cone[ct][coff + 22 * i + 6] = DM_POLYTOPE_QUADRILATERAL; 426 ex->cone[ct][coff + 22 * i + 7] = 1; 427 ex->cone[ct][coff + 22 * i + 8] = 0; 428 ex->cone[ct][coff + 22 * i + 9] = i; 429 ex->cone[ct][coff + 22 * i + 10] = DM_POLYTOPE_QUADRILATERAL; 430 ex->cone[ct][coff + 22 * i + 11] = 1; 431 ex->cone[ct][coff + 22 * i + 12] = 2; 432 ex->cone[ct][coff + 22 * i + 13] = i; 433 ex->cone[ct][coff + 22 * i + 14] = DM_POLYTOPE_QUADRILATERAL; 434 ex->cone[ct][coff + 22 * i + 15] = 1; 435 ex->cone[ct][coff + 22 * i + 16] = 1; 436 ex->cone[ct][coff + 22 * i + 17] = i; 437 ex->cone[ct][coff + 22 * i + 18] = DM_POLYTOPE_QUADRILATERAL; 438 ex->cone[ct][coff + 22 * i + 19] = 1; 439 ex->cone[ct][coff + 22 * i + 20] = 3; 440 ex->cone[ct][coff + 22 * i + 21] = i; 441 ex->ornt[ct][ooff + 6 * i + 0] = -2; 442 ex->ornt[ct][ooff + 6 * i + 1] = 0; 443 ex->ornt[ct][ooff + 6 * i + 2] = 0; 444 ex->ornt[ct][ooff + 6 * i + 3] = 0; 445 ex->ornt[ct][ooff + 6 * i + 4] = 0; 446 ex->ornt[ct][ooff + 6 * i + 5] = 1; 447 } 448 } 449 PetscFunctionReturn(PETSC_SUCCESS); 450 } 451 452 /* 453 The refine types for extrusion are: 454 455 ct: For any normally extruded point 456 ct + 100: For any point which should just return itself 457 */ 458 static PetscErrorCode DMPlexTransformSetUp_Extrude(DMPlexTransform tr) 459 { 460 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 461 DM dm; 462 DMLabel active; 463 PetscInt Nl = ex->layers, l, ict; 464 465 PetscFunctionBegin; 466 PetscCall(DMPlexTransformExtrudeComputeExtrusionDim(tr)); 467 PetscCall(DMPlexTransformGetDM(tr, &dm)); 468 PetscCall(DMPlexTransformGetActive(tr, &active)); 469 if (active) { 470 DMLabel celltype; 471 PetscInt pStart, pEnd, p; 472 473 PetscCall(DMPlexGetCellTypeLabel(dm, &celltype)); 474 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "Refine Type", &tr->trType)); 475 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 476 for (p = pStart; p < pEnd; ++p) { 477 PetscInt ct, val; 478 479 PetscCall(DMLabelGetValue(celltype, p, &ct)); 480 PetscCall(DMLabelGetValue(active, p, &val)); 481 if (val < 0) { 482 PetscCall(DMLabelSetValue(tr->trType, p, ct + 100)); 483 } else { 484 PetscCall(DMLabelSetValue(tr->trType, p, ct)); 485 } 486 } 487 } 488 PetscCall(PetscMalloc5(DM_NUM_POLYTOPES, &ex->Nt, DM_NUM_POLYTOPES, &ex->target, DM_NUM_POLYTOPES, &ex->size, DM_NUM_POLYTOPES, &ex->cone, DM_NUM_POLYTOPES, &ex->ornt)); 489 for (ict = 0; ict < DM_NUM_POLYTOPES; ++ict) { 490 ex->Nt[ict] = -1; 491 ex->target[ict] = NULL; 492 ex->size[ict] = NULL; 493 ex->cone[ict] = NULL; 494 ex->ornt[ict] = NULL; 495 } 496 PetscCall(DMPlexTransformExtrudeSetUp_Point(ex, Nl)); 497 PetscCall(DMPlexTransformExtrudeSetUp_Segment(ex, Nl)); 498 PetscCall(DMPlexTransformExtrudeSetUp_Triangle(ex, Nl)); 499 PetscCall(DMPlexTransformExtrudeSetUp_Quadrilateral(ex, Nl)); 500 /* Layers positions */ 501 if (!ex->Nth) { 502 if (ex->symmetric) 503 for (l = 0; l <= ex->layers; ++l) ex->layerPos[l] = (ex->thickness * l) / ex->layers - ex->thickness / 2; 504 else 505 for (l = 0; l <= ex->layers; ++l) ex->layerPos[l] = (ex->thickness * l) / ex->layers; 506 } else { 507 ex->thickness = 0.; 508 ex->layerPos[0] = 0.; 509 for (l = 0; l < ex->layers; ++l) { 510 const PetscReal t = ex->thicknesses[PetscMin(l, ex->Nth - 1)]; 511 ex->layerPos[l + 1] = ex->layerPos[l] + t; 512 ex->thickness += t; 513 } 514 if (ex->symmetric) 515 for (l = 0; l <= ex->layers; ++l) ex->layerPos[l] -= ex->thickness / 2.; 516 } 517 518 // Need this to determine face sharing 519 PetscMPIInt size; 520 521 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 522 if (size > 1) { 523 PetscSF sf; 524 PetscInt Nr; 525 526 PetscCall(DMGetPointSF(dm, &sf)); 527 PetscCall(PetscSFGetGraph(sf, &Nr, NULL, NULL, NULL)); 528 if (Nr >= 0) { 529 PetscCall(PetscSFComputeDegreeBegin(sf, &ex->degree)); 530 PetscCall(PetscSFComputeDegreeEnd(sf, &ex->degree)); 531 } 532 } 533 PetscFunctionReturn(PETSC_SUCCESS); 534 } 535 536 static PetscErrorCode DMPlexTransformDestroy_Extrude(DMPlexTransform tr) 537 { 538 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 539 PetscInt ct; 540 541 PetscFunctionBegin; 542 if (ex->target) { 543 for (ct = 0; ct < DM_NUM_POLYTOPES; ++ct) PetscCall(PetscFree4(ex->target[ct], ex->size[ct], ex->cone[ct], ex->ornt[ct])); 544 } 545 PetscCall(PetscFree5(ex->Nt, ex->target, ex->size, ex->cone, ex->ornt)); 546 PetscCall(PetscFree(ex->layerPos)); 547 PetscCall(PetscFree(ex)); 548 PetscFunctionReturn(PETSC_SUCCESS); 549 } 550 551 static PetscErrorCode DMPlexTransformGetSubcellOrientation_Extrude(DMPlexTransform tr, DMPolytopeType sct, PetscInt sp, PetscInt so, DMPolytopeType tct, PetscInt r, PetscInt o, PetscInt *rnew, PetscInt *onew) 552 { 553 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 554 DMLabel trType = tr->trType; 555 PetscInt rt; 556 557 PetscFunctionBeginHot; 558 *rnew = r; 559 *onew = DMPolytopeTypeComposeOrientation(tct, o, so); 560 if (!so) PetscFunctionReturn(PETSC_SUCCESS); 561 if (trType) { 562 PetscCall(DMLabelGetValue(tr->trType, sp, &rt)); 563 if (rt >= 100) PetscFunctionReturn(PETSC_SUCCESS); 564 } 565 if (ex->useTensor) { 566 switch (sct) { 567 case DM_POLYTOPE_POINT: 568 break; 569 case DM_POLYTOPE_SEGMENT: 570 switch (tct) { 571 case DM_POLYTOPE_SEGMENT: 572 break; 573 case DM_POLYTOPE_SEG_PRISM_TENSOR: 574 *onew = DMPolytopeTypeComposeOrientation(tct, o, so ? -1 : 0); 575 break; 576 default: 577 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell type %s is not produced by %s", DMPolytopeTypes[tct], DMPolytopeTypes[sct]); 578 } 579 break; 580 // We need to handle identity extrusions from volumes (TET, HEX, etc) when boundary faces are being extruded 581 case DM_POLYTOPE_TRIANGLE: 582 break; 583 case DM_POLYTOPE_QUADRILATERAL: 584 break; 585 default: 586 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported cell type %s", DMPolytopeTypes[sct]); 587 } 588 } else { 589 switch (sct) { 590 case DM_POLYTOPE_POINT: 591 break; 592 case DM_POLYTOPE_SEGMENT: 593 switch (tct) { 594 case DM_POLYTOPE_SEGMENT: 595 break; 596 case DM_POLYTOPE_QUADRILATERAL: 597 *onew = DMPolytopeTypeComposeOrientation(tct, o, so ? -3 : 0); 598 break; 599 default: 600 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell type %s is not produced by %s", DMPolytopeTypes[tct], DMPolytopeTypes[sct]); 601 } 602 break; 603 // We need to handle identity extrusions from volumes (TET, HEX, etc) when boundary faces are being extruded 604 case DM_POLYTOPE_TRIANGLE: 605 break; 606 case DM_POLYTOPE_QUADRILATERAL: 607 break; 608 default: 609 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported cell type %s", DMPolytopeTypes[sct]); 610 } 611 } 612 PetscFunctionReturn(PETSC_SUCCESS); 613 } 614 615 static PetscErrorCode DMPlexTransformCellTransform_Extrude(DMPlexTransform tr, DMPolytopeType source, PetscInt p, PetscInt *rt, PetscInt *Nt, DMPolytopeType *target[], PetscInt *size[], PetscInt *cone[], PetscInt *ornt[]) 616 { 617 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 618 DMLabel trType = tr->trType; 619 PetscBool ignore = PETSC_FALSE, identity = PETSC_FALSE; 620 PetscInt val = 0; 621 622 PetscFunctionBegin; 623 if (trType) { 624 PetscCall(DMLabelGetValue(trType, p, &val)); 625 identity = val >= 100 ? PETSC_TRUE : PETSC_FALSE; 626 } else { 627 ignore = ex->Nt[source] < 0 ? PETSC_TRUE : PETSC_FALSE; 628 } 629 if (rt) *rt = val; 630 if (ignore) { 631 /* Ignore cells that cannot be extruded */ 632 *Nt = 0; 633 *target = NULL; 634 *size = NULL; 635 *cone = NULL; 636 *ornt = NULL; 637 } else if (identity) { 638 PetscCall(DMPlexTransformCellTransformIdentity(tr, source, p, NULL, Nt, target, size, cone, ornt)); 639 } else { 640 *Nt = ex->Nt[source]; 641 *target = ex->target[source]; 642 *size = ex->size[source]; 643 *cone = ex->cone[source]; 644 *ornt = ex->ornt[source]; 645 } 646 PetscFunctionReturn(PETSC_SUCCESS); 647 } 648 649 /* Computes new vertex along normal */ 650 static PetscErrorCode DMPlexTransformMapCoordinates_Extrude(DMPlexTransform tr, DMPolytopeType pct, DMPolytopeType ct, PetscInt p, PetscInt r, PetscInt Nv, PetscInt dE, const PetscScalar in[], PetscScalar out[]) 651 { 652 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 653 DM dm; 654 DMLabel active; 655 PetscReal ones2[2] = {0., 1.}, ones3[3] = {0., 0., 1.}; 656 PetscReal normal[3] = {0., 0., 0.}, norm; 657 PetscBool computeNormal; 658 PetscInt dim, dEx = ex->cdimEx, cStart, cEnd; 659 660 PetscFunctionBeginHot; 661 PetscCheck(pct == DM_POLYTOPE_POINT, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for parent point type %s", DMPolytopeTypes[pct]); 662 PetscCheck(ct == DM_POLYTOPE_POINT, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not for refined point type %s", DMPolytopeTypes[ct]); 663 PetscCheck(Nv == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Vertices should be produced from a single vertex, not %" PetscInt_FMT, Nv); 664 PetscCheck(dE == ex->cdim, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Coordinate dim %" PetscInt_FMT " != %" PetscInt_FMT " original dimension", dE, ex->cdim); 665 PetscCheck(dEx <= 3, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate dimension for extruded mesh %" PetscInt_FMT " must not exceed 3", dEx); 666 667 PetscCall(DMPlexTransformGetDM(tr, &dm)); 668 PetscCall(DMGetDimension(dm, &dim)); 669 PetscCall(DMPlexTransformGetActive(tr, &active)); 670 computeNormal = dim != ex->cdim && !ex->useNormal ? PETSC_TRUE : PETSC_FALSE; 671 if (computeNormal) { // Average all normals in the star of p 672 PetscInt *star = NULL; 673 PetscInt starSize; 674 675 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 676 PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_FALSE, &starSize, &star)); 677 for (PetscInt st = 0; st < starSize * 2; st += 2) { 678 if ((star[st] >= cStart) && (star[st] < cEnd)) { 679 PetscReal cnormal[3] = {0, 0, 0}; 680 681 PetscCall(DMPlexComputeCellGeometryFVM(dm, star[st], NULL, NULL, cnormal)); 682 for (PetscInt d = 0; d < dEx; ++d) normal[d] += cnormal[d]; 683 } 684 } 685 PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_FALSE, &starSize, &star)); 686 } else if (ex->useNormal) { 687 for (PetscInt d = 0; d < dEx; ++d) normal[d] = ex->normal[d]; 688 } else if (active) { // Average all normals in star of p which are active faces 689 PetscSF sf; 690 const PetscInt *leaves; 691 PetscInt *star = NULL; 692 PetscInt Nl, starSize, pStart, pEnd; 693 694 PetscCall(DMGetPointSF(dm, &sf)); 695 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 696 PetscCall(DMPlexGetDepthStratum(dm, ex->cdimEx - 1, &pStart, &pEnd)); 697 PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_FALSE, &starSize, &star)); 698 for (PetscInt st = 0; st < starSize * 2; st += 2) { 699 const PetscInt face = star[st]; 700 if ((face >= pStart) && (face < pEnd)) { 701 PetscReal cnormal[3] = {0, 0, 0}; 702 const PetscInt *supp; 703 PetscInt suppSize, floc = -1; 704 PetscBool shared; 705 706 PetscCall(DMPlexComputeCellGeometryFVM(dm, face, NULL, NULL, cnormal)); 707 PetscCall(DMPlexGetSupportSize(dm, face, &suppSize)); 708 PetscCall(DMPlexGetSupport(dm, face, &supp)); 709 // Only use external faces, so I can get the orientation from any cell 710 if (leaves) PetscCall(PetscFindInt(face, Nl, leaves, &floc)); 711 shared = floc >= 0 || (ex->degree && ex->degree[face]) ? PETSC_TRUE : PETSC_FALSE; 712 if (suppSize == 1 && !shared) { 713 const PetscInt *cone, *ornt; 714 PetscInt coneSize, c; 715 716 PetscCall(DMPlexGetConeSize(dm, supp[0], &coneSize)); 717 PetscCall(DMPlexGetCone(dm, supp[0], &cone)); 718 PetscCall(DMPlexGetConeOrientation(dm, supp[0], &ornt)); 719 for (c = 0; c < coneSize; ++c) 720 if (cone[c] == face) break; 721 PetscCheck(c < coneSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Asymmetry in cone/support"); 722 if (ornt[c] < 0) 723 for (PetscInt d = 0; d < dEx; ++d) cnormal[d] *= -1.; 724 for (PetscInt d = 0; d < dEx; ++d) normal[d] += cnormal[d]; 725 } 726 } 727 } 728 PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_FALSE, &starSize, &star)); 729 } else if (ex->cdimEx == 2) { 730 for (PetscInt d = 0; d < dEx; ++d) normal[d] = ones2[d]; 731 } else if (ex->cdimEx == 3) { 732 for (PetscInt d = 0; d < dEx; ++d) normal[d] = ones3[d]; 733 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unable to determine normal for extrusion"); 734 if (ex->normalFunc) { 735 PetscScalar n[3]; 736 PetscReal x[3], dot; 737 738 for (PetscInt d = 0; d < ex->cdim; ++d) x[d] = PetscRealPart(in[d]); 739 PetscCall((*ex->normalFunc)(ex->cdim, 0., x, r, n, NULL)); 740 dot = 0.; 741 for (PetscInt d = 0; d < dEx; d++) dot += PetscRealPart(n[d]) * normal[d]; 742 for (PetscInt d = 0; d < dEx; ++d) normal[d] = PetscSign(dot) * PetscRealPart(n[d]); 743 } 744 norm = 0.0; 745 for (PetscInt d = 0; d < dEx; ++d) norm += PetscSqr(normal[d]); 746 for (PetscInt d = 0; d < dEx; ++d) normal[d] *= norm == 0.0 ? 1.0 : 1. / PetscSqrtReal(norm); 747 for (PetscInt d = 0; d < dEx; ++d) out[d] = normal[d] * ex->layerPos[r]; 748 for (PetscInt d = 0; d < ex->cdim; ++d) out[d] += in[d]; 749 PetscFunctionReturn(PETSC_SUCCESS); 750 } 751 752 static PetscErrorCode DMPlexTransformInitialize_Extrude(DMPlexTransform tr) 753 { 754 PetscFunctionBegin; 755 tr->ops->view = DMPlexTransformView_Extrude; 756 tr->ops->setfromoptions = DMPlexTransformSetFromOptions_Extrude; 757 tr->ops->setup = DMPlexTransformSetUp_Extrude; 758 tr->ops->destroy = DMPlexTransformDestroy_Extrude; 759 tr->ops->setdimensions = DMPlexTransformSetDimensions_Extrude; 760 tr->ops->celltransform = DMPlexTransformCellTransform_Extrude; 761 tr->ops->getsubcellorientation = DMPlexTransformGetSubcellOrientation_Extrude; 762 tr->ops->mapcoordinates = DMPlexTransformMapCoordinates_Extrude; 763 PetscFunctionReturn(PETSC_SUCCESS); 764 } 765 766 PETSC_EXTERN PetscErrorCode DMPlexTransformCreate_Extrude(DMPlexTransform tr) 767 { 768 DMPlexTransform_Extrude *ex; 769 DM dm; 770 PetscInt dim; 771 772 PetscFunctionBegin; 773 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 774 PetscCall(PetscNew(&ex)); 775 tr->data = ex; 776 ex->thickness = 1.; 777 ex->useTensor = PETSC_TRUE; 778 ex->symmetric = PETSC_FALSE; 779 ex->periodic = PETSC_FALSE; 780 ex->useNormal = PETSC_FALSE; 781 ex->layerPos = NULL; 782 PetscCall(DMPlexTransformGetDM(tr, &dm)); 783 PetscCall(DMGetDimension(dm, &dim)); 784 PetscCall(DMGetCoordinateDim(dm, &ex->cdim)); 785 PetscCall(DMPlexTransformExtrudeSetLayers(tr, 1)); 786 PetscCall(DMPlexTransformInitialize_Extrude(tr)); 787 PetscFunctionReturn(PETSC_SUCCESS); 788 } 789 790 /*@ 791 DMPlexTransformExtrudeGetLayers - Get the number of extruded layers. 792 793 Not Collective 794 795 Input Parameter: 796 . tr - The `DMPlexTransform` 797 798 Output Parameter: 799 . layers - The number of layers 800 801 Level: intermediate 802 803 .seealso: `DMPlexTransform`, `DMPlexTransformExtrudeSetLayers()` 804 @*/ 805 PetscErrorCode DMPlexTransformExtrudeGetLayers(DMPlexTransform tr, PetscInt *layers) 806 { 807 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 808 809 PetscFunctionBegin; 810 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 811 PetscAssertPointer(layers, 2); 812 *layers = ex->layers; 813 PetscFunctionReturn(PETSC_SUCCESS); 814 } 815 816 /*@ 817 DMPlexTransformExtrudeSetLayers - Set the number of extruded layers. 818 819 Not Collective 820 821 Input Parameters: 822 + tr - The `DMPlexTransform` 823 - layers - The number of layers 824 825 Level: intermediate 826 827 .seealso: `DMPlexTransform`, `DMPlexTransformExtrudeGetLayers()` 828 @*/ 829 PetscErrorCode DMPlexTransformExtrudeSetLayers(DMPlexTransform tr, PetscInt layers) 830 { 831 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 832 833 PetscFunctionBegin; 834 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 835 ex->layers = layers; 836 PetscCall(PetscFree(ex->layerPos)); 837 PetscCall(PetscCalloc1(ex->layers + 1, &ex->layerPos)); 838 PetscFunctionReturn(PETSC_SUCCESS); 839 } 840 841 /*@ 842 DMPlexTransformExtrudeGetThickness - Get the total thickness of the layers 843 844 Not Collective 845 846 Input Parameter: 847 . tr - The `DMPlexTransform` 848 849 Output Parameter: 850 . thickness - The total thickness of the layers 851 852 Level: intermediate 853 854 .seealso: `DMPlexTransform`, `DMPlexTransformExtrudeSetThickness()` 855 @*/ 856 PetscErrorCode DMPlexTransformExtrudeGetThickness(DMPlexTransform tr, PetscReal *thickness) 857 { 858 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 859 860 PetscFunctionBegin; 861 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 862 PetscAssertPointer(thickness, 2); 863 *thickness = ex->thickness; 864 PetscFunctionReturn(PETSC_SUCCESS); 865 } 866 867 /*@ 868 DMPlexTransformExtrudeSetThickness - Set the total thickness of the layers 869 870 Not Collective 871 872 Input Parameters: 873 + tr - The `DMPlexTransform` 874 - thickness - The total thickness of the layers 875 876 Level: intermediate 877 878 .seealso: `DMPlexTransform`, `DMPlexTransformExtrudeGetThickness()` 879 @*/ 880 PetscErrorCode DMPlexTransformExtrudeSetThickness(DMPlexTransform tr, PetscReal thickness) 881 { 882 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 883 884 PetscFunctionBegin; 885 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 886 PetscCheck(thickness > 0., PetscObjectComm((PetscObject)tr), PETSC_ERR_ARG_OUTOFRANGE, "Height of layers %g must be positive", (double)thickness); 887 ex->thickness = thickness; 888 PetscFunctionReturn(PETSC_SUCCESS); 889 } 890 891 /*@ 892 DMPlexTransformExtrudeGetTensor - Get the flag to use tensor cells 893 894 Not Collective 895 896 Input Parameter: 897 . tr - The `DMPlexTransform` 898 899 Output Parameter: 900 . useTensor - The flag to use tensor cells 901 902 Note: 903 This flag determines the orientation behavior of the created points. 904 905 For example, if tensor is `PETSC_TRUE`, then 906 .vb 907 DM_POLYTOPE_POINT_PRISM_TENSOR is made instead of DM_POLYTOPE_SEGMENT, 908 DM_POLYTOPE_SEG_PRISM_TENSOR instead of DM_POLYTOPE_QUADRILATERAL, 909 DM_POLYTOPE_TRI_PRISM_TENSOR instead of DM_POLYTOPE_TRI_PRISM, and 910 DM_POLYTOPE_QUAD_PRISM_TENSOR instead of DM_POLYTOPE_HEXAHEDRON. 911 .ve 912 913 Level: intermediate 914 915 .seealso: `DMPlexTransform`, `DMPlexTransformExtrudeSetTensor()` 916 @*/ 917 PetscErrorCode DMPlexTransformExtrudeGetTensor(DMPlexTransform tr, PetscBool *useTensor) 918 { 919 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 920 921 PetscFunctionBegin; 922 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 923 PetscAssertPointer(useTensor, 2); 924 *useTensor = ex->useTensor; 925 PetscFunctionReturn(PETSC_SUCCESS); 926 } 927 928 /*@ 929 DMPlexTransformExtrudeSetTensor - Set the flag to use tensor cells 930 931 Not Collective 932 933 Input Parameters: 934 + tr - The `DMPlexTransform` 935 - useTensor - The flag for tensor cells 936 937 Note: 938 This flag determines the orientation behavior of the created points 939 For example, if tensor is `PETSC_TRUE`, then 940 .vb 941 DM_POLYTOPE_POINT_PRISM_TENSOR is made instead of DM_POLYTOPE_SEGMENT, 942 DM_POLYTOPE_SEG_PRISM_TENSOR instead of DM_POLYTOPE_QUADRILATERAL, 943 DM_POLYTOPE_TRI_PRISM_TENSOR instead of DM_POLYTOPE_TRI_PRISM, and 944 DM_POLYTOPE_QUAD_PRISM_TENSOR instead of DM_POLYTOPE_HEXAHEDRON. 945 .ve 946 947 Level: intermediate 948 949 .seealso: `DMPlexTransform`, `DMPlexTransformExtrudeGetTensor()` 950 @*/ 951 PetscErrorCode DMPlexTransformExtrudeSetTensor(DMPlexTransform tr, PetscBool useTensor) 952 { 953 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 954 955 PetscFunctionBegin; 956 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 957 ex->useTensor = useTensor; 958 PetscFunctionReturn(PETSC_SUCCESS); 959 } 960 961 /*@ 962 DMPlexTransformExtrudeGetSymmetric - Get the flag to extrude symmetrically from the initial surface 963 964 Not Collective 965 966 Input Parameter: 967 . tr - The `DMPlexTransform` 968 969 Output Parameter: 970 . symmetric - The flag to extrude symmetrically 971 972 Level: intermediate 973 974 .seealso: `DMPlexTransform`, `DMPlexTransformExtrudeSetSymmetric()`, `DMPlexTransformExtrudeGetPeriodic()` 975 @*/ 976 PetscErrorCode DMPlexTransformExtrudeGetSymmetric(DMPlexTransform tr, PetscBool *symmetric) 977 { 978 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 979 980 PetscFunctionBegin; 981 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 982 PetscAssertPointer(symmetric, 2); 983 *symmetric = ex->symmetric; 984 PetscFunctionReturn(PETSC_SUCCESS); 985 } 986 987 /*@ 988 DMPlexTransformExtrudeSetSymmetric - Set the flag to extrude symmetrically from the initial surface 989 990 Not Collective 991 992 Input Parameters: 993 + tr - The `DMPlexTransform` 994 - symmetric - The flag to extrude symmetrically 995 996 Level: intermediate 997 998 .seealso: `DMPlexTransform`, `DMPlexTransformExtrudeGetSymmetric()`, `DMPlexTransformExtrudeSetPeriodic()` 999 @*/ 1000 PetscErrorCode DMPlexTransformExtrudeSetSymmetric(DMPlexTransform tr, PetscBool symmetric) 1001 { 1002 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 1003 1004 PetscFunctionBegin; 1005 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 1006 ex->symmetric = symmetric; 1007 PetscFunctionReturn(PETSC_SUCCESS); 1008 } 1009 1010 /*@ 1011 DMPlexTransformExtrudeGetPeriodic - Get the flag to extrude periodically from the initial surface 1012 1013 Not Collective 1014 1015 Input Parameter: 1016 . tr - The `DMPlexTransform` 1017 1018 Output Parameter: 1019 . periodic - The flag to extrude periodically 1020 1021 Level: intermediate 1022 1023 .seealso: `DMPlexTransform`, `DMPlexTransformExtrudeSetPeriodic()`, `DMPlexTransformExtrudeGetSymmetric()` 1024 @*/ 1025 PetscErrorCode DMPlexTransformExtrudeGetPeriodic(DMPlexTransform tr, PetscBool *periodic) 1026 { 1027 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 1028 1029 PetscFunctionBegin; 1030 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 1031 PetscAssertPointer(periodic, 2); 1032 *periodic = ex->periodic; 1033 PetscFunctionReturn(PETSC_SUCCESS); 1034 } 1035 1036 /*@ 1037 DMPlexTransformExtrudeSetPeriodic - Set the flag to extrude periodically from the initial surface 1038 1039 Not Collective 1040 1041 Input Parameters: 1042 + tr - The `DMPlexTransform` 1043 - periodic - The flag to extrude periodically 1044 1045 Level: intermediate 1046 1047 .seealso: `DMPlexTransform`, `DMPlexTransformExtrudeGetPeriodic()`, `DMPlexTransformExtrudeSetSymmetric()` 1048 @*/ 1049 PetscErrorCode DMPlexTransformExtrudeSetPeriodic(DMPlexTransform tr, PetscBool periodic) 1050 { 1051 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 1052 1053 PetscFunctionBegin; 1054 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 1055 ex->periodic = periodic; 1056 PetscFunctionReturn(PETSC_SUCCESS); 1057 } 1058 1059 /*@ 1060 DMPlexTransformExtrudeGetNormal - Get the extrusion normal vector 1061 1062 Not Collective 1063 1064 Input Parameter: 1065 . tr - The `DMPlexTransform` 1066 1067 Output Parameter: 1068 . normal - The extrusion direction 1069 1070 Note: 1071 The user passes in an array, which is filled by the library. 1072 1073 Level: intermediate 1074 1075 .seealso: `DMPlexTransform`, `DMPlexTransformExtrudeSetNormal()` 1076 @*/ 1077 PetscErrorCode DMPlexTransformExtrudeGetNormal(DMPlexTransform tr, PetscReal normal[]) 1078 { 1079 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 1080 PetscInt d; 1081 1082 PetscFunctionBegin; 1083 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 1084 if (ex->useNormal) { 1085 for (d = 0; d < ex->cdimEx; ++d) normal[d] = ex->normal[d]; 1086 } else { 1087 for (d = 0; d < ex->cdimEx; ++d) normal[d] = 0.; 1088 } 1089 PetscFunctionReturn(PETSC_SUCCESS); 1090 } 1091 1092 /*@ 1093 DMPlexTransformExtrudeSetNormal - Set the extrusion normal 1094 1095 Not Collective 1096 1097 Input Parameters: 1098 + tr - The `DMPlexTransform` 1099 - normal - The extrusion direction 1100 1101 Level: intermediate 1102 1103 .seealso: `DMPlexTransform`, `DMPlexTransformExtrudeGetNormal()` 1104 @*/ 1105 PetscErrorCode DMPlexTransformExtrudeSetNormal(DMPlexTransform tr, const PetscReal normal[]) 1106 { 1107 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 1108 PetscInt d; 1109 1110 PetscFunctionBegin; 1111 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 1112 ex->useNormal = PETSC_TRUE; 1113 for (d = 0; d < ex->cdimEx; ++d) ex->normal[d] = normal[d]; 1114 PetscFunctionReturn(PETSC_SUCCESS); 1115 } 1116 1117 /*@C 1118 DMPlexTransformExtrudeSetNormalFunction - Set a function to determine the extrusion normal 1119 1120 Not Collective 1121 1122 Input Parameters: 1123 + tr - The `DMPlexTransform` 1124 - normalFunc - A function determining the extrusion direction, see `PetscSimplePointFn` for the calling sequence 1125 1126 Level: intermediate 1127 1128 .seealso: `DMPlexTransform`, `DMPlexTransformExtrudeGetNormal()`, `PetscSimplePointFn` 1129 @*/ 1130 PetscErrorCode DMPlexTransformExtrudeSetNormalFunction(DMPlexTransform tr, PetscSimplePointFn *normalFunc) 1131 { 1132 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 1133 1134 PetscFunctionBegin; 1135 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 1136 ex->normalFunc = normalFunc; 1137 PetscFunctionReturn(PETSC_SUCCESS); 1138 } 1139 1140 /*@ 1141 DMPlexTransformExtrudeSetThicknesses - Set the thickness of each layer 1142 1143 Not Collective 1144 1145 Input Parameters: 1146 + tr - The `DMPlexTransform` 1147 . Nth - The number of thicknesses 1148 - thicknesses - The array of thicknesses 1149 1150 Level: intermediate 1151 1152 .seealso: `DMPlexTransform`, `DMPlexTransformExtrudeSetThickness()`, `DMPlexTransformExtrudeGetThickness()` 1153 @*/ 1154 PetscErrorCode DMPlexTransformExtrudeSetThicknesses(DMPlexTransform tr, PetscInt Nth, const PetscReal thicknesses[]) 1155 { 1156 DMPlexTransform_Extrude *ex = (DMPlexTransform_Extrude *)tr->data; 1157 PetscInt t; 1158 1159 PetscFunctionBegin; 1160 PetscValidHeaderSpecific(tr, DMPLEXTRANSFORM_CLASSID, 1); 1161 PetscCheck(Nth > 0, PetscObjectComm((PetscObject)tr), PETSC_ERR_ARG_OUTOFRANGE, "Number of thicknesses %" PetscInt_FMT " must be positive", Nth); 1162 ex->Nth = PetscMin(Nth, ex->layers); 1163 PetscCall(PetscFree(ex->thicknesses)); 1164 PetscCall(PetscMalloc1(ex->Nth, &ex->thicknesses)); 1165 for (t = 0; t < ex->Nth; ++t) { 1166 PetscCheck(thicknesses[t] > 0., PetscObjectComm((PetscObject)tr), PETSC_ERR_ARG_OUTOFRANGE, "Thickness %g of layer %" PetscInt_FMT " must be positive", (double)thicknesses[t], t); 1167 ex->thicknesses[t] = thicknesses[t]; 1168 } 1169 PetscFunctionReturn(PETSC_SUCCESS); 1170 } 1171