1 static char help[] = "Spectral element access patterns with Plex\n\n"; 2 3 #include <petscdmplex.h> 4 5 typedef struct { 6 PetscInt Nf; /* Number of fields */ 7 PetscInt *Nc; /* Number of components per field */ 8 PetscInt *k; /* Spectral order per field */ 9 } AppCtx; 10 11 static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options) 12 { 13 PetscInt len; 14 PetscBool flg; 15 PetscErrorCode ierr; 16 17 PetscFunctionBeginUser; 18 options->Nf = 0; 19 options->Nc = NULL; 20 options->k = NULL; 21 22 ierr = PetscOptionsBegin(comm, "", "SEM Problem Options", "DMPLEX");PetscCall(ierr); 23 PetscCall(PetscOptionsBoundedInt("-num_fields", "The number of fields", "ex6.c", options->Nf, &options->Nf, NULL,0)); 24 if (options->Nf) { 25 len = options->Nf; 26 PetscCall(PetscMalloc1(len, &options->Nc)); 27 PetscCall(PetscOptionsIntArray("-num_components", "The number of components per field", "ex6.c", options->Nc, &len, &flg)); 28 PetscCheck(!flg || !(len != options->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Length of components array is %d should be %d", len, options->Nf); 29 len = options->Nf; 30 PetscCall(PetscMalloc1(len, &options->k)); 31 PetscCall(PetscOptionsIntArray("-order", "The spectral order per field", "ex6.c", options->k, &len, &flg)); 32 PetscCheck(!flg || !(len != options->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Length of order array is %d should be %d", len, options->Nf); 33 } 34 ierr = PetscOptionsEnd();PetscCall(ierr); 35 PetscFunctionReturn(0); 36 } 37 38 static PetscErrorCode LoadData2D(DM dm, PetscInt Ni, PetscInt Nj, PetscInt clSize, Vec u, AppCtx *user) 39 { 40 PetscInt i, j, f, c; 41 PetscScalar *closure; 42 43 PetscFunctionBeginUser; 44 PetscCall(PetscMalloc1(clSize,&closure)); 45 for (j = 0; j < Nj; ++j) { 46 for (i = 0; i < Ni; ++i) { 47 PetscInt ki, kj, o = 0; 48 PetscCall(PetscArrayzero(closure,clSize)); 49 50 for (f = 0; f < user->Nf; ++f) { 51 PetscInt ioff = i*user->k[f], joff = j*user->k[f]; 52 53 for (kj = 0; kj <= user->k[f]; ++kj) { 54 for (ki = 0; ki <= user->k[f]; ++ki) { 55 for (c = 0; c < user->Nc[f]; ++c) { 56 closure[o++] = ((kj + joff)*(Ni*user->k[f]+1) + ki + ioff)*user->Nc[f]+c; 57 } 58 } 59 } 60 } 61 PetscCall(DMPlexVecSetClosure(dm, NULL, u, j*Ni+i, closure, INSERT_VALUES)); 62 } 63 } 64 PetscCall(PetscFree(closure)); 65 PetscFunctionReturn(0); 66 } 67 68 static PetscErrorCode LoadData3D(DM dm, PetscInt Ni, PetscInt Nj, PetscInt Nk, PetscInt clSize, Vec u, AppCtx *user) 69 { 70 PetscInt i, j, k, f, c; 71 PetscScalar *closure; 72 73 PetscFunctionBeginUser; 74 PetscCall(PetscMalloc1(clSize,&closure)); 75 for (k = 0; k < Nk; ++k) { 76 for (j = 0; j < Nj; ++j) { 77 for (i = 0; i < Ni; ++i) { 78 PetscInt ki, kj, kk, o = 0; 79 PetscCall(PetscArrayzero(closure,clSize)); 80 81 for (f = 0; f < user->Nf; ++f) { 82 PetscInt ioff = i*user->k[f], joff = j*user->k[f], koff = k*user->k[f]; 83 84 for (kk = 0; kk <= user->k[f]; ++kk) { 85 for (kj = 0; kj <= user->k[f]; ++kj) { 86 for (ki = 0; ki <= user->k[f]; ++ki) { 87 for (c = 0; c < user->Nc[f]; ++c) { 88 closure[o++] = (((kk + koff)*(Nj*user->k[f]+1) + kj + joff)*(Ni*user->k[f]+1) + ki + ioff)*user->Nc[f]+c; 89 } 90 } 91 } 92 } 93 } 94 PetscCall(DMPlexVecSetClosure(dm, NULL, u, (k*Nj+j)*Ni+i, closure, INSERT_VALUES)); 95 } 96 } 97 } 98 PetscCall(PetscFree(closure)); 99 PetscFunctionReturn(0); 100 } 101 102 static PetscErrorCode CheckPoint(DM dm, Vec u, PetscInt point, AppCtx *user) 103 { 104 PetscSection s; 105 PetscScalar *a; 106 const PetscScalar *array; 107 PetscInt dof, d; 108 109 PetscFunctionBeginUser; 110 PetscCall(DMGetLocalSection(dm, &s)); 111 PetscCall(VecGetArrayRead(u, &array)); 112 PetscCall(DMPlexPointLocalRead(dm, point, array, &a)); 113 PetscCall(PetscSectionGetDof(s, point, &dof)); 114 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Point %D: ", point)); 115 for (d = 0; d < dof; ++d) { 116 if (d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 117 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%2.0f", (double) PetscRealPart(a[d]))); 118 } 119 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 120 PetscCall(VecRestoreArrayRead(u, &array)); 121 PetscFunctionReturn(0); 122 } 123 124 static PetscErrorCode ReadData2D(DM dm, Vec u, AppCtx *user) 125 { 126 PetscInt cStart, cEnd, cell; 127 128 PetscFunctionBeginUser; 129 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 130 for (cell = cStart; cell < cEnd; ++cell) { 131 PetscScalar *closure = NULL; 132 PetscInt closureSize, ki, kj, f, c, foff = 0; 133 134 PetscCall(DMPlexVecGetClosure(dm, NULL, u, cell, &closureSize, &closure)); 135 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %D\n", cell)); 136 for (f = 0; f < user->Nf; ++f) { 137 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Field %D\n", f)); 138 for (kj = user->k[f]; kj >= 0; --kj) { 139 for (ki = 0; ki <= user->k[f]; ++ki) { 140 if (ki > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, " ")); 141 for (c = 0; c < user->Nc[f]; ++c) { 142 if (c > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ",")); 143 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%2.0f", (double) PetscRealPart(closure[(kj*(user->k[f]+1) + ki)*user->Nc[f]+c + foff]))); 144 } 145 } 146 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 147 } 148 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n\n")); 149 foff += PetscSqr(user->k[f]+1); 150 } 151 PetscCall(DMPlexVecRestoreClosure(dm, NULL, u, cell, &closureSize, &closure)); 152 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n\n")); 153 } 154 PetscFunctionReturn(0); 155 } 156 157 static PetscErrorCode ReadData3D(DM dm, Vec u, AppCtx *user) 158 { 159 PetscInt cStart, cEnd, cell; 160 161 PetscFunctionBeginUser; 162 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 163 for (cell = cStart; cell < cEnd; ++cell) { 164 PetscScalar *closure = NULL; 165 PetscInt closureSize, ki, kj, kk, f, c, foff = 0; 166 167 PetscCall(DMPlexVecGetClosure(dm, NULL, u, cell, &closureSize, &closure)); 168 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %D\n", cell)); 169 for (f = 0; f < user->Nf; ++f) { 170 PetscCall(PetscPrintf(PETSC_COMM_SELF, " Field %D\n", f)); 171 for (kk = user->k[f]; kk >= 0; --kk) { 172 for (kj = user->k[f]; kj >= 0; --kj) { 173 for (ki = 0; ki <= user->k[f]; ++ki) { 174 if (ki > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, " ")); 175 for (c = 0; c < user->Nc[f]; ++c) { 176 if (c > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ",")); 177 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%2.0f", (double) PetscRealPart(closure[((kk*(user->k[f]+1) + kj)*(user->k[f]+1) + ki)*user->Nc[f]+c + foff]))); 178 } 179 } 180 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 181 } 182 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n")); 183 } 184 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n\n")); 185 foff += PetscSqr(user->k[f]+1); 186 } 187 PetscCall(DMPlexVecRestoreClosure(dm, NULL, u, cell, &closureSize, &closure)); 188 PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n\n")); 189 } 190 PetscFunctionReturn(0); 191 } 192 193 static PetscErrorCode SetSymmetries(DM dm, PetscSection s, AppCtx *user) 194 { 195 PetscInt dim, f, o, i, j, k, c, d; 196 DMLabel depthLabel; 197 198 PetscFunctionBegin; 199 PetscCall(DMGetDimension(dm, &dim)); 200 PetscCall(DMGetLabel(dm,"depth",&depthLabel)); 201 for (f = 0; f < user->Nf; f++) { 202 PetscSectionSym sym; 203 204 if (user->k[f] < 3) continue; /* No symmetries needed for order < 3, because no cell, facet, edge or vertex has more than one node */ 205 PetscCall(PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)s),depthLabel,&sym)); 206 207 for (d = 0; d <= dim; d++) { 208 if (d == 1) { 209 PetscInt numDof = user->k[f] - 1; 210 PetscInt numComp = user->Nc[f]; 211 PetscInt minOrnt = -1; 212 PetscInt maxOrnt = 1; 213 PetscInt **perms; 214 215 PetscCall(PetscCalloc1(maxOrnt - minOrnt,&perms)); 216 for (o = minOrnt; o < maxOrnt; o++) { 217 PetscInt *perm; 218 219 if (!o) { /* identity */ 220 perms[o - minOrnt] = NULL; 221 } else { 222 PetscCall(PetscMalloc1(numDof * numComp, &perm)); 223 for (i = numDof - 1, k = 0; i >= 0; i--) { 224 for (j = 0; j < numComp; j++, k++) perm[k] = i * numComp + j; 225 } 226 perms[o - minOrnt] = perm; 227 } 228 } 229 PetscCall(PetscSectionSymLabelSetStratum(sym,d,numDof*numComp,minOrnt,maxOrnt,PETSC_OWN_POINTER,(const PetscInt **) perms,NULL)); 230 } else if (d == 2) { 231 PetscInt perEdge = user->k[f] - 1; 232 PetscInt numDof = perEdge * perEdge; 233 PetscInt numComp = user->Nc[f]; 234 PetscInt minOrnt = -4; 235 PetscInt maxOrnt = 4; 236 PetscInt **perms; 237 238 PetscCall(PetscCalloc1(maxOrnt-minOrnt,&perms)); 239 for (o = minOrnt; o < maxOrnt; o++) { 240 PetscInt *perm; 241 242 if (!o) continue; /* identity */ 243 PetscCall(PetscMalloc1(numDof * numComp, &perm)); 244 /* We want to perm[k] to list which *localArray* position the *sectionArray* position k should go to for the given orientation*/ 245 switch (o) { 246 case 0: 247 break; /* identity */ 248 case -2: /* flip along (-1,-1)--( 1, 1), which swaps edges 0 and 3 and edges 1 and 2. This swaps the i and j variables */ 249 for (i = 0, k = 0; i < perEdge; i++) { 250 for (j = 0; j < perEdge; j++, k++) { 251 for (c = 0; c < numComp; c++) { 252 perm[k * numComp + c] = (perEdge * j + i) * numComp + c; 253 } 254 } 255 } 256 break; 257 case -1: /* flip along (-1, 0)--( 1, 0), which swaps edges 0 and 2. This reverses the i variable */ 258 for (i = 0, k = 0; i < perEdge; i++) { 259 for (j = 0; j < perEdge; j++, k++) { 260 for (c = 0; c < numComp; c++) { 261 perm[k * numComp + c] = (perEdge * (perEdge - 1 - i) + j) * numComp + c; 262 } 263 } 264 } 265 break; 266 case -4: /* flip along ( 1,-1)--(-1, 1), which swaps edges 0 and 1 and edges 2 and 3. This swaps the i and j variables and reverse both */ 267 for (i = 0, k = 0; i < perEdge; i++) { 268 for (j = 0; j < perEdge; j++, k++) { 269 for (c = 0; c < numComp; c++) { 270 perm[k * numComp + c] = (perEdge * (perEdge - 1 - j) + (perEdge - 1 - i)) * numComp + c; 271 } 272 } 273 } 274 break; 275 case -3: /* flip along ( 0,-1)--( 0, 1), which swaps edges 3 and 1. This reverses the j variable */ 276 for (i = 0, k = 0; i < perEdge; i++) { 277 for (j = 0; j < perEdge; j++, k++) { 278 for (c = 0; c < numComp; c++) { 279 perm[k * numComp + c] = (perEdge * i + (perEdge - 1 - j)) * numComp + c; 280 } 281 } 282 } 283 break; 284 case 1: /* rotate section edge 1 to local edge 0. This swaps the i and j variables and then reverses the j variable */ 285 for (i = 0, k = 0; i < perEdge; i++) { 286 for (j = 0; j < perEdge; j++, k++) { 287 for (c = 0; c < numComp; c++) { 288 perm[k * numComp + c] = (perEdge * (perEdge - 1 - j) + i) * numComp + c; 289 } 290 } 291 } 292 break; 293 case 2: /* rotate section edge 2 to local edge 0. This reverse both i and j variables */ 294 for (i = 0, k = 0; i < perEdge; i++) { 295 for (j = 0; j < perEdge; j++, k++) { 296 for (c = 0; c < numComp; c++) { 297 perm[k * numComp + c] = (perEdge * (perEdge - 1 - i) + (perEdge - 1 - j)) * numComp + c; 298 } 299 } 300 } 301 break; 302 case 3: /* rotate section edge 3 to local edge 0. This swaps the i and j variables and then reverses the i variable */ 303 for (i = 0, k = 0; i < perEdge; i++) { 304 for (j = 0; j < perEdge; j++, k++) { 305 for (c = 0; c < numComp; c++) { 306 perm[k * numComp + c] = (perEdge * j + (perEdge - 1 - i)) * numComp + c; 307 } 308 } 309 } 310 break; 311 default: 312 break; 313 } 314 perms[o - minOrnt] = perm; 315 } 316 PetscCall(PetscSectionSymLabelSetStratum(sym,d,numDof*numComp,minOrnt,maxOrnt,PETSC_OWN_POINTER,(const PetscInt **) perms,NULL)); 317 } 318 } 319 PetscCall(PetscSectionSetFieldSym(s,f,sym)); 320 PetscCall(PetscSectionSymDestroy(&sym)); 321 } 322 PetscCall(PetscSectionViewFromOptions(s,NULL,"-section_with_sym_view")); 323 PetscFunctionReturn(0); 324 } 325 326 int main(int argc, char **argv) 327 { 328 DM dm; 329 PetscSection s; 330 Vec u; 331 AppCtx user; 332 PetscInt dim, size = 0, f; 333 334 PetscCall(PetscInitialize(&argc, &argv, NULL,help)); 335 PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user)); 336 PetscCall(DMCreate(PETSC_COMM_WORLD, &dm)); 337 PetscCall(DMSetType(dm, DMPLEX)); 338 PetscCall(DMSetFromOptions(dm)); 339 PetscCall(DMViewFromOptions(dm, NULL, "-dm_view")); 340 PetscCall(DMGetDimension(dm, &dim)); 341 /* Create a section for SEM order k */ 342 { 343 PetscInt *numDof, d; 344 345 PetscCall(PetscMalloc1(user.Nf*(dim+1), &numDof)); 346 for (f = 0; f < user.Nf; ++f) { 347 for (d = 0; d <= dim; ++d) numDof[f*(dim+1)+d] = PetscPowInt(user.k[f]-1, d)*user.Nc[f]; 348 size += PetscPowInt(user.k[f]+1, d)*user.Nc[f]; 349 } 350 PetscCall(DMSetNumFields(dm, user.Nf)); 351 PetscCall(DMPlexCreateSection(dm, NULL, user.Nc, numDof, 0, NULL, NULL, NULL, NULL, &s)); 352 PetscCall(SetSymmetries(dm, s, &user)); 353 PetscCall(PetscFree(numDof)); 354 } 355 PetscCall(DMSetLocalSection(dm, s)); 356 /* Create spectral ordering and load in data */ 357 PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL)); 358 PetscCall(DMGetLocalVector(dm, &u)); 359 switch (dim) { 360 case 2: PetscCall(LoadData2D(dm, 2, 2, size, u, &user));break; 361 case 3: PetscCall(LoadData3D(dm, 2, 2, 2, size, u, &user));break; 362 } 363 /* Remove ordering and check some values */ 364 PetscCall(PetscSectionSetClosurePermutation(s, (PetscObject) dm, dim, NULL)); 365 switch (dim) { 366 case 2: 367 PetscCall(CheckPoint(dm, u, 0, &user)); 368 PetscCall(CheckPoint(dm, u, 13, &user)); 369 PetscCall(CheckPoint(dm, u, 15, &user)); 370 PetscCall(CheckPoint(dm, u, 19, &user)); 371 break; 372 case 3: 373 PetscCall(CheckPoint(dm, u, 0, &user)); 374 PetscCall(CheckPoint(dm, u, 13, &user)); 375 PetscCall(CheckPoint(dm, u, 15, &user)); 376 PetscCall(CheckPoint(dm, u, 19, &user)); 377 break; 378 } 379 /* Recreate spectral ordering and read out data */ 380 PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, s)); 381 switch (dim) { 382 case 2: PetscCall(ReadData2D(dm, u, &user));break; 383 case 3: PetscCall(ReadData3D(dm, u, &user));break; 384 } 385 PetscCall(DMRestoreLocalVector(dm, &u)); 386 PetscCall(PetscSectionDestroy(&s)); 387 PetscCall(DMDestroy(&dm)); 388 PetscCall(PetscFree(user.Nc)); 389 PetscCall(PetscFree(user.k)); 390 PetscCall(PetscFinalize()); 391 return 0; 392 } 393 394 /*TEST 395 396 # Spectral ordering 2D 0-5 397 testset: 398 args: -dm_plex_simplex 0 -dm_plex_box_faces 2,2 399 400 test: 401 suffix: 0 402 args: -num_fields 1 -num_components 1 -order 2 403 test: 404 suffix: 1 405 args: -num_fields 1 -num_components 1 -order 3 406 test: 407 suffix: 2 408 args: -num_fields 1 -num_components 1 -order 5 409 test: 410 suffix: 3 411 args: -num_fields 1 -num_components 2 -order 2 412 test: 413 suffix: 4 414 args: -num_fields 2 -num_components 1,1 -order 2,2 415 test: 416 suffix: 5 417 args: -num_fields 2 -num_components 1,2 -order 2,3 418 419 # Spectral ordering 3D 6-11 420 testset: 421 args: -dm_plex_dim 3 -dm_plex_simplex 0 -dm_plex_box_faces 2,2,2 422 423 test: 424 suffix: 6 425 args: -num_fields 1 -num_components 1 -order 2 426 test: 427 suffix: 7 428 args: -num_fields 1 -num_components 1 -order 3 429 test: 430 suffix: 8 431 args: -num_fields 1 -num_components 1 -order 5 432 test: 433 suffix: 9 434 args: -num_fields 1 -num_components 2 -order 2 435 test: 436 suffix: 10 437 args: -num_fields 2 -num_components 1,1 -order 2,2 438 test: 439 suffix: 11 440 args: -num_fields 2 -num_components 1,2 -order 2,3 441 442 TEST*/ 443