1 /* 2 This file contains routines for basic section object implementation. 3 */ 4 5 #include <petsc/private/sectionimpl.h> /*I "petscsection.h" I*/ 6 #include <petscsf.h> 7 8 PetscClassId PETSC_SECTION_CLASSID; 9 10 /*@ 11 PetscSectionCreate - Allocates a `PetscSection` and sets the map contents to the default. 12 13 Collective 14 15 Input Parameters: 16 + comm - the MPI communicator 17 - s - pointer to the section 18 19 Level: beginner 20 21 Notes: 22 Typical calling sequence 23 .vb 24 PetscSectionCreate(MPI_Comm,PetscSection *);! 25 PetscSectionSetNumFields(PetscSection, numFields); 26 PetscSectionSetChart(PetscSection,low,high); 27 PetscSectionSetDof(PetscSection,point,numdof); 28 PetscSectionSetUp(PetscSection); 29 PetscSectionGetOffset(PetscSection,point,PetscInt *); 30 PetscSectionDestroy(PetscSection); 31 .ve 32 33 The `PetscSection` object and methods are intended to be used in the PETSc `Vec` and `Mat` implementations. The indices returned by the `PetscSection` are appropriate for the kind of `Vec` it is associated with. For example, if the vector being indexed is a local vector, we call the section a local section. If the section indexes a global vector, we call it a global section. For parallel vectors, like global vectors, we use negative indices to indicate dofs owned by other processes. 34 35 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSetChart()`, `PetscSectionDestroy()`, `PetscSectionCreateGlobalSection()` 36 @*/ 37 PetscErrorCode PetscSectionCreate(MPI_Comm comm, PetscSection *s) 38 { 39 PetscFunctionBegin; 40 PetscAssertPointer(s, 2); 41 PetscCall(ISInitializePackage()); 42 43 PetscCall(PetscHeaderCreate(*s, PETSC_SECTION_CLASSID, "PetscSection", "Section", "IS", comm, PetscSectionDestroy, PetscSectionView)); 44 (*s)->pStart = -1; 45 (*s)->pEnd = -1; 46 (*s)->perm = NULL; 47 (*s)->pointMajor = PETSC_TRUE; 48 (*s)->includesConstraints = PETSC_TRUE; 49 (*s)->atlasDof = NULL; 50 (*s)->atlasOff = NULL; 51 (*s)->bc = NULL; 52 (*s)->bcIndices = NULL; 53 (*s)->setup = PETSC_FALSE; 54 (*s)->numFields = 0; 55 (*s)->fieldNames = NULL; 56 (*s)->field = NULL; 57 (*s)->useFieldOff = PETSC_FALSE; 58 (*s)->compNames = NULL; 59 (*s)->clObj = NULL; 60 (*s)->clHash = NULL; 61 (*s)->clSection = NULL; 62 (*s)->clPoints = NULL; 63 PetscCall(PetscSectionInvalidateMaxDof_Internal(*s)); 64 PetscFunctionReturn(PETSC_SUCCESS); 65 } 66 67 /*@ 68 PetscSectionCopy - Creates a shallow (if possible) copy of the `PetscSection` 69 70 Collective 71 72 Input Parameter: 73 . section - the `PetscSection` 74 75 Output Parameter: 76 . newSection - the copy 77 78 Level: intermediate 79 80 Developer Notes: 81 What exactly does shallow mean in this context? 82 83 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()` 84 @*/ 85 PetscErrorCode PetscSectionCopy(PetscSection section, PetscSection newSection) 86 { 87 PetscFunctionBegin; 88 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 89 PetscValidHeaderSpecific(newSection, PETSC_SECTION_CLASSID, 2); 90 PetscCall(PetscSectionCopy_Internal(section, newSection, NULL)); 91 PetscFunctionReturn(PETSC_SUCCESS); 92 } 93 94 PetscErrorCode PetscSectionCopy_Internal(PetscSection section, PetscSection newSection, PetscBT constrained_dofs) 95 { 96 PetscSectionSym sym; 97 IS perm; 98 PetscInt numFields, f, c, pStart, pEnd, p; 99 100 PetscFunctionBegin; 101 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 102 PetscValidHeaderSpecific(newSection, PETSC_SECTION_CLASSID, 2); 103 PetscCall(PetscSectionReset(newSection)); 104 PetscCall(PetscSectionGetNumFields(section, &numFields)); 105 if (numFields) PetscCall(PetscSectionSetNumFields(newSection, numFields)); 106 for (f = 0; f < numFields; ++f) { 107 const char *fieldName = NULL, *compName = NULL; 108 PetscInt numComp = 0; 109 110 PetscCall(PetscSectionGetFieldName(section, f, &fieldName)); 111 PetscCall(PetscSectionSetFieldName(newSection, f, fieldName)); 112 PetscCall(PetscSectionGetFieldComponents(section, f, &numComp)); 113 PetscCall(PetscSectionSetFieldComponents(newSection, f, numComp)); 114 for (c = 0; c < numComp; ++c) { 115 PetscCall(PetscSectionGetComponentName(section, f, c, &compName)); 116 PetscCall(PetscSectionSetComponentName(newSection, f, c, compName)); 117 } 118 PetscCall(PetscSectionGetFieldSym(section, f, &sym)); 119 PetscCall(PetscSectionSetFieldSym(newSection, f, sym)); 120 } 121 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 122 PetscCall(PetscSectionSetChart(newSection, pStart, pEnd)); 123 PetscCall(PetscSectionGetPermutation(section, &perm)); 124 PetscCall(PetscSectionSetPermutation(newSection, perm)); 125 PetscCall(PetscSectionGetSym(section, &sym)); 126 PetscCall(PetscSectionSetSym(newSection, sym)); 127 for (p = pStart; p < pEnd; ++p) { 128 PetscInt dof, cdof, fcdof = 0; 129 PetscBool force_constrained = (PetscBool)(constrained_dofs && PetscBTLookup(constrained_dofs, p - pStart)); 130 131 PetscCall(PetscSectionGetDof(section, p, &dof)); 132 PetscCall(PetscSectionSetDof(newSection, p, dof)); 133 if (force_constrained) cdof = dof; 134 else PetscCall(PetscSectionGetConstraintDof(section, p, &cdof)); 135 if (cdof) PetscCall(PetscSectionSetConstraintDof(newSection, p, cdof)); 136 for (f = 0; f < numFields; ++f) { 137 PetscCall(PetscSectionGetFieldDof(section, p, f, &dof)); 138 PetscCall(PetscSectionSetFieldDof(newSection, p, f, dof)); 139 if (cdof) { 140 if (force_constrained) fcdof = dof; 141 else PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof)); 142 if (fcdof) PetscCall(PetscSectionSetFieldConstraintDof(newSection, p, f, fcdof)); 143 } 144 } 145 } 146 PetscCall(PetscSectionSetUp(newSection)); 147 for (p = pStart; p < pEnd; ++p) { 148 PetscInt off, cdof, fcdof = 0; 149 const PetscInt *cInd; 150 PetscBool force_constrained = (PetscBool)(constrained_dofs && PetscBTLookup(constrained_dofs, p - pStart)); 151 152 /* Must set offsets in case they do not agree with the prefix sums */ 153 PetscCall(PetscSectionGetOffset(section, p, &off)); 154 PetscCall(PetscSectionSetOffset(newSection, p, off)); 155 PetscCall(PetscSectionGetConstraintDof(newSection, p, &cdof)); 156 if (cdof) { 157 if (force_constrained) cInd = NULL; 158 else PetscCall(PetscSectionGetConstraintIndices(section, p, &cInd)); 159 PetscCall(PetscSectionSetConstraintIndices(newSection, p, cInd)); 160 for (f = 0; f < numFields; ++f) { 161 PetscCall(PetscSectionGetFieldOffset(section, p, f, &off)); 162 PetscCall(PetscSectionSetFieldOffset(newSection, p, f, off)); 163 PetscCall(PetscSectionGetFieldConstraintDof(newSection, p, f, &fcdof)); 164 if (fcdof) { 165 if (force_constrained) cInd = NULL; 166 else PetscCall(PetscSectionGetFieldConstraintIndices(section, p, f, &cInd)); 167 PetscCall(PetscSectionSetFieldConstraintIndices(newSection, p, f, cInd)); 168 } 169 } 170 } 171 } 172 PetscFunctionReturn(PETSC_SUCCESS); 173 } 174 175 /*@ 176 PetscSectionClone - Creates a shallow (if possible) copy of the `PetscSection` 177 178 Collective 179 180 Input Parameter: 181 . section - the `PetscSection` 182 183 Output Parameter: 184 . newSection - the copy 185 186 Level: beginner 187 188 Developer Notes: 189 With standard PETSc terminology this should be called `PetscSectionDuplicate()` 190 191 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`, `PetscSectionCopy()` 192 @*/ 193 PetscErrorCode PetscSectionClone(PetscSection section, PetscSection *newSection) 194 { 195 PetscFunctionBegin; 196 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 197 PetscAssertPointer(newSection, 2); 198 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)section), newSection)); 199 PetscCall(PetscSectionCopy(section, *newSection)); 200 PetscFunctionReturn(PETSC_SUCCESS); 201 } 202 203 /*@ 204 PetscSectionSetFromOptions - sets parameters in a `PetscSection` from the options database 205 206 Collective 207 208 Input Parameter: 209 . s - the `PetscSection` 210 211 Options Database Key: 212 . -petscsection_point_major - `PETSC_TRUE` for point-major order 213 214 Level: intermediate 215 216 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()` 217 @*/ 218 PetscErrorCode PetscSectionSetFromOptions(PetscSection s) 219 { 220 PetscFunctionBegin; 221 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 222 PetscObjectOptionsBegin((PetscObject)s); 223 PetscCall(PetscOptionsBool("-petscsection_point_major", "The for ordering, either point major or field major", "PetscSectionSetPointMajor", s->pointMajor, &s->pointMajor, NULL)); 224 /* process any options handlers added with PetscObjectAddOptionsHandler() */ 225 PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)s, PetscOptionsObject)); 226 PetscOptionsEnd(); 227 PetscCall(PetscObjectViewFromOptions((PetscObject)s, NULL, "-petscsection_view")); 228 PetscFunctionReturn(PETSC_SUCCESS); 229 } 230 231 /*@ 232 PetscSectionCompare - Compares two sections 233 234 Collective 235 236 Input Parameters: 237 + s1 - the first `PetscSection` 238 - s2 - the second `PetscSection` 239 240 Output Parameter: 241 . congruent - `PETSC_TRUE` if the two sections are congruent, `PETSC_FALSE` otherwise 242 243 Level: intermediate 244 245 Note: 246 Field names are disregarded. 247 248 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionCopy()`, `PetscSectionClone()` 249 @*/ 250 PetscErrorCode PetscSectionCompare(PetscSection s1, PetscSection s2, PetscBool *congruent) 251 { 252 PetscInt pStart, pEnd, nfields, ncdof, nfcdof, p, f, n1, n2; 253 const PetscInt *idx1, *idx2; 254 IS perm1, perm2; 255 PetscBool flg; 256 PetscMPIInt mflg; 257 258 PetscFunctionBegin; 259 PetscValidHeaderSpecific(s1, PETSC_SECTION_CLASSID, 1); 260 PetscValidHeaderSpecific(s2, PETSC_SECTION_CLASSID, 2); 261 PetscAssertPointer(congruent, 3); 262 flg = PETSC_FALSE; 263 264 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)s1), PetscObjectComm((PetscObject)s2), &mflg)); 265 if (mflg != MPI_CONGRUENT && mflg != MPI_IDENT) { 266 *congruent = PETSC_FALSE; 267 PetscFunctionReturn(PETSC_SUCCESS); 268 } 269 270 PetscCall(PetscSectionGetChart(s1, &pStart, &pEnd)); 271 PetscCall(PetscSectionGetChart(s2, &n1, &n2)); 272 if (pStart != n1 || pEnd != n2) goto not_congruent; 273 274 PetscCall(PetscSectionGetPermutation(s1, &perm1)); 275 PetscCall(PetscSectionGetPermutation(s2, &perm2)); 276 if (perm1 && perm2) { 277 PetscCall(ISEqual(perm1, perm2, congruent)); 278 if (!*congruent) goto not_congruent; 279 } else if (perm1 != perm2) goto not_congruent; 280 281 for (p = pStart; p < pEnd; ++p) { 282 PetscCall(PetscSectionGetOffset(s1, p, &n1)); 283 PetscCall(PetscSectionGetOffset(s2, p, &n2)); 284 if (n1 != n2) goto not_congruent; 285 286 PetscCall(PetscSectionGetDof(s1, p, &n1)); 287 PetscCall(PetscSectionGetDof(s2, p, &n2)); 288 if (n1 != n2) goto not_congruent; 289 290 PetscCall(PetscSectionGetConstraintDof(s1, p, &ncdof)); 291 PetscCall(PetscSectionGetConstraintDof(s2, p, &n2)); 292 if (ncdof != n2) goto not_congruent; 293 294 PetscCall(PetscSectionGetConstraintIndices(s1, p, &idx1)); 295 PetscCall(PetscSectionGetConstraintIndices(s2, p, &idx2)); 296 PetscCall(PetscArraycmp(idx1, idx2, ncdof, congruent)); 297 if (!*congruent) goto not_congruent; 298 } 299 300 PetscCall(PetscSectionGetNumFields(s1, &nfields)); 301 PetscCall(PetscSectionGetNumFields(s2, &n2)); 302 if (nfields != n2) goto not_congruent; 303 304 for (f = 0; f < nfields; ++f) { 305 PetscCall(PetscSectionGetFieldComponents(s1, f, &n1)); 306 PetscCall(PetscSectionGetFieldComponents(s2, f, &n2)); 307 if (n1 != n2) goto not_congruent; 308 309 for (p = pStart; p < pEnd; ++p) { 310 PetscCall(PetscSectionGetFieldOffset(s1, p, f, &n1)); 311 PetscCall(PetscSectionGetFieldOffset(s2, p, f, &n2)); 312 if (n1 != n2) goto not_congruent; 313 314 PetscCall(PetscSectionGetFieldDof(s1, p, f, &n1)); 315 PetscCall(PetscSectionGetFieldDof(s2, p, f, &n2)); 316 if (n1 != n2) goto not_congruent; 317 318 PetscCall(PetscSectionGetFieldConstraintDof(s1, p, f, &nfcdof)); 319 PetscCall(PetscSectionGetFieldConstraintDof(s2, p, f, &n2)); 320 if (nfcdof != n2) goto not_congruent; 321 322 PetscCall(PetscSectionGetFieldConstraintIndices(s1, p, f, &idx1)); 323 PetscCall(PetscSectionGetFieldConstraintIndices(s2, p, f, &idx2)); 324 PetscCall(PetscArraycmp(idx1, idx2, nfcdof, congruent)); 325 if (!*congruent) goto not_congruent; 326 } 327 } 328 329 flg = PETSC_TRUE; 330 not_congruent: 331 PetscCallMPI(MPIU_Allreduce(&flg, congruent, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)s1))); 332 PetscFunctionReturn(PETSC_SUCCESS); 333 } 334 335 /*@ 336 PetscSectionGetNumFields - Returns the number of fields in a `PetscSection`, or 0 if no fields were defined. 337 338 Not Collective 339 340 Input Parameter: 341 . s - the `PetscSection` 342 343 Output Parameter: 344 . numFields - the number of fields defined, or 0 if none were defined 345 346 Level: intermediate 347 348 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSetNumFields()` 349 @*/ 350 PetscErrorCode PetscSectionGetNumFields(PetscSection s, PetscInt *numFields) 351 { 352 PetscFunctionBegin; 353 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 354 PetscAssertPointer(numFields, 2); 355 *numFields = s->numFields; 356 PetscFunctionReturn(PETSC_SUCCESS); 357 } 358 359 /*@ 360 PetscSectionSetNumFields - Sets the number of fields in a `PetscSection` 361 362 Not Collective 363 364 Input Parameters: 365 + s - the `PetscSection` 366 - numFields - the number of fields 367 368 Level: intermediate 369 370 Notes: 371 Calling this destroys all the information in the `PetscSection` including the chart. 372 373 You must call `PetscSectionSetChart()` after calling this. 374 375 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetNumFields()`, `PetscSectionSetChart()`, `PetscSectionReset()` 376 @*/ 377 PetscErrorCode PetscSectionSetNumFields(PetscSection s, PetscInt numFields) 378 { 379 PetscInt f; 380 381 PetscFunctionBegin; 382 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 383 PetscCheck(numFields > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "The number of fields %" PetscInt_FMT " must be positive", numFields); 384 PetscCall(PetscSectionReset(s)); 385 386 s->numFields = numFields; 387 PetscCall(PetscMalloc1(s->numFields, &s->numFieldComponents)); 388 PetscCall(PetscMalloc1(s->numFields, &s->fieldNames)); 389 PetscCall(PetscMalloc1(s->numFields, &s->compNames)); 390 PetscCall(PetscMalloc1(s->numFields, &s->field)); 391 for (f = 0; f < s->numFields; ++f) { 392 char name[64]; 393 394 s->numFieldComponents[f] = 1; 395 396 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), &s->field[f])); 397 PetscCall(PetscSNPrintf(name, 64, "Field_%" PetscInt_FMT, f)); 398 PetscCall(PetscStrallocpy(name, &s->fieldNames[f])); 399 PetscCall(PetscSNPrintf(name, 64, "Component_0")); 400 PetscCall(PetscMalloc1(s->numFieldComponents[f], &s->compNames[f])); 401 PetscCall(PetscStrallocpy(name, &s->compNames[f][0])); 402 } 403 PetscFunctionReturn(PETSC_SUCCESS); 404 } 405 406 /*@ 407 PetscSectionGetFieldName - Returns the name of a field in the `PetscSection` 408 409 Not Collective 410 411 Input Parameters: 412 + s - the `PetscSection` 413 - field - the field number 414 415 Output Parameter: 416 . fieldName - the field name 417 418 Level: intermediate 419 420 Note: 421 Will error if the field number is out of range 422 423 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSetFieldName()`, `PetscSectionSetNumFields()`, `PetscSectionGetNumFields()` 424 @*/ 425 PetscErrorCode PetscSectionGetFieldName(PetscSection s, PetscInt field, const char *fieldName[]) 426 { 427 PetscFunctionBegin; 428 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 429 PetscAssertPointer(fieldName, 3); 430 PetscSectionCheckValidField(field, s->numFields); 431 *fieldName = s->fieldNames[field]; 432 PetscFunctionReturn(PETSC_SUCCESS); 433 } 434 435 /*@ 436 PetscSectionSetFieldName - Sets the name of a field in the `PetscSection` 437 438 Not Collective 439 440 Input Parameters: 441 + s - the `PetscSection` 442 . field - the field number 443 - fieldName - the field name 444 445 Level: intermediate 446 447 Note: 448 Will error if the field number is out of range 449 450 .seealso: [PetscSection](ch_petscsection), `PetscSectionGetFieldName()`, `PetscSectionSetNumFields()`, `PetscSectionGetNumFields()` 451 @*/ 452 PetscErrorCode PetscSectionSetFieldName(PetscSection s, PetscInt field, const char fieldName[]) 453 { 454 PetscFunctionBegin; 455 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 456 if (fieldName) PetscAssertPointer(fieldName, 3); 457 PetscSectionCheckValidField(field, s->numFields); 458 PetscCall(PetscFree(s->fieldNames[field])); 459 PetscCall(PetscStrallocpy(fieldName, &s->fieldNames[field])); 460 PetscFunctionReturn(PETSC_SUCCESS); 461 } 462 463 /*@ 464 PetscSectionGetComponentName - Gets the name of a field component in the `PetscSection` 465 466 Not Collective 467 468 Input Parameters: 469 + s - the `PetscSection` 470 . field - the field number 471 - comp - the component number 472 473 Output Parameter: 474 . compName - the component name 475 476 Level: intermediate 477 478 Note: 479 Will error if the field or component number do not exist 480 481 Developer Notes: 482 The function name should have Field in it since they are field components. 483 484 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetFieldName()`, `PetscSectionSetNumFields()`, `PetscSectionGetNumFields()`, 485 `PetscSectionSetComponentName()`, `PetscSectionSetFieldName()`, `PetscSectionGetFieldComponents()`, `PetscSectionSetFieldComponents()` 486 @*/ 487 PetscErrorCode PetscSectionGetComponentName(PetscSection s, PetscInt field, PetscInt comp, const char *compName[]) 488 { 489 PetscFunctionBegin; 490 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 491 PetscAssertPointer(compName, 4); 492 PetscSectionCheckValidField(field, s->numFields); 493 PetscSectionCheckValidFieldComponent(comp, s->numFieldComponents[field]); 494 *compName = s->compNames[field][comp]; 495 PetscFunctionReturn(PETSC_SUCCESS); 496 } 497 498 /*@ 499 PetscSectionSetComponentName - Sets the name of a field component in the `PetscSection` 500 501 Not Collective 502 503 Input Parameters: 504 + s - the `PetscSection` 505 . field - the field number 506 . comp - the component number 507 - compName - the component name 508 509 Level: advanced 510 511 Note: 512 Will error if the field or component number do not exist 513 514 Developer Notes: 515 The function name should have Field in it since they are field components. 516 517 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetComponentName()`, `PetscSectionSetNumFields()`, `PetscSectionGetNumFields()`, 518 `PetscSectionSetFieldName()`, `PetscSectionGetFieldComponents()`, `PetscSectionSetFieldComponents()` 519 @*/ 520 PetscErrorCode PetscSectionSetComponentName(PetscSection s, PetscInt field, PetscInt comp, const char compName[]) 521 { 522 PetscFunctionBegin; 523 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 524 if (compName) PetscAssertPointer(compName, 4); 525 PetscSectionCheckValidField(field, s->numFields); 526 PetscSectionCheckValidFieldComponent(comp, s->numFieldComponents[field]); 527 PetscCall(PetscFree(s->compNames[field][comp])); 528 PetscCall(PetscStrallocpy(compName, &s->compNames[field][comp])); 529 PetscFunctionReturn(PETSC_SUCCESS); 530 } 531 532 /*@ 533 PetscSectionGetFieldComponents - Returns the number of field components for the given field. 534 535 Not Collective 536 537 Input Parameters: 538 + s - the `PetscSection` 539 - field - the field number 540 541 Output Parameter: 542 . numComp - the number of field components 543 544 Level: advanced 545 546 Developer Notes: 547 This function is misnamed. There is a Num in `PetscSectionGetNumFields()` but not in this name 548 549 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSetFieldComponents()`, `PetscSectionGetNumFields()`, 550 `PetscSectionSetComponentName()`, `PetscSectionGetComponentName()` 551 @*/ 552 PetscErrorCode PetscSectionGetFieldComponents(PetscSection s, PetscInt field, PetscInt *numComp) 553 { 554 PetscFunctionBegin; 555 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 556 PetscAssertPointer(numComp, 3); 557 PetscSectionCheckValidField(field, s->numFields); 558 *numComp = s->numFieldComponents[field]; 559 PetscFunctionReturn(PETSC_SUCCESS); 560 } 561 562 /*@ 563 PetscSectionSetFieldComponents - Sets the number of field components for the given field. 564 565 Not Collective 566 567 Input Parameters: 568 + s - the `PetscSection` 569 . field - the field number 570 - numComp - the number of field components 571 572 Level: advanced 573 574 Note: 575 This number can be different than the values set with `PetscSectionSetFieldDof()`. It can be used to indicate the number of 576 components in the field of the underlying physical model which may be different than the number of degrees of freedom needed 577 at a point in a discretization. For example, if in three dimensions the field is velocity, it will have 3 components, u, v, and w but 578 an face based model for velocity (where the velocity normal to the face is stored) there is only 1 dof for each face point. 579 580 The value set with this function are not needed or used in `PetscSectionSetUp()`. 581 582 Developer Notes: 583 This function is misnamed. There is a Num in `PetscSectionSetNumFields()` but not in this name 584 585 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetFieldComponents()`, `PetscSectionSetComponentName()`, 586 `PetscSectionGetComponentName()`, `PetscSectionGetNumFields()` 587 @*/ 588 PetscErrorCode PetscSectionSetFieldComponents(PetscSection s, PetscInt field, PetscInt numComp) 589 { 590 PetscInt c; 591 592 PetscFunctionBegin; 593 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 594 PetscSectionCheckValidField(field, s->numFields); 595 if (s->compNames) { 596 for (c = 0; c < s->numFieldComponents[field]; ++c) PetscCall(PetscFree(s->compNames[field][c])); 597 PetscCall(PetscFree(s->compNames[field])); 598 } 599 600 s->numFieldComponents[field] = numComp; 601 if (numComp) { 602 PetscCall(PetscMalloc1(numComp, &s->compNames[field])); 603 for (c = 0; c < numComp; ++c) { 604 char name[64]; 605 606 PetscCall(PetscSNPrintf(name, 64, "%" PetscInt_FMT, c)); 607 PetscCall(PetscStrallocpy(name, &s->compNames[field][c])); 608 } 609 } 610 PetscFunctionReturn(PETSC_SUCCESS); 611 } 612 613 /*@ 614 PetscSectionGetChart - Returns the range [`pStart`, `pEnd`) in which points (indices) lie for this `PetscSection` on this MPI process 615 616 Not Collective 617 618 Input Parameter: 619 . s - the `PetscSection` 620 621 Output Parameters: 622 + pStart - the first point 623 - pEnd - one past the last point 624 625 Level: intermediate 626 627 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSetChart()`, `PetscSectionCreate()` 628 @*/ 629 PetscErrorCode PetscSectionGetChart(PetscSection s, PetscInt *pStart, PetscInt *pEnd) 630 { 631 PetscFunctionBegin; 632 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 633 if (pStart) *pStart = s->pStart; 634 if (pEnd) *pEnd = s->pEnd; 635 PetscFunctionReturn(PETSC_SUCCESS); 636 } 637 638 /*@ 639 PetscSectionSetChart - Sets the range [`pStart`, `pEnd`) in which points (indices) lie for this `PetscSection` on this MPI process 640 641 Not Collective 642 643 Input Parameters: 644 + s - the `PetscSection` 645 . pStart - the first point 646 - pEnd - one past the last point, `pStart` $ \le $ `pEnd` 647 648 Level: intermediate 649 650 Notes: 651 The charts on different MPI processes may (and often do) overlap 652 653 If you intend to use `PetscSectionSetNumFields()` it must be called before this call. 654 655 The chart for all fields created with `PetscSectionSetNumFields()` is the same as this chart. 656 657 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetChart()`, `PetscSectionCreate()`, `PetscSectionSetNumFields()` 658 @*/ 659 PetscErrorCode PetscSectionSetChart(PetscSection s, PetscInt pStart, PetscInt pEnd) 660 { 661 PetscInt f; 662 663 PetscFunctionBegin; 664 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 665 PetscCheck(pEnd >= pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Chart pEnd %" PetscInt_FMT " cannot be smaller than chart pStart %" PetscInt_FMT, pEnd, pStart); 666 if (pStart == s->pStart && pEnd == s->pEnd) PetscFunctionReturn(PETSC_SUCCESS); 667 /* Cannot Reset() because it destroys field information */ 668 s->setup = PETSC_FALSE; 669 PetscCall(PetscSectionDestroy(&s->bc)); 670 PetscCall(PetscFree(s->bcIndices)); 671 PetscCall(PetscFree2(s->atlasDof, s->atlasOff)); 672 673 s->pStart = pStart; 674 s->pEnd = pEnd; 675 PetscCall(PetscMalloc2(pEnd - pStart, &s->atlasDof, pEnd - pStart, &s->atlasOff)); 676 PetscCall(PetscArrayzero(s->atlasDof, pEnd - pStart)); 677 for (f = 0; f < s->numFields; ++f) PetscCall(PetscSectionSetChart(s->field[f], pStart, pEnd)); 678 PetscFunctionReturn(PETSC_SUCCESS); 679 } 680 681 /*@ 682 PetscSectionGetPermutation - Returns the permutation of [0, `pEnd` - `pStart`) or `NULL` that was set with `PetscSectionSetPermutation()` 683 684 Not Collective 685 686 Input Parameter: 687 . s - the `PetscSection` 688 689 Output Parameter: 690 . perm - The permutation as an `IS` 691 692 Level: intermediate 693 694 .seealso: [](sec_scatter), `IS`, `PetscSection`, `PetscSectionSetPermutation()`, `PetscSectionCreate()` 695 @*/ 696 PetscErrorCode PetscSectionGetPermutation(PetscSection s, IS *perm) 697 { 698 PetscFunctionBegin; 699 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 700 if (perm) { 701 PetscAssertPointer(perm, 2); 702 *perm = s->perm; 703 } 704 PetscFunctionReturn(PETSC_SUCCESS); 705 } 706 707 /*@ 708 PetscSectionSetPermutation - Sets a permutation of the chart for this section, [0, `pEnd` - `pStart`), which determines the order to store the `PetscSection` information 709 710 Not Collective 711 712 Input Parameters: 713 + s - the `PetscSection` 714 - perm - the permutation of points 715 716 Level: intermediate 717 718 Notes: 719 The permutation must be provided before `PetscSectionSetUp()`. 720 721 The data in the `PetscSection` are permuted but the access via `PetscSectionGetFieldOffset()` and `PetscSectionGetOffset()` is not changed 722 723 Compare to `PetscSectionPermute()` 724 725 .seealso: [](sec_scatter), `IS`, `PetscSection`, `PetscSectionSetUp()`, `PetscSectionGetPermutation()`, `PetscSectionPermute()`, `PetscSectionCreate()` 726 @*/ 727 PetscErrorCode PetscSectionSetPermutation(PetscSection s, IS perm) 728 { 729 PetscFunctionBegin; 730 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 731 if (perm) PetscValidHeaderSpecific(perm, IS_CLASSID, 2); 732 PetscCheck(!s->setup, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONGSTATE, "Cannot set a permutation after the section is setup"); 733 if (s->perm != perm) { 734 PetscCall(ISDestroy(&s->perm)); 735 if (perm) { 736 s->perm = perm; 737 PetscCall(PetscObjectReference((PetscObject)s->perm)); 738 } 739 } 740 PetscFunctionReturn(PETSC_SUCCESS); 741 } 742 743 /*@C 744 PetscSectionGetBlockStarts - Returns a table indicating which points start new blocks 745 746 Not Collective, No Fortran Support 747 748 Input Parameter: 749 . s - the `PetscSection` 750 751 Output Parameter: 752 . blockStarts - The `PetscBT` with a 1 for each point that begins a block 753 754 Notes: 755 The table is on [0, `pEnd` - `pStart`). 756 757 This information is used by `DMCreateMatrix()` to create a variable block size description which is set using `MatSetVariableBlockSizes()`. 758 759 Level: intermediate 760 761 .seealso: [](sec_scatter), `IS`, `PetscSection`, `PetscSectionSetBlockStarts()`, `PetscSectionCreate()`, `DMCreateMatrix()`, `MatSetVariableBlockSizes()` 762 @*/ 763 PetscErrorCode PetscSectionGetBlockStarts(PetscSection s, PetscBT *blockStarts) 764 { 765 PetscFunctionBegin; 766 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 767 if (blockStarts) { 768 PetscAssertPointer(blockStarts, 2); 769 *blockStarts = s->blockStarts; 770 } 771 PetscFunctionReturn(PETSC_SUCCESS); 772 } 773 774 /*@C 775 PetscSectionSetBlockStarts - Sets a table indicating which points start new blocks 776 777 Not Collective, No Fortran Support 778 779 Input Parameters: 780 + s - the `PetscSection` 781 - blockStarts - The `PetscBT` with a 1 for each point that begins a block 782 783 Level: intermediate 784 785 Notes: 786 The table is on [0, `pEnd` - `pStart`). PETSc takes ownership of the `PetscBT` when it is passed in and will destroy it. The user should not destroy it. 787 788 This information is used by `DMCreateMatrix()` to create a variable block size description which is set using `MatSetVariableBlockSizes()`. 789 790 .seealso: [](sec_scatter), `IS`, `PetscSection`, `PetscSectionGetBlockStarts()`, `PetscSectionCreate()`, `DMCreateMatrix()`, `MatSetVariableBlockSizes()` 791 @*/ 792 PetscErrorCode PetscSectionSetBlockStarts(PetscSection s, PetscBT blockStarts) 793 { 794 PetscFunctionBegin; 795 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 796 if (s->blockStarts != blockStarts) { 797 PetscCall(PetscBTDestroy(&s->blockStarts)); 798 s->blockStarts = blockStarts; 799 } 800 PetscFunctionReturn(PETSC_SUCCESS); 801 } 802 803 /*@ 804 PetscSectionGetPointMajor - Returns the flag for dof ordering, `PETSC_TRUE` if it is point major, `PETSC_FALSE` if it is field major 805 806 Not Collective 807 808 Input Parameter: 809 . s - the `PetscSection` 810 811 Output Parameter: 812 . pm - the flag for point major ordering 813 814 Level: intermediate 815 816 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSetPointMajor()` 817 @*/ 818 PetscErrorCode PetscSectionGetPointMajor(PetscSection s, PetscBool *pm) 819 { 820 PetscFunctionBegin; 821 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 822 PetscAssertPointer(pm, 2); 823 *pm = s->pointMajor; 824 PetscFunctionReturn(PETSC_SUCCESS); 825 } 826 827 /*@ 828 PetscSectionSetPointMajor - Sets the flag for dof ordering, `PETSC_TRUE` for point major, otherwise it will be field major 829 830 Not Collective 831 832 Input Parameters: 833 + s - the `PetscSection` 834 - pm - the flag for point major ordering 835 836 Level: intermediate 837 838 Note: 839 Field-major order is not recommended unless you are managing the entire problem yourself, since many higher-level functions in PETSc depend on point-major order. 840 841 Point major order means the degrees of freedom are stored as follows 842 .vb 843 all the degrees of freedom for each point are stored contiguously, one point after another (respecting a permutation set with `PetscSectionSetPermutation()`) 844 for each point 845 the degrees of freedom for each field (starting with the unnamed default field) are listed in order by field 846 .ve 847 848 Field major order means the degrees of freedom are stored as follows 849 .vb 850 all degrees of freedom for each field (including the unnamed default field) are stored contiguously, one field after another 851 for each field (started with unnamed default field) 852 the degrees of freedom for each point are listed in order by point (respecting a permutation set with `PetscSectionSetPermutation()`) 853 .ve 854 855 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetPointMajor()`, `PetscSectionSetPermutation()` 856 @*/ 857 PetscErrorCode PetscSectionSetPointMajor(PetscSection s, PetscBool pm) 858 { 859 PetscFunctionBegin; 860 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 861 PetscCheck(!s->setup, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONGSTATE, "Cannot set the dof ordering after the section is setup"); 862 s->pointMajor = pm; 863 PetscFunctionReturn(PETSC_SUCCESS); 864 } 865 866 /*@ 867 PetscSectionGetIncludesConstraints - Returns the flag indicating if constrained dofs were included when computing offsets in the `PetscSection`. 868 The value is set with `PetscSectionSetIncludesConstraints()` 869 870 Not Collective 871 872 Input Parameter: 873 . s - the `PetscSection` 874 875 Output Parameter: 876 . includesConstraints - the flag indicating if constrained dofs were included when computing offsets 877 878 Level: intermediate 879 880 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSetIncludesConstraints()` 881 @*/ 882 PetscErrorCode PetscSectionGetIncludesConstraints(PetscSection s, PetscBool *includesConstraints) 883 { 884 PetscFunctionBegin; 885 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 886 PetscAssertPointer(includesConstraints, 2); 887 *includesConstraints = s->includesConstraints; 888 PetscFunctionReturn(PETSC_SUCCESS); 889 } 890 891 /*@ 892 PetscSectionSetIncludesConstraints - Sets the flag indicating if constrained dofs are to be included when computing offsets 893 894 Not Collective 895 896 Input Parameters: 897 + s - the `PetscSection` 898 - includesConstraints - the flag indicating if constrained dofs are to be included when computing offsets 899 900 Level: intermediate 901 902 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetIncludesConstraints()` 903 @*/ 904 PetscErrorCode PetscSectionSetIncludesConstraints(PetscSection s, PetscBool includesConstraints) 905 { 906 PetscFunctionBegin; 907 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 908 PetscCheck(!s->setup, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONGSTATE, "Cannot set includesConstraints after the section is set up"); 909 s->includesConstraints = includesConstraints; 910 PetscFunctionReturn(PETSC_SUCCESS); 911 } 912 913 /*@ 914 PetscSectionGetDof - Return the total number of degrees of freedom associated with a given point. 915 916 Not Collective 917 918 Input Parameters: 919 + s - the `PetscSection` 920 - point - the point 921 922 Output Parameter: 923 . numDof - the number of dof 924 925 Level: intermediate 926 927 Notes: 928 In a global section, this size will be negative for points not owned by this process. 929 930 This number is for the unnamed default field at the given point plus all degrees of freedom associated with all fields at that point 931 932 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSetDof()`, `PetscSectionCreate()` 933 @*/ 934 PetscErrorCode PetscSectionGetDof(PetscSection s, PetscInt point, PetscInt *numDof) 935 { 936 PetscFunctionBeginHot; 937 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 938 PetscAssertPointer(numDof, 3); 939 PetscAssert(point >= s->pStart && point < s->pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd); 940 *numDof = s->atlasDof[point - s->pStart]; 941 PetscFunctionReturn(PETSC_SUCCESS); 942 } 943 944 /*@ 945 PetscSectionSetDof - Sets the total number of degrees of freedom associated with a given point. 946 947 Not Collective 948 949 Input Parameters: 950 + s - the `PetscSection` 951 . point - the point 952 - numDof - the number of dof, these values may be negative -(dof+1) to indicate they are off process 953 954 Level: intermediate 955 956 Note: 957 This number is for the unnamed default field at the given point plus all degrees of freedom associated with all fields at that point 958 959 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionAddDof()`, `PetscSectionCreate()` 960 @*/ 961 PetscErrorCode PetscSectionSetDof(PetscSection s, PetscInt point, PetscInt numDof) 962 { 963 PetscFunctionBegin; 964 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 965 PetscAssert(point >= s->pStart && point < s->pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd); 966 s->atlasDof[point - s->pStart] = numDof; 967 PetscCall(PetscSectionInvalidateMaxDof_Internal(s)); 968 PetscFunctionReturn(PETSC_SUCCESS); 969 } 970 971 /*@ 972 PetscSectionAddDof - Adds to the total number of degrees of freedom associated with a given point. 973 974 Not Collective 975 976 Input Parameters: 977 + s - the `PetscSection` 978 . point - the point 979 - numDof - the number of additional dof 980 981 Level: intermediate 982 983 Note: 984 This number is for the unnamed default field at the given point plus all degrees of freedom associated with all fields at that point 985 986 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetDof()`, `PetscSectionCreate()` 987 @*/ 988 PetscErrorCode PetscSectionAddDof(PetscSection s, PetscInt point, PetscInt numDof) 989 { 990 PetscFunctionBeginHot; 991 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 992 PetscAssert(point >= s->pStart && point < s->pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd); 993 PetscCheck(numDof >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "numDof %" PetscInt_FMT " should not be negative", numDof); 994 s->atlasDof[point - s->pStart] += numDof; 995 PetscCall(PetscSectionInvalidateMaxDof_Internal(s)); 996 PetscFunctionReturn(PETSC_SUCCESS); 997 } 998 999 /*@ 1000 PetscSectionGetFieldDof - Return the number of degrees of freedom associated with a field on a given point. 1001 1002 Not Collective 1003 1004 Input Parameters: 1005 + s - the `PetscSection` 1006 . point - the point 1007 - field - the field 1008 1009 Output Parameter: 1010 . numDof - the number of dof 1011 1012 Level: intermediate 1013 1014 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSetFieldDof()`, `PetscSectionCreate()` 1015 @*/ 1016 PetscErrorCode PetscSectionGetFieldDof(PetscSection s, PetscInt point, PetscInt field, PetscInt *numDof) 1017 { 1018 PetscFunctionBegin; 1019 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1020 PetscAssertPointer(numDof, 4); 1021 PetscSectionCheckValidField(field, s->numFields); 1022 PetscCall(PetscSectionGetDof(s->field[field], point, numDof)); 1023 PetscFunctionReturn(PETSC_SUCCESS); 1024 } 1025 1026 /*@ 1027 PetscSectionSetFieldDof - Sets the number of degrees of freedom associated with a field on a given point. 1028 1029 Not Collective 1030 1031 Input Parameters: 1032 + s - the `PetscSection` 1033 . point - the point 1034 . field - the field 1035 - numDof - the number of dof, these values may be negative -(dof+1) to indicate they are off process 1036 1037 Level: intermediate 1038 1039 Note: 1040 When setting the number of dof for a field at a point one must also ensure the count of the total number of dof at the point (summed over 1041 the fields and the unnamed default field) is correct by also calling `PetscSectionAddDof()` or `PetscSectionSetDof()` 1042 1043 This is equivalent to 1044 .vb 1045 PetscSection fs; 1046 PetscSectionGetField(s,field,&fs) 1047 PetscSectionSetDof(fs,numDof) 1048 .ve 1049 1050 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetFieldDof()`, `PetscSectionCreate()`, `PetscSectionAddDof()`, `PetscSectionSetDof()` 1051 @*/ 1052 PetscErrorCode PetscSectionSetFieldDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof) 1053 { 1054 PetscFunctionBegin; 1055 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1056 PetscSectionCheckValidField(field, s->numFields); 1057 PetscCall(PetscSectionSetDof(s->field[field], point, numDof)); 1058 PetscFunctionReturn(PETSC_SUCCESS); 1059 } 1060 1061 /*@ 1062 PetscSectionAddFieldDof - Adds a number of degrees of freedom associated with a field on a given point. 1063 1064 Not Collective 1065 1066 Input Parameters: 1067 + s - the `PetscSection` 1068 . point - the point 1069 . field - the field 1070 - numDof - the number of dof 1071 1072 Level: intermediate 1073 1074 Notes: 1075 When adding to the number of dof for a field at a point one must also ensure the count of the total number of dof at the point (summed over 1076 the fields and the unnamed default field) is correct by also calling `PetscSectionAddDof()` or `PetscSectionSetDof()` 1077 1078 This is equivalent to 1079 .vb 1080 PetscSection fs; 1081 PetscSectionGetField(s,field,&fs) 1082 PetscSectionAddDof(fs,numDof) 1083 .ve 1084 1085 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSetFieldDof()`, `PetscSectionGetFieldDof()`, `PetscSectionCreate()` 1086 @*/ 1087 PetscErrorCode PetscSectionAddFieldDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof) 1088 { 1089 PetscFunctionBegin; 1090 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1091 PetscSectionCheckValidField(field, s->numFields); 1092 PetscCall(PetscSectionAddDof(s->field[field], point, numDof)); 1093 PetscFunctionReturn(PETSC_SUCCESS); 1094 } 1095 1096 /*@ 1097 PetscSectionGetConstraintDof - Return the number of constrained degrees of freedom associated with a given point. 1098 1099 Not Collective 1100 1101 Input Parameters: 1102 + s - the `PetscSection` 1103 - point - the point 1104 1105 Output Parameter: 1106 . numDof - the number of dof which are fixed by constraints 1107 1108 Level: intermediate 1109 1110 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetConstraintDof()`, `PetscSectionCreate()` 1111 @*/ 1112 PetscErrorCode PetscSectionGetConstraintDof(PetscSection s, PetscInt point, PetscInt *numDof) 1113 { 1114 PetscFunctionBegin; 1115 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1116 PetscAssertPointer(numDof, 3); 1117 if (s->bc) { 1118 PetscCall(PetscSectionGetDof(s->bc, point, numDof)); 1119 } else *numDof = 0; 1120 PetscFunctionReturn(PETSC_SUCCESS); 1121 } 1122 1123 /*@ 1124 PetscSectionSetConstraintDof - Set the number of constrained degrees of freedom associated with a given point. 1125 1126 Not Collective 1127 1128 Input Parameters: 1129 + s - the `PetscSection` 1130 . point - the point 1131 - numDof - the number of dof which are fixed by constraints 1132 1133 Level: intermediate 1134 1135 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSetDof()`, `PetscSectionGetConstraintDof()`, `PetscSectionCreate()` 1136 @*/ 1137 PetscErrorCode PetscSectionSetConstraintDof(PetscSection s, PetscInt point, PetscInt numDof) 1138 { 1139 PetscFunctionBegin; 1140 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1141 if (numDof) { 1142 PetscCall(PetscSectionCheckConstraints_Private(s)); 1143 PetscCall(PetscSectionSetDof(s->bc, point, numDof)); 1144 } 1145 PetscFunctionReturn(PETSC_SUCCESS); 1146 } 1147 1148 /*@ 1149 PetscSectionAddConstraintDof - Increment the number of constrained degrees of freedom associated with a given point. 1150 1151 Not Collective 1152 1153 Input Parameters: 1154 + s - the `PetscSection` 1155 . point - the point 1156 - numDof - the number of additional dof which are fixed by constraints 1157 1158 Level: intermediate 1159 1160 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionAddDof()`, `PetscSectionGetConstraintDof()`, `PetscSectionCreate()` 1161 @*/ 1162 PetscErrorCode PetscSectionAddConstraintDof(PetscSection s, PetscInt point, PetscInt numDof) 1163 { 1164 PetscFunctionBegin; 1165 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1166 if (numDof) { 1167 PetscCall(PetscSectionCheckConstraints_Private(s)); 1168 PetscCall(PetscSectionAddDof(s->bc, point, numDof)); 1169 } 1170 PetscFunctionReturn(PETSC_SUCCESS); 1171 } 1172 1173 /*@ 1174 PetscSectionGetFieldConstraintDof - Return the number of constrained degrees of freedom associated with a given field on a point. 1175 1176 Not Collective 1177 1178 Input Parameters: 1179 + s - the `PetscSection` 1180 . point - the point 1181 - field - the field 1182 1183 Output Parameter: 1184 . numDof - the number of dof which are fixed by constraints 1185 1186 Level: intermediate 1187 1188 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetFieldConstraintDof()`, `PetscSectionCreate()` 1189 @*/ 1190 PetscErrorCode PetscSectionGetFieldConstraintDof(PetscSection s, PetscInt point, PetscInt field, PetscInt *numDof) 1191 { 1192 PetscFunctionBegin; 1193 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1194 PetscAssertPointer(numDof, 4); 1195 PetscSectionCheckValidField(field, s->numFields); 1196 PetscCall(PetscSectionGetConstraintDof(s->field[field], point, numDof)); 1197 PetscFunctionReturn(PETSC_SUCCESS); 1198 } 1199 1200 /*@ 1201 PetscSectionSetFieldConstraintDof - Set the number of constrained degrees of freedom associated with a given field on a point. 1202 1203 Not Collective 1204 1205 Input Parameters: 1206 + s - the `PetscSection` 1207 . point - the point 1208 . field - the field 1209 - numDof - the number of dof which are fixed by constraints 1210 1211 Level: intermediate 1212 1213 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSetDof()`, `PetscSectionGetFieldConstraintDof()`, `PetscSectionCreate()` 1214 @*/ 1215 PetscErrorCode PetscSectionSetFieldConstraintDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof) 1216 { 1217 PetscFunctionBegin; 1218 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1219 PetscSectionCheckValidField(field, s->numFields); 1220 PetscCall(PetscSectionSetConstraintDof(s->field[field], point, numDof)); 1221 PetscFunctionReturn(PETSC_SUCCESS); 1222 } 1223 1224 /*@ 1225 PetscSectionAddFieldConstraintDof - Increment the number of constrained degrees of freedom associated with a given field on a point. 1226 1227 Not Collective 1228 1229 Input Parameters: 1230 + s - the `PetscSection` 1231 . point - the point 1232 . field - the field 1233 - numDof - the number of additional dof which are fixed by constraints 1234 1235 Level: intermediate 1236 1237 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionAddDof()`, `PetscSectionGetFieldConstraintDof()`, `PetscSectionCreate()` 1238 @*/ 1239 PetscErrorCode PetscSectionAddFieldConstraintDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof) 1240 { 1241 PetscFunctionBegin; 1242 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1243 PetscSectionCheckValidField(field, s->numFields); 1244 PetscCall(PetscSectionAddConstraintDof(s->field[field], point, numDof)); 1245 PetscFunctionReturn(PETSC_SUCCESS); 1246 } 1247 1248 /*@ 1249 PetscSectionSetUpBC - Setup the subsections describing boundary conditions. 1250 1251 Not Collective 1252 1253 Input Parameter: 1254 . s - the `PetscSection` 1255 1256 Level: advanced 1257 1258 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSetUp()`, `PetscSectionCreate()` 1259 @*/ 1260 PetscErrorCode PetscSectionSetUpBC(PetscSection s) 1261 { 1262 PetscFunctionBegin; 1263 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1264 if (s->bc) { 1265 const PetscInt last = (s->bc->pEnd - s->bc->pStart) - 1; 1266 1267 PetscCall(PetscSectionSetUp(s->bc)); 1268 if (last >= 0) PetscCall(PetscMalloc1(s->bc->atlasOff[last] + s->bc->atlasDof[last], &s->bcIndices)); 1269 else s->bcIndices = NULL; 1270 } 1271 PetscFunctionReturn(PETSC_SUCCESS); 1272 } 1273 1274 /*@ 1275 PetscSectionSetUp - Calculate offsets based upon the number of degrees of freedom for each point in preparation for use of the `PetscSection` 1276 1277 Not Collective 1278 1279 Input Parameter: 1280 . s - the `PetscSection` 1281 1282 Level: intermediate 1283 1284 Notes: 1285 If used, `PetscSectionSetPermutation()` must be called before this routine. 1286 1287 `PetscSectionSetPointMajor()`, cannot be called after this routine. 1288 1289 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionSetPermutation()` 1290 @*/ 1291 PetscErrorCode PetscSectionSetUp(PetscSection s) 1292 { 1293 PetscInt f; 1294 const PetscInt *pind = NULL; 1295 PetscCount offset = 0; 1296 1297 PetscFunctionBegin; 1298 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1299 if (s->setup) PetscFunctionReturn(PETSC_SUCCESS); 1300 s->setup = PETSC_TRUE; 1301 /* Set offsets and field offsets for all points */ 1302 /* Assume that all fields have the same chart */ 1303 PetscCheck(s->includesConstraints, PETSC_COMM_SELF, PETSC_ERR_SUP, "PetscSectionSetUp is currently unsupported for includesConstraints = PETSC_TRUE"); 1304 if (s->perm) PetscCall(ISGetIndices(s->perm, &pind)); 1305 if (s->pointMajor) { 1306 PetscCount foff; 1307 for (PetscInt p = 0; p < s->pEnd - s->pStart; ++p) { 1308 const PetscInt q = pind ? pind[p] : p; 1309 1310 /* Set point offset */ 1311 PetscCall(PetscIntCast(offset, &s->atlasOff[q])); 1312 offset += s->atlasDof[q]; 1313 /* Set field offset */ 1314 for (f = 0, foff = s->atlasOff[q]; f < s->numFields; ++f) { 1315 PetscSection sf = s->field[f]; 1316 1317 PetscCall(PetscIntCast(foff, &sf->atlasOff[q])); 1318 foff += sf->atlasDof[q]; 1319 } 1320 } 1321 } else { 1322 /* Set field offsets for all points */ 1323 for (f = 0; f < s->numFields; ++f) { 1324 PetscSection sf = s->field[f]; 1325 1326 for (PetscInt p = 0; p < s->pEnd - s->pStart; ++p) { 1327 const PetscInt q = pind ? pind[p] : p; 1328 1329 PetscCall(PetscIntCast(offset, &sf->atlasOff[q])); 1330 offset += sf->atlasDof[q]; 1331 } 1332 } 1333 /* Disable point offsets since these are unused */ 1334 for (PetscInt p = 0; p < s->pEnd - s->pStart; ++p) s->atlasOff[p] = -1; 1335 } 1336 if (s->perm) PetscCall(ISRestoreIndices(s->perm, &pind)); 1337 /* Setup BC sections */ 1338 PetscCall(PetscSectionSetUpBC(s)); 1339 for (f = 0; f < s->numFields; ++f) PetscCall(PetscSectionSetUpBC(s->field[f])); 1340 PetscFunctionReturn(PETSC_SUCCESS); 1341 } 1342 1343 /*@ 1344 PetscSectionGetMaxDof - Return the maximum number of degrees of freedom on any point in the `PetscSection` 1345 1346 Not Collective 1347 1348 Input Parameter: 1349 . s - the `PetscSection` 1350 1351 Output Parameter: 1352 . maxDof - the maximum dof 1353 1354 Level: intermediate 1355 1356 Notes: 1357 The returned number is up-to-date without need for `PetscSectionSetUp()`. 1358 1359 This is the maximum over all points of the sum of the number of dof in the unnamed default field plus all named fields. This is equivalent to 1360 the maximum over all points of the value returned by `PetscSectionGetDof()` on this MPI process 1361 1362 Developer Notes: 1363 The returned number is calculated lazily and stashed. 1364 1365 A call to `PetscSectionInvalidateMaxDof_Internal()` invalidates the stashed value. 1366 1367 `PetscSectionInvalidateMaxDof_Internal()` is called in `PetscSectionSetDof()`, `PetscSectionAddDof()` and `PetscSectionReset()` 1368 1369 It should also be called every time `atlasDof` is modified directly. 1370 1371 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetDof()`, `PetscSectionAddDof()`, `PetscSectionCreate()` 1372 @*/ 1373 PetscErrorCode PetscSectionGetMaxDof(PetscSection s, PetscInt *maxDof) 1374 { 1375 PetscInt p; 1376 1377 PetscFunctionBegin; 1378 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1379 PetscAssertPointer(maxDof, 2); 1380 if (s->maxDof == PETSC_INT_MIN) { 1381 s->maxDof = 0; 1382 for (p = 0; p < s->pEnd - s->pStart; ++p) s->maxDof = PetscMax(s->maxDof, s->atlasDof[p]); 1383 } 1384 *maxDof = s->maxDof; 1385 PetscFunctionReturn(PETSC_SUCCESS); 1386 } 1387 1388 /*@ 1389 PetscSectionGetStorageSize - Return the size of an array or local `Vec` capable of holding all the degrees of freedom defined in a `PetscSection` 1390 1391 Not Collective 1392 1393 Input Parameter: 1394 . s - the `PetscSection` 1395 1396 Output Parameter: 1397 . size - the size of an array which can hold all the dofs 1398 1399 Level: intermediate 1400 1401 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionGetConstrainedStorageSize()`, `PetscSectionCreate()` 1402 @*/ 1403 PetscErrorCode PetscSectionGetStorageSize(PetscSection s, PetscInt *size) 1404 { 1405 PetscInt64 n = 0; 1406 1407 PetscFunctionBegin; 1408 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1409 PetscAssertPointer(size, 2); 1410 for (PetscInt p = 0; p < s->pEnd - s->pStart; ++p) n += s->atlasDof[p] > 0 ? s->atlasDof[p] : 0; 1411 PetscCall(PetscIntCast(n, size)); 1412 PetscFunctionReturn(PETSC_SUCCESS); 1413 } 1414 1415 /*@ 1416 PetscSectionGetConstrainedStorageSize - Return the size of an array or local `Vec` capable of holding all unconstrained degrees of freedom in a `PetscSection` 1417 1418 Not Collective 1419 1420 Input Parameter: 1421 . s - the `PetscSection` 1422 1423 Output Parameter: 1424 . size - the size of an array which can hold all unconstrained dofs 1425 1426 Level: intermediate 1427 1428 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetStorageSize()`, `PetscSectionGetOffset()`, `PetscSectionCreate()` 1429 @*/ 1430 PetscErrorCode PetscSectionGetConstrainedStorageSize(PetscSection s, PetscInt *size) 1431 { 1432 PetscInt64 n = 0; 1433 1434 PetscFunctionBegin; 1435 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1436 PetscAssertPointer(size, 2); 1437 for (PetscInt p = 0; p < s->pEnd - s->pStart; ++p) { 1438 const PetscInt cdof = s->bc ? s->bc->atlasDof[p] : 0; 1439 n += s->atlasDof[p] > 0 ? s->atlasDof[p] - cdof : 0; 1440 } 1441 PetscCall(PetscIntCast(n, size)); 1442 PetscFunctionReturn(PETSC_SUCCESS); 1443 } 1444 1445 /*@ 1446 PetscSectionCreateGlobalSection - Create a parallel section describing the global layout using 1447 a local (sequential) `PetscSection` on each MPI process and a `PetscSF` describing the section point overlap. 1448 1449 Input Parameters: 1450 + s - The `PetscSection` for the local field layout 1451 . sf - The `PetscSF` describing parallel layout of the section points (leaves are unowned local points) 1452 . usePermutation - By default this is `PETSC_TRUE`, meaning any permutation of the local section is transferred to the global section 1453 . includeConstraints - By default this is `PETSC_FALSE`, meaning that the global field vector will not possess constrained dofs 1454 - localOffsets - If `PETSC_TRUE`, use local rather than global offsets for the points 1455 1456 Output Parameter: 1457 . gsection - The `PetscSection` for the global field layout 1458 1459 Level: intermediate 1460 1461 Notes: 1462 On each MPI process `gsection` inherits the chart of the `s` on that process. 1463 1464 This sets negative sizes and offsets to points not owned by this process as defined by `sf` but that are within the local value of the chart of `gsection`. 1465 In those locations the value of size is -(size+1) and the value of the offset on the remote process is -(off+1). 1466 1467 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionCreateGlobalSectionCensored()` 1468 @*/ 1469 PetscErrorCode PetscSectionCreateGlobalSection(PetscSection s, PetscSF sf, PetscBool usePermutation, PetscBool includeConstraints, PetscBool localOffsets, PetscSection *gsection) 1470 { 1471 PetscSection gs; 1472 const PetscInt *pind = NULL; 1473 PetscInt *recv = NULL, *neg = NULL; 1474 PetscInt pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots, nlocal, maxleaf; 1475 PetscInt numFields, f, numComponents; 1476 PetscInt foff; 1477 1478 PetscFunctionBegin; 1479 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1480 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2); 1481 PetscValidLogicalCollectiveBool(s, usePermutation, 3); 1482 PetscValidLogicalCollectiveBool(s, includeConstraints, 4); 1483 PetscValidLogicalCollectiveBool(s, localOffsets, 5); 1484 PetscAssertPointer(gsection, 6); 1485 PetscCheck(s->pointMajor, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for field major ordering"); 1486 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), &gs)); 1487 PetscCall(PetscSectionGetNumFields(s, &numFields)); 1488 if (numFields > 0) PetscCall(PetscSectionSetNumFields(gs, numFields)); 1489 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 1490 PetscCall(PetscSectionSetChart(gs, pStart, pEnd)); 1491 gs->includesConstraints = includeConstraints; 1492 PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL)); 1493 nlocal = nroots; /* The local/leaf space matches global/root space */ 1494 /* Must allocate for all points visible to SF, which may be more than this section */ 1495 if (nroots >= 0) { /* nroots < 0 means that the graph has not been set, only happens in serial */ 1496 PetscCall(PetscSFGetLeafRange(sf, NULL, &maxleaf)); 1497 PetscCheck(nroots >= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "SF roots %" PetscInt_FMT " < pEnd %" PetscInt_FMT, nroots, pEnd); 1498 PetscCheck(maxleaf < nroots, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Max local leaf %" PetscInt_FMT " >= nroots %" PetscInt_FMT, maxleaf, nroots); 1499 PetscCall(PetscMalloc2(nroots, &neg, nlocal, &recv)); 1500 PetscCall(PetscArrayzero(neg, nroots)); 1501 } 1502 /* Mark all local points with negative dof */ 1503 for (p = pStart; p < pEnd; ++p) { 1504 PetscCall(PetscSectionGetDof(s, p, &dof)); 1505 PetscCall(PetscSectionSetDof(gs, p, dof)); 1506 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 1507 if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetConstraintDof(gs, p, cdof)); 1508 if (neg) neg[p] = -(dof + 1); 1509 } 1510 PetscCall(PetscSectionSetUpBC(gs)); 1511 if (gs->bcIndices) PetscCall(PetscArraycpy(gs->bcIndices, s->bcIndices, gs->bc->atlasOff[gs->bc->pEnd - gs->bc->pStart - 1] + gs->bc->atlasDof[gs->bc->pEnd - gs->bc->pStart - 1])); 1512 if (nroots >= 0) { 1513 PetscCall(PetscArrayzero(recv, nlocal)); 1514 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, recv, MPI_REPLACE)); 1515 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, recv, MPI_REPLACE)); 1516 for (p = pStart; p < pEnd; ++p) { 1517 if (recv[p] < 0) { 1518 gs->atlasDof[p - pStart] = recv[p]; 1519 PetscCall(PetscSectionGetDof(s, p, &dof)); 1520 PetscCheck(-(recv[p] + 1) == dof, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " is not the unconstrained %" PetscInt_FMT, -(recv[p] + 1), p, dof); 1521 } 1522 } 1523 } 1524 /* Calculate new sizes, get process offset, and calculate point offsets */ 1525 if (usePermutation && s->perm) PetscCall(ISGetIndices(s->perm, &pind)); 1526 for (p = 0, off = 0; p < pEnd - pStart; ++p) { 1527 const PetscInt q = pind ? pind[p] : p; 1528 1529 cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[q] : 0; 1530 gs->atlasOff[q] = off; 1531 off += gs->atlasDof[q] > 0 ? gs->atlasDof[q] - cdof : 0; 1532 } 1533 if (!localOffsets) { 1534 PetscCallMPI(MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)sf))); 1535 globalOff -= off; 1536 } 1537 for (p = pStart, off = 0; p < pEnd; ++p) { 1538 gs->atlasOff[p - pStart] += globalOff; 1539 if (neg) neg[p] = -(gs->atlasOff[p - pStart] + 1); 1540 } 1541 if (usePermutation && s->perm) PetscCall(ISRestoreIndices(s->perm, &pind)); 1542 /* Put in negative offsets for ghost points */ 1543 if (nroots >= 0) { 1544 PetscCall(PetscArrayzero(recv, nlocal)); 1545 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, recv, MPI_REPLACE)); 1546 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, recv, MPI_REPLACE)); 1547 for (p = pStart; p < pEnd; ++p) { 1548 if (recv[p] < 0) gs->atlasOff[p - pStart] = recv[p]; 1549 } 1550 } 1551 PetscCall(PetscFree2(neg, recv)); 1552 /* Set field dofs/offsets/constraints */ 1553 for (f = 0; f < numFields; ++f) { 1554 const char *name; 1555 1556 gs->field[f]->includesConstraints = includeConstraints; 1557 PetscCall(PetscSectionGetFieldComponents(s, f, &numComponents)); 1558 PetscCall(PetscSectionSetFieldComponents(gs, f, numComponents)); 1559 PetscCall(PetscSectionGetFieldName(s, f, &name)); 1560 PetscCall(PetscSectionSetFieldName(gs, f, name)); 1561 } 1562 for (p = pStart; p < pEnd; ++p) { 1563 PetscCall(PetscSectionGetOffset(gs, p, &off)); 1564 for (f = 0, foff = off; f < numFields; ++f) { 1565 PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof)); 1566 if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetFieldConstraintDof(gs, p, f, cdof)); 1567 PetscCall(PetscSectionGetFieldDof(s, p, f, &dof)); 1568 PetscCall(PetscSectionSetFieldDof(gs, p, f, off < 0 ? -(dof + 1) : dof)); 1569 PetscCall(PetscSectionSetFieldOffset(gs, p, f, foff)); 1570 PetscCall(PetscSectionGetFieldConstraintDof(gs, p, f, &cdof)); 1571 foff = off < 0 ? foff - (dof - cdof) : foff + (dof - cdof); 1572 } 1573 } 1574 for (f = 0; f < numFields; ++f) { 1575 PetscSection gfs = gs->field[f]; 1576 1577 PetscCall(PetscSectionSetUpBC(gfs)); 1578 if (gfs->bcIndices) PetscCall(PetscArraycpy(gfs->bcIndices, s->field[f]->bcIndices, gfs->bc->atlasOff[gfs->bc->pEnd - gfs->bc->pStart - 1] + gfs->bc->atlasDof[gfs->bc->pEnd - gfs->bc->pStart - 1])); 1579 } 1580 gs->setup = PETSC_TRUE; 1581 PetscCall(PetscSectionViewFromOptions(gs, NULL, "-global_section_view")); 1582 *gsection = gs; 1583 PetscFunctionReturn(PETSC_SUCCESS); 1584 } 1585 1586 /*@ 1587 PetscSectionCreateGlobalSectionCensored - Create a `PetscSection` describing the globallayout using 1588 a local (sequential) `PetscSection` on each MPI process and an `PetscSF` describing the section point overlap. 1589 1590 Input Parameters: 1591 + s - The `PetscSection` for the local field layout 1592 . sf - The `PetscSF` describing parallel layout of the section points 1593 . includeConstraints - By default this is `PETSC_FALSE`, meaning that the global vector will not possess constrained dofs 1594 . numExcludes - The number of exclusion ranges, this must have the same value on all MPI processes 1595 - excludes - An array [start_0, end_0, start_1, end_1, ...] where there are `numExcludes` pairs and must have the same values on all MPI processes 1596 1597 Output Parameter: 1598 . gsection - The `PetscSection` for the global field layout 1599 1600 Level: advanced 1601 1602 Notes: 1603 On each MPI process `gsection` inherits the chart of the `s` on that process. 1604 1605 This sets negative sizes and offsets to points not owned by this process as defined by `sf` but that are within the local value of the chart of `gsection`. 1606 In those locations the value of size is -(size+1) and the value of the offset on the remote process is -(off+1). 1607 1608 This routine augments `PetscSectionCreateGlobalSection()` by allowing one to exclude certain ranges in the chart of the `PetscSection` 1609 1610 Developer Notes: 1611 This is a terrible function name 1612 1613 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()` 1614 @*/ 1615 PetscErrorCode PetscSectionCreateGlobalSectionCensored(PetscSection s, PetscSF sf, PetscBool includeConstraints, PetscInt numExcludes, const PetscInt excludes[], PetscSection *gsection) 1616 { 1617 const PetscInt *pind = NULL; 1618 PetscInt *neg = NULL, *tmpOff = NULL; 1619 PetscInt pStart, pEnd, p, e, dof, cdof, globalOff = 0, nroots; 1620 PetscInt off; 1621 1622 PetscFunctionBegin; 1623 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1624 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2); 1625 PetscAssertPointer(gsection, 6); 1626 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), gsection)); 1627 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 1628 PetscCall(PetscSectionSetChart(*gsection, pStart, pEnd)); 1629 PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL)); 1630 if (nroots >= 0) { 1631 PetscCheck(nroots >= pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %" PetscInt_FMT " < %" PetscInt_FMT " section size", nroots, pEnd - pStart); 1632 PetscCall(PetscCalloc1(nroots, &neg)); 1633 if (nroots > pEnd - pStart) { 1634 PetscCall(PetscCalloc1(nroots, &tmpOff)); 1635 } else { 1636 tmpOff = &(*gsection)->atlasDof[-pStart]; 1637 } 1638 } 1639 /* Mark ghost points with negative dof */ 1640 for (p = pStart; p < pEnd; ++p) { 1641 for (e = 0; e < numExcludes; ++e) { 1642 if ((p >= excludes[e * 2 + 0]) && (p < excludes[e * 2 + 1])) { 1643 PetscCall(PetscSectionSetDof(*gsection, p, 0)); 1644 break; 1645 } 1646 } 1647 if (e < numExcludes) continue; 1648 PetscCall(PetscSectionGetDof(s, p, &dof)); 1649 PetscCall(PetscSectionSetDof(*gsection, p, dof)); 1650 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 1651 if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetConstraintDof(*gsection, p, cdof)); 1652 if (neg) neg[p] = -(dof + 1); 1653 } 1654 PetscCall(PetscSectionSetUpBC(*gsection)); 1655 if (nroots >= 0) { 1656 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE)); 1657 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE)); 1658 if (nroots > pEnd - pStart) { 1659 for (p = pStart; p < pEnd; ++p) { 1660 if (tmpOff[p] < 0) (*gsection)->atlasDof[p - pStart] = tmpOff[p]; 1661 } 1662 } 1663 } 1664 /* Calculate new sizes, get process offset, and calculate point offsets */ 1665 if (s->perm) PetscCall(ISGetIndices(s->perm, &pind)); 1666 for (p = 0, off = 0; p < pEnd - pStart; ++p) { 1667 const PetscInt q = pind ? pind[p] : p; 1668 1669 cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[q] : 0; 1670 (*gsection)->atlasOff[q] = off; 1671 off += (*gsection)->atlasDof[q] > 0 ? (*gsection)->atlasDof[q] - cdof : 0; 1672 } 1673 PetscCallMPI(MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)s))); 1674 globalOff -= off; 1675 for (p = 0, off = 0; p < pEnd - pStart; ++p) { 1676 (*gsection)->atlasOff[p] += globalOff; 1677 if (neg) neg[p + pStart] = -((*gsection)->atlasOff[p] + 1); 1678 } 1679 if (s->perm) PetscCall(ISRestoreIndices(s->perm, &pind)); 1680 /* Put in negative offsets for ghost points */ 1681 if (nroots >= 0) { 1682 if (nroots == pEnd - pStart) tmpOff = &(*gsection)->atlasOff[-pStart]; 1683 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE)); 1684 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE)); 1685 if (nroots > pEnd - pStart) { 1686 for (p = pStart; p < pEnd; ++p) { 1687 if (tmpOff[p] < 0) (*gsection)->atlasOff[p - pStart] = tmpOff[p]; 1688 } 1689 } 1690 } 1691 if (nroots >= 0 && nroots > pEnd - pStart) PetscCall(PetscFree(tmpOff)); 1692 PetscCall(PetscFree(neg)); 1693 PetscFunctionReturn(PETSC_SUCCESS); 1694 } 1695 1696 /*@ 1697 PetscSectionGetPointLayout - Get a `PetscLayout` for the points with nonzero dof counts of the unnamed default field within this `PetscSection`s local chart 1698 1699 Collective 1700 1701 Input Parameters: 1702 + comm - The `MPI_Comm` 1703 - s - The `PetscSection` 1704 1705 Output Parameter: 1706 . layout - The point layout for the data that defines the section 1707 1708 Level: advanced 1709 1710 Notes: 1711 `PetscSectionGetValueLayout()` provides similar information but counting the total number of degrees of freedom on the MPI process (excluding constrained 1712 degrees of freedom). 1713 1714 This count includes constrained degrees of freedom 1715 1716 This is usually called on the default global section. 1717 1718 Example: 1719 .vb 1720 The chart is [2,5), point 2 has 2 dof, point 3 has 0 dof, point 4 has 1 dof 1721 The local size of the `PetscLayout` is 2 since 2 points have a non-zero number of dof 1722 .ve 1723 1724 Developer Notes: 1725 I find the names of these two functions extremely non-informative 1726 1727 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetValueLayout()`, `PetscSectionCreate()` 1728 @*/ 1729 PetscErrorCode PetscSectionGetPointLayout(MPI_Comm comm, PetscSection s, PetscLayout *layout) 1730 { 1731 PetscInt pStart, pEnd, p, localSize = 0; 1732 1733 PetscFunctionBegin; 1734 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 1735 for (p = pStart; p < pEnd; ++p) { 1736 PetscInt dof; 1737 1738 PetscCall(PetscSectionGetDof(s, p, &dof)); 1739 if (dof >= 0) ++localSize; 1740 } 1741 PetscCall(PetscLayoutCreate(comm, layout)); 1742 PetscCall(PetscLayoutSetLocalSize(*layout, localSize)); 1743 PetscCall(PetscLayoutSetBlockSize(*layout, 1)); 1744 PetscCall(PetscLayoutSetUp(*layout)); 1745 PetscFunctionReturn(PETSC_SUCCESS); 1746 } 1747 1748 /*@ 1749 PetscSectionGetValueLayout - Get the `PetscLayout` associated with the section dofs of a `PetscSection` 1750 1751 Collective 1752 1753 Input Parameters: 1754 + comm - The `MPI_Comm` 1755 - s - The `PetscSection` 1756 1757 Output Parameter: 1758 . layout - The dof layout for the section 1759 1760 Level: advanced 1761 1762 Notes: 1763 `PetscSectionGetPointLayout()` provides similar information but only counting the number of points with nonzero degrees of freedom and 1764 including the constrained degrees of freedom 1765 1766 This is usually called for the default global section. 1767 1768 Example: 1769 .vb 1770 The chart is [2,5), point 2 has 4 dof (2 constrained), point 3 has 0 dof, point 4 has 1 dof (not constrained) 1771 The local size of the `PetscLayout` is 3 since there are 3 unconstrained degrees of freedom on this MPI process 1772 .ve 1773 1774 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetPointLayout()`, `PetscSectionCreate()` 1775 @*/ 1776 PetscErrorCode PetscSectionGetValueLayout(MPI_Comm comm, PetscSection s, PetscLayout *layout) 1777 { 1778 PetscInt pStart, pEnd, p, localSize = 0; 1779 1780 PetscFunctionBegin; 1781 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2); 1782 PetscAssertPointer(layout, 3); 1783 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 1784 for (p = pStart; p < pEnd; ++p) { 1785 PetscInt dof, cdof; 1786 1787 PetscCall(PetscSectionGetDof(s, p, &dof)); 1788 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 1789 if (dof - cdof > 0) localSize += dof - cdof; 1790 } 1791 PetscCall(PetscLayoutCreate(comm, layout)); 1792 PetscCall(PetscLayoutSetLocalSize(*layout, localSize)); 1793 PetscCall(PetscLayoutSetBlockSize(*layout, 1)); 1794 PetscCall(PetscLayoutSetUp(*layout)); 1795 PetscFunctionReturn(PETSC_SUCCESS); 1796 } 1797 1798 /*@ 1799 PetscSectionGetOffset - Return the offset into an array or `Vec` for the dof associated with the given point. 1800 1801 Not Collective 1802 1803 Input Parameters: 1804 + s - the `PetscSection` 1805 - point - the point 1806 1807 Output Parameter: 1808 . offset - the offset 1809 1810 Level: intermediate 1811 1812 Notes: 1813 In a global section, `offset` will be negative for points not owned by this process. 1814 1815 This is for the unnamed default field in the `PetscSection` not the named fields 1816 1817 The `offset` values are different depending on a value set with `PetscSectionSetPointMajor()` 1818 1819 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionCreate()`, `PetscSectionSetPointMajor()` 1820 @*/ 1821 PetscErrorCode PetscSectionGetOffset(PetscSection s, PetscInt point, PetscInt *offset) 1822 { 1823 PetscFunctionBegin; 1824 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1825 PetscAssertPointer(offset, 3); 1826 PetscAssert(!(point < s->pStart) && !(point >= s->pEnd), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd); 1827 *offset = s->atlasOff[point - s->pStart]; 1828 PetscFunctionReturn(PETSC_SUCCESS); 1829 } 1830 1831 /*@ 1832 PetscSectionSetOffset - Set the offset into an array or `Vec` for the dof associated with the given point. 1833 1834 Not Collective 1835 1836 Input Parameters: 1837 + s - the `PetscSection` 1838 . point - the point 1839 - offset - the offset, these values may be negative indicating the values are off process 1840 1841 Level: developer 1842 1843 Note: 1844 The user usually does not call this function, but uses `PetscSectionSetUp()` 1845 1846 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionCreate()`, `PetscSectionSetUp()` 1847 @*/ 1848 PetscErrorCode PetscSectionSetOffset(PetscSection s, PetscInt point, PetscInt offset) 1849 { 1850 PetscFunctionBegin; 1851 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1852 PetscCheck(!(point < s->pStart) && !(point >= s->pEnd), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section point %" PetscInt_FMT " should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", point, s->pStart, s->pEnd); 1853 s->atlasOff[point - s->pStart] = offset; 1854 PetscFunctionReturn(PETSC_SUCCESS); 1855 } 1856 1857 /*@ 1858 PetscSectionGetFieldOffset - Return the offset into an array or `Vec` for the field dof associated with the given point. 1859 1860 Not Collective 1861 1862 Input Parameters: 1863 + s - the `PetscSection` 1864 . point - the point 1865 - field - the field 1866 1867 Output Parameter: 1868 . offset - the offset 1869 1870 Level: intermediate 1871 1872 Notes: 1873 In a global section, `offset` will be negative for points not owned by this process. 1874 1875 The `offset` values are different depending on a value set with `PetscSectionSetPointMajor()` 1876 1877 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()`, `PetscSectionGetFieldPointOffset()` 1878 @*/ 1879 PetscErrorCode PetscSectionGetFieldOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt *offset) 1880 { 1881 PetscFunctionBegin; 1882 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1883 PetscAssertPointer(offset, 4); 1884 PetscSectionCheckValidField(field, s->numFields); 1885 PetscCall(PetscSectionGetOffset(s->field[field], point, offset)); 1886 PetscFunctionReturn(PETSC_SUCCESS); 1887 } 1888 1889 /*@ 1890 PetscSectionSetFieldOffset - Set the offset into an array or `Vec` for the dof associated with the given field at a point. 1891 1892 Not Collective 1893 1894 Input Parameters: 1895 + s - the `PetscSection` 1896 . point - the point 1897 . field - the field 1898 - offset - the offset, these values may be negative indicating the values are off process 1899 1900 Level: developer 1901 1902 Note: 1903 The user usually does not call this function, but uses `PetscSectionSetUp()` 1904 1905 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionSetOffset()`, `PetscSectionCreate()`, `PetscSectionSetUp()` 1906 @*/ 1907 PetscErrorCode PetscSectionSetFieldOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt offset) 1908 { 1909 PetscFunctionBegin; 1910 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1911 PetscSectionCheckValidField(field, s->numFields); 1912 PetscCall(PetscSectionSetOffset(s->field[field], point, offset)); 1913 PetscFunctionReturn(PETSC_SUCCESS); 1914 } 1915 1916 /*@ 1917 PetscSectionGetFieldPointOffset - Return the offset for the first field dof associated with the given point relative to the offset for that point for the 1918 unnamed default field's first dof 1919 1920 Not Collective 1921 1922 Input Parameters: 1923 + s - the `PetscSection` 1924 . point - the point 1925 - field - the field 1926 1927 Output Parameter: 1928 . offset - the offset 1929 1930 Level: advanced 1931 1932 Note: 1933 This ignores constraints 1934 1935 Example: 1936 .vb 1937 if PetscSectionSetPointMajor(s,PETSC_TRUE) 1938 The unnamed default field has 3 dof at `point` 1939 Field 0 has 2 dof at `point` 1940 Then PetscSectionGetFieldPointOffset(s,point,1,&offset) returns and offset of 5 1941 .ve 1942 1943 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()`, `PetscSectionGetFieldOffset()` 1944 @*/ 1945 PetscErrorCode PetscSectionGetFieldPointOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt *offset) 1946 { 1947 PetscInt off, foff; 1948 1949 PetscFunctionBegin; 1950 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1951 PetscAssertPointer(offset, 4); 1952 PetscSectionCheckValidField(field, s->numFields); 1953 PetscCall(PetscSectionGetOffset(s, point, &off)); 1954 PetscCall(PetscSectionGetOffset(s->field[field], point, &foff)); 1955 *offset = foff - off; 1956 PetscFunctionReturn(PETSC_SUCCESS); 1957 } 1958 1959 /*@ 1960 PetscSectionGetOffsetRange - Return the full range of offsets [`start`, `end`) for a `PetscSection` 1961 1962 Not Collective 1963 1964 Input Parameter: 1965 . s - the `PetscSection` 1966 1967 Output Parameters: 1968 + start - the minimum offset 1969 - end - one more than the maximum offset 1970 1971 Level: intermediate 1972 1973 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()` 1974 @*/ 1975 PetscErrorCode PetscSectionGetOffsetRange(PetscSection s, PetscInt *start, PetscInt *end) 1976 { 1977 PetscInt os = 0, oe = 0, pStart, pEnd, p; 1978 1979 PetscFunctionBegin; 1980 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1981 if (s->atlasOff) { 1982 os = s->atlasOff[0]; 1983 oe = s->atlasOff[0]; 1984 } 1985 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 1986 for (p = 0; p < pEnd - pStart; ++p) { 1987 PetscInt dof = s->atlasDof[p], off = s->atlasOff[p]; 1988 1989 if (off >= 0) { 1990 os = PetscMin(os, off); 1991 oe = PetscMax(oe, off + dof); 1992 } 1993 } 1994 if (start) *start = os; 1995 if (end) *end = oe; 1996 PetscFunctionReturn(PETSC_SUCCESS); 1997 } 1998 1999 /*@ 2000 PetscSectionCreateSubsection - Create a new, smaller `PetscSection` composed of only selected fields 2001 2002 Collective 2003 2004 Input Parameters: 2005 + s - the `PetscSection` 2006 . len - the number of subfields 2007 - fields - the subfield numbers 2008 2009 Output Parameter: 2010 . subs - the subsection 2011 2012 Level: advanced 2013 2014 Notes: 2015 The chart of `subs` is the same as the chart of `s` 2016 2017 This will error if a fieldnumber is out of range 2018 2019 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreateSupersection()`, `PetscSectionCreate()` 2020 @*/ 2021 PetscErrorCode PetscSectionCreateSubsection(PetscSection s, PetscInt len, const PetscInt fields[], PetscSection *subs) 2022 { 2023 PetscInt nF, f, c, pStart, pEnd, p, maxCdof = 0; 2024 2025 PetscFunctionBegin; 2026 if (!len) PetscFunctionReturn(PETSC_SUCCESS); 2027 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2028 PetscAssertPointer(fields, 3); 2029 PetscAssertPointer(subs, 4); 2030 PetscCall(PetscSectionGetNumFields(s, &nF)); 2031 PetscCheck(len <= nF, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONG, "Number of requested fields %" PetscInt_FMT " greater than number of fields %" PetscInt_FMT, len, nF); 2032 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), subs)); 2033 PetscCall(PetscSectionSetNumFields(*subs, len)); 2034 for (f = 0; f < len; ++f) { 2035 const char *name = NULL; 2036 PetscInt numComp = 0; 2037 PetscSectionSym sym; 2038 2039 PetscCall(PetscSectionGetFieldName(s, fields[f], &name)); 2040 PetscCall(PetscSectionSetFieldName(*subs, f, name)); 2041 PetscCall(PetscSectionGetFieldComponents(s, fields[f], &numComp)); 2042 PetscCall(PetscSectionSetFieldComponents(*subs, f, numComp)); 2043 for (c = 0; c < s->numFieldComponents[fields[f]]; ++c) { 2044 PetscCall(PetscSectionGetComponentName(s, fields[f], c, &name)); 2045 PetscCall(PetscSectionSetComponentName(*subs, f, c, name)); 2046 } 2047 PetscCall(PetscSectionGetFieldSym(s, fields[f], &sym)); 2048 PetscCall(PetscSectionSetFieldSym(*subs, f, sym)); 2049 } 2050 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 2051 PetscCall(PetscSectionSetChart(*subs, pStart, pEnd)); 2052 for (p = pStart; p < pEnd; ++p) { 2053 PetscInt dof = 0, cdof = 0, fdof = 0, cfdof = 0; 2054 2055 for (f = 0; f < len; ++f) { 2056 PetscCall(PetscSectionGetFieldDof(s, p, fields[f], &fdof)); 2057 PetscCall(PetscSectionSetFieldDof(*subs, p, f, fdof)); 2058 PetscCall(PetscSectionGetFieldConstraintDof(s, p, fields[f], &cfdof)); 2059 if (cfdof) PetscCall(PetscSectionSetFieldConstraintDof(*subs, p, f, cfdof)); 2060 dof += fdof; 2061 cdof += cfdof; 2062 } 2063 PetscCall(PetscSectionSetDof(*subs, p, dof)); 2064 if (cdof) PetscCall(PetscSectionSetConstraintDof(*subs, p, cdof)); 2065 maxCdof = PetscMax(cdof, maxCdof); 2066 } 2067 PetscCall(PetscSectionSetUp(*subs)); 2068 if (maxCdof) { 2069 PetscInt *indices; 2070 2071 PetscCall(PetscMalloc1(maxCdof, &indices)); 2072 for (p = pStart; p < pEnd; ++p) { 2073 PetscInt cdof; 2074 2075 PetscCall(PetscSectionGetConstraintDof(*subs, p, &cdof)); 2076 if (cdof) { 2077 const PetscInt *oldIndices = NULL; 2078 PetscInt fdof = 0, cfdof = 0, fc, numConst = 0, fOff = 0; 2079 2080 for (f = 0; f < len; ++f) { 2081 PetscCall(PetscSectionGetFieldDof(s, p, fields[f], &fdof)); 2082 PetscCall(PetscSectionGetFieldConstraintDof(s, p, fields[f], &cfdof)); 2083 PetscCall(PetscSectionGetFieldConstraintIndices(s, p, fields[f], &oldIndices)); 2084 PetscCall(PetscSectionSetFieldConstraintIndices(*subs, p, f, oldIndices)); 2085 for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] = oldIndices[fc] + fOff; 2086 numConst += cfdof; 2087 fOff += fdof; 2088 } 2089 PetscCall(PetscSectionSetConstraintIndices(*subs, p, indices)); 2090 } 2091 } 2092 PetscCall(PetscFree(indices)); 2093 } 2094 PetscFunctionReturn(PETSC_SUCCESS); 2095 } 2096 2097 /*@ 2098 PetscSectionCreateComponentSubsection - Create a new, smaller `PetscSection` composed of only selected components 2099 2100 Collective 2101 2102 Input Parameters: 2103 + s - the `PetscSection` 2104 . len - the number of components 2105 - comps - the component numbers 2106 2107 Output Parameter: 2108 . subs - the subsection 2109 2110 Level: advanced 2111 2112 Notes: 2113 The chart of `subs` is the same as the chart of `s` 2114 2115 This will error if the section has more than one field, or if a component number is out of range 2116 2117 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreateSupersection()`, `PetscSectionCreate()` 2118 @*/ 2119 PetscErrorCode PetscSectionCreateComponentSubsection(PetscSection s, PetscInt len, const PetscInt comps[], PetscSection *subs) 2120 { 2121 PetscSectionSym sym; 2122 const char *name = NULL; 2123 PetscInt Nf, pStart, pEnd; 2124 2125 PetscFunctionBegin; 2126 if (!len) PetscFunctionReturn(PETSC_SUCCESS); 2127 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2128 PetscAssertPointer(comps, 3); 2129 PetscAssertPointer(subs, 4); 2130 PetscCall(PetscSectionGetNumFields(s, &Nf)); 2131 PetscCheck(Nf == 1, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONG, "This method can only handle one field, not %" PetscInt_FMT, Nf); 2132 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), subs)); 2133 PetscCall(PetscSectionSetNumFields(*subs, 1)); 2134 PetscCall(PetscSectionGetFieldName(s, 0, &name)); 2135 PetscCall(PetscSectionSetFieldName(*subs, 0, name)); 2136 PetscCall(PetscSectionSetFieldComponents(*subs, 0, len)); 2137 PetscCall(PetscSectionGetFieldSym(s, 0, &sym)); 2138 PetscCall(PetscSectionSetFieldSym(*subs, 0, sym)); 2139 for (PetscInt c = 0; c < len; ++c) { 2140 PetscCall(PetscSectionGetComponentName(s, 0, comps[c], &name)); 2141 PetscCall(PetscSectionSetComponentName(*subs, 0, c, name)); 2142 } 2143 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 2144 PetscCall(PetscSectionSetChart(*subs, pStart, pEnd)); 2145 for (PetscInt p = pStart; p < pEnd; ++p) { 2146 PetscInt dof, cdof, cfdof; 2147 2148 PetscCall(PetscSectionGetDof(s, p, &dof)); 2149 if (!dof) continue; 2150 PetscCall(PetscSectionGetFieldConstraintDof(s, p, 0, &cfdof)); 2151 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 2152 PetscCheck(!cdof && !cfdof, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Component selection does not work with constraints"); 2153 PetscCall(PetscSectionSetFieldDof(*subs, p, 0, len)); 2154 PetscCall(PetscSectionSetDof(*subs, p, len)); 2155 } 2156 PetscCall(PetscSectionSetUp(*subs)); 2157 PetscFunctionReturn(PETSC_SUCCESS); 2158 } 2159 2160 /*@ 2161 PetscSectionCreateSupersection - Create a new, larger section composed of multiple `PetscSection`s 2162 2163 Collective 2164 2165 Input Parameters: 2166 + s - the input sections 2167 - len - the number of input sections 2168 2169 Output Parameter: 2170 . supers - the supersection 2171 2172 Level: advanced 2173 2174 Notes: 2175 The section offsets now refer to a new, larger vector. 2176 2177 Developer Notes: 2178 Needs to explain how the sections are composed 2179 2180 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreateSubsection()`, `PetscSectionCreate()` 2181 @*/ 2182 PetscErrorCode PetscSectionCreateSupersection(PetscSection s[], PetscInt len, PetscSection *supers) 2183 { 2184 PetscInt Nf = 0, f, pStart = PETSC_INT_MAX, pEnd = 0, p, maxCdof = 0, i; 2185 2186 PetscFunctionBegin; 2187 if (!len) PetscFunctionReturn(PETSC_SUCCESS); 2188 for (i = 0; i < len; ++i) { 2189 PetscInt nf, pStarti, pEndi; 2190 2191 PetscCall(PetscSectionGetNumFields(s[i], &nf)); 2192 PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi)); 2193 pStart = PetscMin(pStart, pStarti); 2194 pEnd = PetscMax(pEnd, pEndi); 2195 Nf += nf; 2196 } 2197 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s[0]), supers)); 2198 PetscCall(PetscSectionSetNumFields(*supers, Nf)); 2199 for (i = 0, f = 0; i < len; ++i) { 2200 PetscInt nf, fi, ci; 2201 2202 PetscCall(PetscSectionGetNumFields(s[i], &nf)); 2203 for (fi = 0; fi < nf; ++fi, ++f) { 2204 const char *name = NULL; 2205 PetscInt numComp = 0; 2206 2207 PetscCall(PetscSectionGetFieldName(s[i], fi, &name)); 2208 PetscCall(PetscSectionSetFieldName(*supers, f, name)); 2209 PetscCall(PetscSectionGetFieldComponents(s[i], fi, &numComp)); 2210 PetscCall(PetscSectionSetFieldComponents(*supers, f, numComp)); 2211 for (ci = 0; ci < s[i]->numFieldComponents[fi]; ++ci) { 2212 PetscCall(PetscSectionGetComponentName(s[i], fi, ci, &name)); 2213 PetscCall(PetscSectionSetComponentName(*supers, f, ci, name)); 2214 } 2215 } 2216 } 2217 PetscCall(PetscSectionSetChart(*supers, pStart, pEnd)); 2218 for (p = pStart; p < pEnd; ++p) { 2219 PetscInt dof = 0, cdof = 0; 2220 2221 for (i = 0, f = 0; i < len; ++i) { 2222 PetscInt nf, fi, pStarti, pEndi; 2223 PetscInt fdof = 0, cfdof = 0; 2224 2225 PetscCall(PetscSectionGetNumFields(s[i], &nf)); 2226 PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi)); 2227 if ((p < pStarti) || (p >= pEndi)) continue; 2228 for (fi = 0; fi < nf; ++fi, ++f) { 2229 PetscCall(PetscSectionGetFieldDof(s[i], p, fi, &fdof)); 2230 PetscCall(PetscSectionAddFieldDof(*supers, p, f, fdof)); 2231 PetscCall(PetscSectionGetFieldConstraintDof(s[i], p, fi, &cfdof)); 2232 if (cfdof) PetscCall(PetscSectionAddFieldConstraintDof(*supers, p, f, cfdof)); 2233 dof += fdof; 2234 cdof += cfdof; 2235 } 2236 } 2237 PetscCall(PetscSectionSetDof(*supers, p, dof)); 2238 if (cdof) PetscCall(PetscSectionSetConstraintDof(*supers, p, cdof)); 2239 maxCdof = PetscMax(cdof, maxCdof); 2240 } 2241 PetscCall(PetscSectionSetUp(*supers)); 2242 if (maxCdof) { 2243 PetscInt *indices; 2244 2245 PetscCall(PetscMalloc1(maxCdof, &indices)); 2246 for (p = pStart; p < pEnd; ++p) { 2247 PetscInt cdof; 2248 2249 PetscCall(PetscSectionGetConstraintDof(*supers, p, &cdof)); 2250 if (cdof) { 2251 PetscInt dof, numConst = 0, fOff = 0; 2252 2253 for (i = 0, f = 0; i < len; ++i) { 2254 const PetscInt *oldIndices = NULL; 2255 PetscInt nf, fi, pStarti, pEndi, fdof, cfdof, fc; 2256 2257 PetscCall(PetscSectionGetNumFields(s[i], &nf)); 2258 PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi)); 2259 if ((p < pStarti) || (p >= pEndi)) continue; 2260 for (fi = 0; fi < nf; ++fi, ++f) { 2261 PetscCall(PetscSectionGetFieldDof(s[i], p, fi, &fdof)); 2262 PetscCall(PetscSectionGetFieldConstraintDof(s[i], p, fi, &cfdof)); 2263 PetscCall(PetscSectionGetFieldConstraintIndices(s[i], p, fi, &oldIndices)); 2264 for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] = oldIndices[fc]; 2265 PetscCall(PetscSectionSetFieldConstraintIndices(*supers, p, f, &indices[numConst])); 2266 for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] += fOff; 2267 numConst += cfdof; 2268 } 2269 PetscCall(PetscSectionGetDof(s[i], p, &dof)); 2270 fOff += dof; 2271 } 2272 PetscCall(PetscSectionSetConstraintIndices(*supers, p, indices)); 2273 } 2274 } 2275 PetscCall(PetscFree(indices)); 2276 } 2277 PetscFunctionReturn(PETSC_SUCCESS); 2278 } 2279 2280 static PetscErrorCode PetscSectionCreateSubplexSection_Private(PetscSection s, IS subpointIS, PetscBool renumberPoints, PetscSection *subs) 2281 { 2282 const PetscInt *points = NULL, *indices = NULL; 2283 PetscInt *spoints = NULL, *order = NULL; 2284 PetscInt numFields, f, c, numSubpoints = 0, pStart, pEnd, p, spStart, spEnd, subp; 2285 2286 PetscFunctionBegin; 2287 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2288 PetscValidHeaderSpecific(subpointIS, IS_CLASSID, 2); 2289 PetscAssertPointer(subs, 4); 2290 PetscCall(PetscSectionGetNumFields(s, &numFields)); 2291 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), subs)); 2292 if (numFields) PetscCall(PetscSectionSetNumFields(*subs, numFields)); 2293 for (f = 0; f < numFields; ++f) { 2294 const char *name = NULL; 2295 PetscInt numComp = 0; 2296 2297 PetscCall(PetscSectionGetFieldName(s, f, &name)); 2298 PetscCall(PetscSectionSetFieldName(*subs, f, name)); 2299 PetscCall(PetscSectionGetFieldComponents(s, f, &numComp)); 2300 PetscCall(PetscSectionSetFieldComponents(*subs, f, numComp)); 2301 for (c = 0; c < s->numFieldComponents[f]; ++c) { 2302 PetscCall(PetscSectionGetComponentName(s, f, c, &name)); 2303 PetscCall(PetscSectionSetComponentName(*subs, f, c, name)); 2304 } 2305 } 2306 /* For right now, we do not try to squeeze the subchart */ 2307 if (subpointIS) { 2308 PetscCall(ISGetLocalSize(subpointIS, &numSubpoints)); 2309 PetscCall(ISGetIndices(subpointIS, &points)); 2310 } 2311 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 2312 if (renumberPoints) { 2313 PetscBool sorted; 2314 2315 spStart = 0; 2316 spEnd = numSubpoints; 2317 PetscCall(ISSorted(subpointIS, &sorted)); 2318 if (!sorted) { 2319 PetscCall(PetscMalloc2(numSubpoints, &spoints, numSubpoints, &order)); 2320 PetscCall(PetscArraycpy(spoints, points, numSubpoints)); 2321 for (PetscInt i = 0; i < numSubpoints; ++i) order[i] = i; 2322 PetscCall(PetscSortIntWithArray(numSubpoints, spoints, order)); 2323 } 2324 } else { 2325 PetscCall(ISGetMinMax(subpointIS, &spStart, &spEnd)); 2326 ++spEnd; 2327 } 2328 PetscCall(PetscSectionSetChart(*subs, spStart, spEnd)); 2329 for (p = pStart; p < pEnd; ++p) { 2330 PetscInt dof, cdof, fdof = 0, cfdof = 0; 2331 2332 PetscCall(PetscFindInt(p, numSubpoints, spoints ? spoints : points, &subp)); 2333 if (subp < 0) continue; 2334 if (!renumberPoints) subp = p; 2335 else subp = order ? order[subp] : subp; 2336 for (f = 0; f < numFields; ++f) { 2337 PetscCall(PetscSectionGetFieldDof(s, p, f, &fdof)); 2338 PetscCall(PetscSectionSetFieldDof(*subs, subp, f, fdof)); 2339 PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cfdof)); 2340 if (cfdof) PetscCall(PetscSectionSetFieldConstraintDof(*subs, subp, f, cfdof)); 2341 } 2342 PetscCall(PetscSectionGetDof(s, p, &dof)); 2343 PetscCall(PetscSectionSetDof(*subs, subp, dof)); 2344 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 2345 if (cdof) PetscCall(PetscSectionSetConstraintDof(*subs, subp, cdof)); 2346 } 2347 PetscCall(PetscSectionSetUp(*subs)); 2348 /* Change offsets to original offsets */ 2349 for (p = pStart; p < pEnd; ++p) { 2350 PetscInt off, foff = 0; 2351 2352 PetscCall(PetscFindInt(p, numSubpoints, spoints ? spoints : points, &subp)); 2353 if (subp < 0) continue; 2354 if (!renumberPoints) subp = p; 2355 else subp = order ? order[subp] : subp; 2356 for (f = 0; f < numFields; ++f) { 2357 PetscCall(PetscSectionGetFieldOffset(s, p, f, &foff)); 2358 PetscCall(PetscSectionSetFieldOffset(*subs, subp, f, foff)); 2359 } 2360 PetscCall(PetscSectionGetOffset(s, p, &off)); 2361 PetscCall(PetscSectionSetOffset(*subs, subp, off)); 2362 } 2363 /* Copy constraint indices */ 2364 for (subp = spStart; subp < spEnd; ++subp) { 2365 PetscInt cdof; 2366 2367 PetscCall(PetscSectionGetConstraintDof(*subs, subp, &cdof)); 2368 if (cdof) { 2369 for (f = 0; f < numFields; ++f) { 2370 PetscCall(PetscSectionGetFieldConstraintIndices(s, points[subp - spStart], f, &indices)); 2371 PetscCall(PetscSectionSetFieldConstraintIndices(*subs, subp, f, indices)); 2372 } 2373 PetscCall(PetscSectionGetConstraintIndices(s, points[subp - spStart], &indices)); 2374 PetscCall(PetscSectionSetConstraintIndices(*subs, subp, indices)); 2375 } 2376 } 2377 if (subpointIS) PetscCall(ISRestoreIndices(subpointIS, &points)); 2378 PetscCall(PetscFree2(spoints, order)); 2379 PetscFunctionReturn(PETSC_SUCCESS); 2380 } 2381 2382 /*@ 2383 PetscSectionCreateSubmeshSection - Create a new, smaller section with support on the submesh 2384 2385 Collective 2386 2387 Input Parameters: 2388 + s - the `PetscSection` 2389 - subpointIS - a sorted list of points in the original mesh which are in the submesh 2390 2391 Output Parameter: 2392 . subs - the subsection 2393 2394 Level: advanced 2395 2396 Notes: 2397 The points are renumbered from 0, and the section offsets now refer to a new, smaller vector. That is the chart of `subs` is `[0,sizeof(subpointmap))` 2398 2399 Compare this with `PetscSectionCreateSubdomainSection()` that does not map the points numbers to start at zero but leaves them as before 2400 2401 Developer Notes: 2402 The use of the term Submesh is confusing and needs clarification, it is not specific to meshes. It appears to be just a subset of the chart of the original `PetscSection` 2403 2404 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreateSubdomainSection()`, `PetscSectionCreateSubsection()`, `DMPlexGetSubpointMap()`, `PetscSectionCreate()` 2405 @*/ 2406 PetscErrorCode PetscSectionCreateSubmeshSection(PetscSection s, IS subpointIS, PetscSection *subs) 2407 { 2408 PetscFunctionBegin; 2409 PetscCall(PetscSectionCreateSubplexSection_Private(s, subpointIS, PETSC_TRUE, subs)); 2410 PetscFunctionReturn(PETSC_SUCCESS); 2411 } 2412 2413 /*@ 2414 PetscSectionCreateSubdomainSection - Create a new, smaller section with support on a subdomain of the mesh 2415 2416 Collective 2417 2418 Input Parameters: 2419 + s - the `PetscSection` 2420 - subpointMap - a sorted list of points in the original mesh which are in the subdomain 2421 2422 Output Parameter: 2423 . subs - the subsection 2424 2425 Level: advanced 2426 2427 Notes: 2428 The point numbers remain the same as in the larger `PetscSection`, but the section offsets now refer to a new, smaller vector. The chart of `subs` 2429 is `[min(subpointMap),max(subpointMap)+1)` 2430 2431 Compare this with `PetscSectionCreateSubmeshSection()` that maps the point numbers to start at zero 2432 2433 Developer Notes: 2434 The use of the term Subdomain is unneeded and needs clarification, it is not specific to meshes. It appears to be just a subset of the chart of the original `PetscSection` 2435 2436 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreateSubmeshSection()`, `PetscSectionCreateSubsection()`, `DMPlexGetSubpointMap()`, `PetscSectionCreate()` 2437 @*/ 2438 PetscErrorCode PetscSectionCreateSubdomainSection(PetscSection s, IS subpointMap, PetscSection *subs) 2439 { 2440 PetscFunctionBegin; 2441 PetscCall(PetscSectionCreateSubplexSection_Private(s, subpointMap, PETSC_FALSE, subs)); 2442 PetscFunctionReturn(PETSC_SUCCESS); 2443 } 2444 2445 static PetscErrorCode PetscSectionView_ASCII(PetscSection s, PetscViewer viewer) 2446 { 2447 PetscInt p; 2448 PetscMPIInt rank; 2449 2450 PetscFunctionBegin; 2451 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 2452 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 2453 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 2454 for (p = 0; p < s->pEnd - s->pStart; ++p) { 2455 if (s->bc && s->bc->atlasDof[p] > 0) { 2456 PetscInt b; 2457 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT " constrained", p + s->pStart, s->atlasDof[p], s->atlasOff[p])); 2458 if (s->bcIndices) { 2459 for (b = 0; b < s->bc->atlasDof[p]; ++b) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, s->bcIndices[s->bc->atlasOff[p] + b])); 2460 } 2461 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 2462 } else { 2463 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT "\n", p + s->pStart, s->atlasDof[p], s->atlasOff[p])); 2464 } 2465 } 2466 PetscCall(PetscViewerFlush(viewer)); 2467 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 2468 if (s->sym) { 2469 PetscCall(PetscViewerASCIIPushTab(viewer)); 2470 PetscCall(PetscSectionSymView(s->sym, viewer)); 2471 PetscCall(PetscViewerASCIIPopTab(viewer)); 2472 } 2473 PetscFunctionReturn(PETSC_SUCCESS); 2474 } 2475 2476 /*@ 2477 PetscSectionViewFromOptions - View the `PetscSection` based on values in the options database 2478 2479 Collective 2480 2481 Input Parameters: 2482 + A - the `PetscSection` object to view 2483 . obj - Optional object that provides the options prefix used for the options 2484 - name - command line option 2485 2486 Level: intermediate 2487 2488 Note: 2489 See `PetscObjectViewFromOptions()` for available values of `PetscViewer` and `PetscViewerFormat` 2490 2491 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionView`, `PetscObjectViewFromOptions()`, `PetscSectionCreate()`, `PetscSectionView()` 2492 @*/ 2493 PetscErrorCode PetscSectionViewFromOptions(PetscSection A, PetscObject obj, const char name[]) 2494 { 2495 PetscFunctionBegin; 2496 PetscValidHeaderSpecific(A, PETSC_SECTION_CLASSID, 1); 2497 PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name)); 2498 PetscFunctionReturn(PETSC_SUCCESS); 2499 } 2500 2501 /*@ 2502 PetscSectionView - Views a `PetscSection` 2503 2504 Collective 2505 2506 Input Parameters: 2507 + s - the `PetscSection` object to view 2508 - viewer - the viewer 2509 2510 Level: beginner 2511 2512 Note: 2513 `PetscSectionView()`, when viewer is of type `PETSCVIEWERHDF5`, only saves 2514 distribution independent data, such as dofs, offsets, constraint dofs, 2515 and constraint indices. Points that have negative dofs, for instance, 2516 are not saved as they represent points owned by other processes. 2517 Point numbering and rank assignment is currently not stored. 2518 The saved section can be loaded with `PetscSectionLoad()`. 2519 2520 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`, `PetscSectionLoad()`, `PetscViewer` 2521 @*/ 2522 PetscErrorCode PetscSectionView(PetscSection s, PetscViewer viewer) 2523 { 2524 PetscBool isascii, ishdf5; 2525 PetscInt f; 2526 2527 PetscFunctionBegin; 2528 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2529 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)s), &viewer)); 2530 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2531 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 2532 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2533 if (isascii) { 2534 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)s, viewer)); 2535 if (s->numFields) { 2536 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " fields\n", s->numFields)); 2537 for (f = 0; f < s->numFields; ++f) { 2538 PetscCall(PetscViewerASCIIPrintf(viewer, " field %" PetscInt_FMT " \"%s\" with %" PetscInt_FMT " components\n", f, s->fieldNames[f], s->numFieldComponents[f])); 2539 PetscCall(PetscSectionView_ASCII(s->field[f], viewer)); 2540 } 2541 } else { 2542 PetscCall(PetscSectionView_ASCII(s, viewer)); 2543 } 2544 } else if (ishdf5) { 2545 #if PetscDefined(HAVE_HDF5) 2546 PetscCall(PetscSectionView_HDF5_Internal(s, viewer)); 2547 #else 2548 SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2549 #endif 2550 } 2551 PetscFunctionReturn(PETSC_SUCCESS); 2552 } 2553 2554 /*@ 2555 PetscSectionLoad - Loads a `PetscSection` 2556 2557 Collective 2558 2559 Input Parameters: 2560 + s - the `PetscSection` object to load 2561 - viewer - the viewer 2562 2563 Level: beginner 2564 2565 Note: 2566 `PetscSectionLoad()`, when viewer is of type `PETSCVIEWERHDF5`, loads 2567 a section saved with `PetscSectionView()`. The number of processes 2568 used here (N) does not need to be the same as that used when saving. 2569 After calling this function, the chart of s on rank i will be set 2570 to [0, E_i), where \sum_{i=0}^{N-1}E_i equals to the total number of 2571 saved section points. 2572 2573 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`, `PetscSectionView()` 2574 @*/ 2575 PetscErrorCode PetscSectionLoad(PetscSection s, PetscViewer viewer) 2576 { 2577 PetscBool ishdf5; 2578 2579 PetscFunctionBegin; 2580 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2581 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2582 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2583 if (ishdf5) { 2584 #if PetscDefined(HAVE_HDF5) 2585 PetscCall(PetscSectionLoad_HDF5_Internal(s, viewer)); 2586 PetscFunctionReturn(PETSC_SUCCESS); 2587 #else 2588 SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2589 #endif 2590 } else SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "Viewer type %s not yet supported for PetscSection loading", ((PetscObject)viewer)->type_name); 2591 } 2592 2593 /*@ 2594 PetscSectionResetClosurePermutation - Remove any existing closure permutation 2595 2596 Input Parameter: 2597 . section - The `PetscSection` 2598 2599 Level: intermediate 2600 2601 .seealso: `PetscSectionSetClosurePermutation()`, `PetscSectionSetClosureIndex()`, `PetscSectionReset()` 2602 @*/ 2603 PetscErrorCode PetscSectionResetClosurePermutation(PetscSection section) 2604 { 2605 PetscSectionClosurePermVal clVal; 2606 2607 PetscFunctionBegin; 2608 if (!section->clHash) PetscFunctionReturn(PETSC_SUCCESS); 2609 kh_foreach_value(section->clHash, clVal, { 2610 PetscCall(PetscFree(clVal.perm)); 2611 PetscCall(PetscFree(clVal.invPerm)); 2612 }); 2613 kh_destroy(ClPerm, section->clHash); 2614 section->clHash = NULL; 2615 PetscFunctionReturn(PETSC_SUCCESS); 2616 } 2617 2618 /*@ 2619 PetscSectionReset - Frees all section data, the section is then as if `PetscSectionCreate()` had just been called. 2620 2621 Not Collective 2622 2623 Input Parameter: 2624 . s - the `PetscSection` 2625 2626 Level: beginner 2627 2628 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()` 2629 @*/ 2630 PetscErrorCode PetscSectionReset(PetscSection s) 2631 { 2632 PetscInt f, c; 2633 2634 PetscFunctionBegin; 2635 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2636 for (f = 0; f < s->numFields; ++f) { 2637 PetscCall(PetscSectionDestroy(&s->field[f])); 2638 PetscCall(PetscFree(s->fieldNames[f])); 2639 for (c = 0; c < s->numFieldComponents[f]; ++c) PetscCall(PetscFree(s->compNames[f][c])); 2640 PetscCall(PetscFree(s->compNames[f])); 2641 } 2642 PetscCall(PetscFree(s->numFieldComponents)); 2643 PetscCall(PetscFree(s->fieldNames)); 2644 PetscCall(PetscFree(s->compNames)); 2645 PetscCall(PetscFree(s->field)); 2646 PetscCall(PetscSectionDestroy(&s->bc)); 2647 PetscCall(PetscFree(s->bcIndices)); 2648 PetscCall(PetscFree2(s->atlasDof, s->atlasOff)); 2649 PetscCall(PetscSectionDestroy(&s->clSection)); 2650 PetscCall(ISDestroy(&s->clPoints)); 2651 PetscCall(ISDestroy(&s->perm)); 2652 PetscCall(PetscBTDestroy(&s->blockStarts)); 2653 PetscCall(PetscSectionResetClosurePermutation(s)); 2654 PetscCall(PetscSectionSymDestroy(&s->sym)); 2655 PetscCall(PetscSectionDestroy(&s->clSection)); 2656 PetscCall(ISDestroy(&s->clPoints)); 2657 PetscCall(PetscSectionInvalidateMaxDof_Internal(s)); 2658 s->pStart = -1; 2659 s->pEnd = -1; 2660 s->maxDof = 0; 2661 s->setup = PETSC_FALSE; 2662 s->numFields = 0; 2663 s->clObj = NULL; 2664 PetscFunctionReturn(PETSC_SUCCESS); 2665 } 2666 2667 /*@ 2668 PetscSectionDestroy - Frees a `PetscSection` 2669 2670 Not Collective 2671 2672 Input Parameter: 2673 . s - the `PetscSection` 2674 2675 Level: beginner 2676 2677 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionReset()` 2678 @*/ 2679 PetscErrorCode PetscSectionDestroy(PetscSection *s) 2680 { 2681 PetscFunctionBegin; 2682 if (!*s) PetscFunctionReturn(PETSC_SUCCESS); 2683 PetscValidHeaderSpecific(*s, PETSC_SECTION_CLASSID, 1); 2684 if (--((PetscObject)*s)->refct > 0) { 2685 *s = NULL; 2686 PetscFunctionReturn(PETSC_SUCCESS); 2687 } 2688 PetscCall(PetscSectionReset(*s)); 2689 PetscCall(PetscHeaderDestroy(s)); 2690 PetscFunctionReturn(PETSC_SUCCESS); 2691 } 2692 2693 static PetscErrorCode VecIntGetValuesSection_Private(const PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt **values) 2694 { 2695 const PetscInt p = point - s->pStart; 2696 2697 PetscFunctionBegin; 2698 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2); 2699 *values = &baseArray[s->atlasOff[p]]; 2700 PetscFunctionReturn(PETSC_SUCCESS); 2701 } 2702 2703 static PetscErrorCode VecIntSetValuesSection_Private(PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt values[], InsertMode mode) 2704 { 2705 PetscInt *array; 2706 const PetscInt p = point - s->pStart; 2707 const PetscInt orientation = 0; /* Needs to be included for use in closure operations */ 2708 PetscInt cDim = 0; 2709 2710 PetscFunctionBegin; 2711 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2); 2712 PetscCall(PetscSectionGetConstraintDof(s, p, &cDim)); 2713 array = &baseArray[s->atlasOff[p]]; 2714 if (!cDim) { 2715 if (orientation >= 0) { 2716 const PetscInt dim = s->atlasDof[p]; 2717 PetscInt i; 2718 2719 if (mode == INSERT_VALUES) { 2720 for (i = 0; i < dim; ++i) array[i] = values ? values[i] : i; 2721 } else { 2722 for (i = 0; i < dim; ++i) array[i] += values[i]; 2723 } 2724 } else { 2725 PetscInt offset = 0; 2726 PetscInt j = -1, field, i; 2727 2728 for (field = 0; field < s->numFields; ++field) { 2729 const PetscInt dim = s->field[field]->atlasDof[p]; 2730 2731 for (i = dim - 1; i >= 0; --i) array[++j] = values ? values[i + offset] : i + offset; 2732 offset += dim; 2733 } 2734 } 2735 } else { 2736 if (orientation >= 0) { 2737 const PetscInt dim = s->atlasDof[p]; 2738 PetscInt cInd = 0, i; 2739 const PetscInt *cDof; 2740 2741 PetscCall(PetscSectionGetConstraintIndices(s, point, &cDof)); 2742 if (mode == INSERT_VALUES) { 2743 for (i = 0; i < dim; ++i) { 2744 if ((cInd < cDim) && (i == cDof[cInd])) { 2745 ++cInd; 2746 continue; 2747 } 2748 array[i] = values ? values[i] : i; 2749 } 2750 } else { 2751 for (i = 0; i < dim; ++i) { 2752 if ((cInd < cDim) && (i == cDof[cInd])) { 2753 ++cInd; 2754 continue; 2755 } 2756 array[i] += values[i]; 2757 } 2758 } 2759 } else { 2760 const PetscInt *cDof; 2761 PetscInt offset = 0; 2762 PetscInt cOffset = 0; 2763 PetscInt j = 0, field; 2764 2765 PetscCall(PetscSectionGetConstraintIndices(s, point, &cDof)); 2766 for (field = 0; field < s->numFields; ++field) { 2767 const PetscInt dim = s->field[field]->atlasDof[p]; /* PetscSectionGetFieldDof() */ 2768 const PetscInt tDim = s->field[field]->bc->atlasDof[p]; /* PetscSectionGetFieldConstraintDof() */ 2769 const PetscInt sDim = dim - tDim; 2770 PetscInt cInd = 0, i, k; 2771 2772 for (i = 0, k = dim + offset - 1; i < dim; ++i, ++j, --k) { 2773 if ((cInd < sDim) && (j == cDof[cInd + cOffset])) { 2774 ++cInd; 2775 continue; 2776 } 2777 array[j] = values ? values[k] : k; 2778 } 2779 offset += dim; 2780 cOffset += dim - tDim; 2781 } 2782 } 2783 } 2784 PetscFunctionReturn(PETSC_SUCCESS); 2785 } 2786 2787 /*@ 2788 PetscSectionHasConstraints - Determine whether a `PetscSection` has constrained dofs 2789 2790 Not Collective 2791 2792 Input Parameter: 2793 . s - The `PetscSection` 2794 2795 Output Parameter: 2796 . hasConstraints - flag indicating that the section has constrained dofs 2797 2798 Level: intermediate 2799 2800 .seealso: [PetscSection](ch_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2801 @*/ 2802 PetscErrorCode PetscSectionHasConstraints(PetscSection s, PetscBool *hasConstraints) 2803 { 2804 PetscFunctionBegin; 2805 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2806 PetscAssertPointer(hasConstraints, 2); 2807 *hasConstraints = s->bc ? PETSC_TRUE : PETSC_FALSE; 2808 PetscFunctionReturn(PETSC_SUCCESS); 2809 } 2810 2811 /*@C 2812 PetscSectionGetConstraintIndices - Get the point dof numbers, in [0, dof), which are constrained for a given point 2813 2814 Not Collective 2815 2816 Input Parameters: 2817 + s - The `PetscSection` 2818 - point - The point 2819 2820 Output Parameter: 2821 . indices - The constrained dofs 2822 2823 Level: intermediate 2824 2825 Fortran Notes: 2826 Use `PetscSectionRestoreConstraintIndices()` when the indices are no longer needed 2827 2828 .seealso: [PetscSection](ch_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2829 @*/ 2830 PetscErrorCode PetscSectionGetConstraintIndices(PetscSection s, PetscInt point, const PetscInt *indices[]) 2831 { 2832 PetscFunctionBegin; 2833 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2834 if (s->bc) { 2835 PetscCall(VecIntGetValuesSection_Private(s->bcIndices, s->bc, point, indices)); 2836 } else *indices = NULL; 2837 PetscFunctionReturn(PETSC_SUCCESS); 2838 } 2839 2840 /*@ 2841 PetscSectionSetConstraintIndices - Set the point dof numbers, in [0, dof), which are constrained 2842 2843 Not Collective 2844 2845 Input Parameters: 2846 + s - The `PetscSection` 2847 . point - The point 2848 - indices - The constrained dofs 2849 2850 Level: intermediate 2851 2852 .seealso: [PetscSection](ch_petscsection), `PetscSectionGetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2853 @*/ 2854 PetscErrorCode PetscSectionSetConstraintIndices(PetscSection s, PetscInt point, const PetscInt indices[]) 2855 { 2856 PetscFunctionBegin; 2857 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2858 if (s->bc) { 2859 const PetscInt dof = s->atlasDof[point]; 2860 const PetscInt cdof = s->bc->atlasDof[point]; 2861 PetscInt d; 2862 2863 if (indices) 2864 for (d = 0; d < cdof; ++d) PetscCheck(indices[d] < dof, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " dof %" PetscInt_FMT ", invalid constraint index[%" PetscInt_FMT "]: %" PetscInt_FMT, point, dof, d, indices[d]); 2865 PetscCall(VecIntSetValuesSection_Private(s->bcIndices, s->bc, point, indices, INSERT_VALUES)); 2866 } 2867 PetscFunctionReturn(PETSC_SUCCESS); 2868 } 2869 2870 /*@C 2871 PetscSectionGetFieldConstraintIndices - Get the field dof numbers, in [0, fdof), which are constrained 2872 2873 Not Collective 2874 2875 Input Parameters: 2876 + s - The `PetscSection` 2877 . field - The field number 2878 - point - The point 2879 2880 Output Parameter: 2881 . indices - The constrained dofs sorted in ascending order, the length is returned by `PetscSectionGetConstraintDof()`. 2882 2883 Level: intermediate 2884 2885 Fortran Notes: 2886 Use `PetscSectionRestoreFieldConstraintIndices()` to restore the indices when no longer needed 2887 2888 .seealso: [PetscSection](ch_petscsection), `PetscSectionSetFieldConstraintIndices()`, `PetscSectionGetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2889 @*/ 2890 PetscErrorCode PetscSectionGetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt *indices[]) 2891 { 2892 PetscFunctionBegin; 2893 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2894 PetscAssertPointer(indices, 4); 2895 PetscSectionCheckValidField(field, s->numFields); 2896 PetscCall(PetscSectionGetConstraintIndices(s->field[field], point, indices)); 2897 PetscFunctionReturn(PETSC_SUCCESS); 2898 } 2899 2900 /*@ 2901 PetscSectionSetFieldConstraintIndices - Set the field dof numbers, in [0, fdof), which are constrained 2902 2903 Not Collective 2904 2905 Input Parameters: 2906 + s - The `PetscSection` 2907 . point - The point 2908 . field - The field number 2909 - indices - The constrained dofs 2910 2911 Level: intermediate 2912 2913 .seealso: [PetscSection](ch_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetFieldConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2914 @*/ 2915 PetscErrorCode PetscSectionSetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt indices[]) 2916 { 2917 PetscFunctionBegin; 2918 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2919 PetscSectionCheckValidField(field, s->numFields); 2920 PetscCall(PetscSectionSetConstraintIndices(s->field[field], point, indices)); 2921 PetscFunctionReturn(PETSC_SUCCESS); 2922 } 2923 2924 /*@ 2925 PetscSectionPermute - Reorder the section according to the input point permutation 2926 2927 Collective 2928 2929 Input Parameters: 2930 + section - The `PetscSection` object 2931 - permutation - The point permutation, old point p becomes new point perm[p] 2932 2933 Output Parameter: 2934 . sectionNew - The permuted `PetscSection` 2935 2936 Level: intermediate 2937 2938 Note: 2939 The data and the access to the data via `PetscSectionGetFieldOffset()` and `PetscSectionGetOffset()` are both changed in `sectionNew` 2940 2941 Compare to `PetscSectionSetPermutation()` 2942 2943 .seealso: [PetscSection](ch_petscsection), `IS`, `PetscSection`, `MatPermute()`, `PetscSectionSetPermutation()` 2944 @*/ 2945 PetscErrorCode PetscSectionPermute(PetscSection section, IS permutation, PetscSection *sectionNew) 2946 { 2947 PetscSection s = section, sNew; 2948 const PetscInt *perm; 2949 PetscInt numFields, f, c, numPoints, pStart, pEnd, p; 2950 2951 PetscFunctionBegin; 2952 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 2953 PetscValidHeaderSpecific(permutation, IS_CLASSID, 2); 2954 PetscAssertPointer(sectionNew, 3); 2955 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), &sNew)); 2956 PetscCall(PetscSectionGetNumFields(s, &numFields)); 2957 if (numFields) PetscCall(PetscSectionSetNumFields(sNew, numFields)); 2958 for (f = 0; f < numFields; ++f) { 2959 const char *name; 2960 PetscInt numComp; 2961 2962 PetscCall(PetscSectionGetFieldName(s, f, &name)); 2963 PetscCall(PetscSectionSetFieldName(sNew, f, name)); 2964 PetscCall(PetscSectionGetFieldComponents(s, f, &numComp)); 2965 PetscCall(PetscSectionSetFieldComponents(sNew, f, numComp)); 2966 for (c = 0; c < s->numFieldComponents[f]; ++c) { 2967 PetscCall(PetscSectionGetComponentName(s, f, c, &name)); 2968 PetscCall(PetscSectionSetComponentName(sNew, f, c, name)); 2969 } 2970 } 2971 PetscCall(ISGetLocalSize(permutation, &numPoints)); 2972 PetscCall(ISGetIndices(permutation, &perm)); 2973 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 2974 PetscCall(PetscSectionSetChart(sNew, pStart, pEnd)); 2975 PetscCheck(numPoints >= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Permutation size %" PetscInt_FMT " is less than largest Section point %" PetscInt_FMT, numPoints, pEnd); 2976 for (p = pStart; p < pEnd; ++p) { 2977 PetscInt dof, cdof; 2978 2979 PetscCall(PetscSectionGetDof(s, p, &dof)); 2980 PetscCall(PetscSectionSetDof(sNew, perm[p], dof)); 2981 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 2982 if (cdof) PetscCall(PetscSectionSetConstraintDof(sNew, perm[p], cdof)); 2983 for (f = 0; f < numFields; ++f) { 2984 PetscCall(PetscSectionGetFieldDof(s, p, f, &dof)); 2985 PetscCall(PetscSectionSetFieldDof(sNew, perm[p], f, dof)); 2986 PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof)); 2987 if (cdof) PetscCall(PetscSectionSetFieldConstraintDof(sNew, perm[p], f, cdof)); 2988 } 2989 } 2990 PetscCall(PetscSectionSetUp(sNew)); 2991 for (p = pStart; p < pEnd; ++p) { 2992 const PetscInt *cind; 2993 PetscInt cdof; 2994 2995 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 2996 if (cdof) { 2997 PetscCall(PetscSectionGetConstraintIndices(s, p, &cind)); 2998 PetscCall(PetscSectionSetConstraintIndices(sNew, perm[p], cind)); 2999 } 3000 for (f = 0; f < numFields; ++f) { 3001 PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof)); 3002 if (cdof) { 3003 PetscCall(PetscSectionGetFieldConstraintIndices(s, p, f, &cind)); 3004 PetscCall(PetscSectionSetFieldConstraintIndices(sNew, perm[p], f, cind)); 3005 } 3006 } 3007 } 3008 PetscCall(ISRestoreIndices(permutation, &perm)); 3009 *sectionNew = sNew; 3010 PetscFunctionReturn(PETSC_SUCCESS); 3011 } 3012 3013 /*@ 3014 PetscSectionSetClosureIndex - Create an internal data structure to speed up closure queries. 3015 3016 Collective 3017 3018 Input Parameters: 3019 + section - The `PetscSection` 3020 . obj - A `PetscObject` which serves as the key for this index 3021 . clSection - `PetscSection` giving the size of the closure of each point 3022 - clPoints - `IS` giving the points in each closure 3023 3024 Level: advanced 3025 3026 Note: 3027 This function creates an internal map from each point to its closure. We compress out closure points with no dofs in this section. 3028 3029 Developer Notes: 3030 The information provided here is completely opaque 3031 3032 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetClosureIndex()`, `DMPlexCreateClosureIndex()` 3033 @*/ 3034 PetscErrorCode PetscSectionSetClosureIndex(PetscSection section, PetscObject obj, PetscSection clSection, IS clPoints) 3035 { 3036 PetscFunctionBegin; 3037 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3038 PetscValidHeaderSpecific(clSection, PETSC_SECTION_CLASSID, 3); 3039 PetscValidHeaderSpecific(clPoints, IS_CLASSID, 4); 3040 if (section->clObj != obj) PetscCall(PetscSectionResetClosurePermutation(section)); 3041 section->clObj = obj; 3042 PetscCall(PetscObjectReference((PetscObject)clSection)); 3043 PetscCall(PetscObjectReference((PetscObject)clPoints)); 3044 PetscCall(PetscSectionDestroy(§ion->clSection)); 3045 PetscCall(ISDestroy(§ion->clPoints)); 3046 section->clSection = clSection; 3047 section->clPoints = clPoints; 3048 PetscFunctionReturn(PETSC_SUCCESS); 3049 } 3050 3051 /*@ 3052 PetscSectionGetClosureIndex - Get the cache of points in the closure of each point in the section set with `PetscSectionSetClosureIndex()` 3053 3054 Collective 3055 3056 Input Parameters: 3057 + section - The `PetscSection` 3058 - obj - A `PetscObject` which serves as the key for this index 3059 3060 Output Parameters: 3061 + clSection - `PetscSection` giving the size of the closure of each point 3062 - clPoints - `IS` giving the points in each closure 3063 3064 Level: advanced 3065 3066 .seealso: [PetscSection](ch_petscsection), `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()` 3067 @*/ 3068 PetscErrorCode PetscSectionGetClosureIndex(PetscSection section, PetscObject obj, PetscSection *clSection, IS *clPoints) 3069 { 3070 PetscFunctionBegin; 3071 if (section->clObj == obj) { 3072 if (clSection) *clSection = section->clSection; 3073 if (clPoints) *clPoints = section->clPoints; 3074 } else { 3075 if (clSection) *clSection = NULL; 3076 if (clPoints) *clPoints = NULL; 3077 } 3078 PetscFunctionReturn(PETSC_SUCCESS); 3079 } 3080 3081 PetscErrorCode PetscSectionSetClosurePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, PetscCopyMode mode, PetscInt *clPerm) 3082 { 3083 PetscInt i; 3084 khiter_t iter; 3085 int new_entry; 3086 PetscSectionClosurePermKey key = {depth, clSize}; 3087 PetscSectionClosurePermVal *val; 3088 3089 PetscFunctionBegin; 3090 if (section->clObj != obj) { 3091 PetscCall(PetscSectionDestroy(§ion->clSection)); 3092 PetscCall(ISDestroy(§ion->clPoints)); 3093 } 3094 section->clObj = obj; 3095 if (!section->clHash) PetscCall(PetscClPermCreate(§ion->clHash)); 3096 iter = kh_put(ClPerm, section->clHash, key, &new_entry); 3097 val = &kh_val(section->clHash, iter); 3098 if (!new_entry) { 3099 PetscCall(PetscFree(val->perm)); 3100 PetscCall(PetscFree(val->invPerm)); 3101 } 3102 if (mode == PETSC_COPY_VALUES) { 3103 PetscCall(PetscMalloc1(clSize, &val->perm)); 3104 PetscCall(PetscArraycpy(val->perm, clPerm, clSize)); 3105 } else if (mode == PETSC_OWN_POINTER) { 3106 val->perm = clPerm; 3107 } else SETERRQ(PetscObjectComm(obj), PETSC_ERR_SUP, "Do not support borrowed arrays"); 3108 PetscCall(PetscMalloc1(clSize, &val->invPerm)); 3109 for (i = 0; i < clSize; ++i) val->invPerm[clPerm[i]] = i; 3110 PetscFunctionReturn(PETSC_SUCCESS); 3111 } 3112 3113 /*@ 3114 PetscSectionSetClosurePermutation - Set the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex. 3115 3116 Not Collective 3117 3118 Input Parameters: 3119 + section - The `PetscSection` 3120 . obj - A `PetscObject` which serves as the key for this index (usually a `DM`) 3121 . depth - Depth of points on which to apply the given permutation 3122 - perm - Permutation of the cell dof closure 3123 3124 Level: intermediate 3125 3126 Notes: 3127 The specified permutation will only be applied to points at depth whose closure size matches the length of perm. In a 3128 mixed-topology or variable-degree finite element space, this function can be called multiple times at each depth for 3129 each topology and degree. 3130 3131 This approach assumes that (depth, len(perm)) uniquely identifies the desired permutation; this might not be true for 3132 exotic/enriched spaces on mixed topology meshes. 3133 3134 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `IS`, `PetscSectionGetClosurePermutation()`, `PetscSectionGetClosureIndex()`, `DMPlexCreateClosureIndex()`, `PetscCopyMode` 3135 @*/ 3136 PetscErrorCode PetscSectionSetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, IS perm) 3137 { 3138 const PetscInt *clPerm = NULL; 3139 PetscInt clSize = 0; 3140 3141 PetscFunctionBegin; 3142 if (perm) { 3143 PetscCall(ISGetLocalSize(perm, &clSize)); 3144 PetscCall(ISGetIndices(perm, &clPerm)); 3145 } 3146 PetscCall(PetscSectionSetClosurePermutation_Internal(section, obj, depth, clSize, PETSC_COPY_VALUES, (PetscInt *)clPerm)); 3147 if (perm) PetscCall(ISRestoreIndices(perm, &clPerm)); 3148 PetscFunctionReturn(PETSC_SUCCESS); 3149 } 3150 3151 static PetscErrorCode PetscSectionGetClosurePermutation_Private(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[]) 3152 { 3153 PetscFunctionBegin; 3154 if (section->clObj == obj) { 3155 PetscSectionClosurePermKey k = {depth, size}; 3156 PetscSectionClosurePermVal v; 3157 3158 PetscCall(PetscClPermGet(section->clHash, k, &v)); 3159 if (perm) *perm = v.perm; 3160 } else { 3161 if (perm) *perm = NULL; 3162 } 3163 PetscFunctionReturn(PETSC_SUCCESS); 3164 } 3165 3166 /*@ 3167 PetscSectionGetClosurePermutation - Get the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex. 3168 3169 Not Collective 3170 3171 Input Parameters: 3172 + section - The `PetscSection` 3173 . obj - A `PetscObject` which serves as the key for this index (usually a DM) 3174 . depth - Depth stratum on which to obtain closure permutation 3175 - clSize - Closure size to be permuted (e.g., may vary with element topology and degree) 3176 3177 Output Parameter: 3178 . perm - The dof closure permutation 3179 3180 Level: intermediate 3181 3182 Note: 3183 The user must destroy the `IS` that is returned. 3184 3185 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `IS`, `PetscSectionSetClosurePermutation()`, `PetscSectionGetClosureInversePermutation()`, `PetscSectionGetClosureIndex()`, `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()` 3186 @*/ 3187 PetscErrorCode PetscSectionGetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm) 3188 { 3189 const PetscInt *clPerm = NULL; 3190 3191 PetscFunctionBegin; 3192 PetscCall(PetscSectionGetClosurePermutation_Private(section, obj, depth, clSize, &clPerm)); 3193 PetscCheck(clPerm, PetscObjectComm(obj), PETSC_ERR_ARG_WRONG, "There is no closure permutation associated with this object for depth %" PetscInt_FMT " of size %" PetscInt_FMT, depth, clSize); 3194 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm)); 3195 PetscFunctionReturn(PETSC_SUCCESS); 3196 } 3197 3198 PetscErrorCode PetscSectionGetClosureInversePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[]) 3199 { 3200 PetscFunctionBegin; 3201 if (section->clObj == obj && section->clHash) { 3202 PetscSectionClosurePermKey k = {depth, size}; 3203 PetscSectionClosurePermVal v; 3204 PetscCall(PetscClPermGet(section->clHash, k, &v)); 3205 if (perm) *perm = v.invPerm; 3206 } else { 3207 if (perm) *perm = NULL; 3208 } 3209 PetscFunctionReturn(PETSC_SUCCESS); 3210 } 3211 3212 /*@ 3213 PetscSectionGetClosureInversePermutation - Get the inverse dof permutation for the closure of each cell in the section, meaning clPerm[oldIndex] = newIndex. 3214 3215 Not Collective 3216 3217 Input Parameters: 3218 + section - The `PetscSection` 3219 . obj - A `PetscObject` which serves as the key for this index (usually a `DM`) 3220 . depth - Depth stratum on which to obtain closure permutation 3221 - clSize - Closure size to be permuted (e.g., may vary with element topology and degree) 3222 3223 Output Parameter: 3224 . perm - The dof closure permutation 3225 3226 Level: intermediate 3227 3228 Note: 3229 The user must destroy the `IS` that is returned. 3230 3231 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `IS`, `PetscSectionSetClosurePermutation()`, `PetscSectionGetClosureIndex()`, `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()` 3232 @*/ 3233 PetscErrorCode PetscSectionGetClosureInversePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm) 3234 { 3235 const PetscInt *clPerm = NULL; 3236 3237 PetscFunctionBegin; 3238 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, obj, depth, clSize, &clPerm)); 3239 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm)); 3240 PetscFunctionReturn(PETSC_SUCCESS); 3241 } 3242 3243 /*@ 3244 PetscSectionGetField - Get the `PetscSection` associated with a single field 3245 3246 Input Parameters: 3247 + s - The `PetscSection` 3248 - field - The field number 3249 3250 Output Parameter: 3251 . subs - The `PetscSection` for the given field, note the chart of `subs` is not set 3252 3253 Level: intermediate 3254 3255 Note: 3256 Does not increase the reference count of the selected sub-section. There is no matching `PetscSectionRestoreField()` 3257 3258 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `IS`, `PetscSectionSetNumFields()` 3259 @*/ 3260 PetscErrorCode PetscSectionGetField(PetscSection s, PetscInt field, PetscSection *subs) 3261 { 3262 PetscFunctionBegin; 3263 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 3264 PetscAssertPointer(subs, 3); 3265 PetscSectionCheckValidField(field, s->numFields); 3266 *subs = s->field[field]; 3267 PetscFunctionReturn(PETSC_SUCCESS); 3268 } 3269 3270 PetscClassId PETSC_SECTION_SYM_CLASSID; 3271 PetscFunctionList PetscSectionSymList = NULL; 3272 3273 /*@ 3274 PetscSectionSymCreate - Creates an empty `PetscSectionSym` object. 3275 3276 Collective 3277 3278 Input Parameter: 3279 . comm - the MPI communicator 3280 3281 Output Parameter: 3282 . sym - pointer to the new set of symmetries 3283 3284 Level: developer 3285 3286 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSym`, `PetscSectionSymDestroy()` 3287 @*/ 3288 PetscErrorCode PetscSectionSymCreate(MPI_Comm comm, PetscSectionSym *sym) 3289 { 3290 PetscFunctionBegin; 3291 PetscAssertPointer(sym, 2); 3292 PetscCall(ISInitializePackage()); 3293 3294 PetscCall(PetscHeaderCreate(*sym, PETSC_SECTION_SYM_CLASSID, "PetscSectionSym", "Section Symmetry", "IS", comm, PetscSectionSymDestroy, PetscSectionSymView)); 3295 PetscFunctionReturn(PETSC_SUCCESS); 3296 } 3297 3298 /*@ 3299 PetscSectionSymSetType - Builds a `PetscSectionSym`, for a particular implementation. 3300 3301 Collective 3302 3303 Input Parameters: 3304 + sym - The section symmetry object 3305 - method - The name of the section symmetry type 3306 3307 Level: developer 3308 3309 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymGetType()`, `PetscSectionSymCreate()` 3310 @*/ 3311 PetscErrorCode PetscSectionSymSetType(PetscSectionSym sym, PetscSectionSymType method) 3312 { 3313 PetscErrorCode (*r)(PetscSectionSym); 3314 PetscBool match; 3315 3316 PetscFunctionBegin; 3317 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3318 PetscCall(PetscObjectTypeCompare((PetscObject)sym, method, &match)); 3319 if (match) PetscFunctionReturn(PETSC_SUCCESS); 3320 3321 PetscCall(PetscFunctionListFind(PetscSectionSymList, method, &r)); 3322 PetscCheck(r, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscSectionSym type: %s", method); 3323 PetscTryTypeMethod(sym, destroy); 3324 sym->ops->destroy = NULL; 3325 3326 PetscCall((*r)(sym)); 3327 PetscCall(PetscObjectChangeTypeName((PetscObject)sym, method)); 3328 PetscFunctionReturn(PETSC_SUCCESS); 3329 } 3330 3331 /*@ 3332 PetscSectionSymGetType - Gets the section symmetry type name (as a string) from the `PetscSectionSym`. 3333 3334 Not Collective 3335 3336 Input Parameter: 3337 . sym - The section symmetry 3338 3339 Output Parameter: 3340 . type - The index set type name 3341 3342 Level: developer 3343 3344 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymSetType()`, `PetscSectionSymCreate()` 3345 @*/ 3346 PetscErrorCode PetscSectionSymGetType(PetscSectionSym sym, PetscSectionSymType *type) 3347 { 3348 PetscFunctionBegin; 3349 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3350 PetscAssertPointer(type, 2); 3351 *type = ((PetscObject)sym)->type_name; 3352 PetscFunctionReturn(PETSC_SUCCESS); 3353 } 3354 3355 /*@C 3356 PetscSectionSymRegister - Registers a new section symmetry implementation 3357 3358 Not Collective, No Fortran Support 3359 3360 Input Parameters: 3361 + sname - The name of a new user-defined creation routine 3362 - function - The creation routine itself 3363 3364 Level: developer 3365 3366 Notes: 3367 `PetscSectionSymRegister()` may be called multiple times to add several user-defined vectors 3368 3369 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymCreate()`, `PetscSectionSymSetType()` 3370 @*/ 3371 PetscErrorCode PetscSectionSymRegister(const char sname[], PetscErrorCode (*function)(PetscSectionSym)) 3372 { 3373 PetscFunctionBegin; 3374 PetscCall(ISInitializePackage()); 3375 PetscCall(PetscFunctionListAdd(&PetscSectionSymList, sname, function)); 3376 PetscFunctionReturn(PETSC_SUCCESS); 3377 } 3378 3379 /*@ 3380 PetscSectionSymDestroy - Destroys a section symmetry. 3381 3382 Collective 3383 3384 Input Parameter: 3385 . sym - the section symmetry 3386 3387 Level: developer 3388 3389 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()` 3390 @*/ 3391 PetscErrorCode PetscSectionSymDestroy(PetscSectionSym *sym) 3392 { 3393 SymWorkLink link, next; 3394 3395 PetscFunctionBegin; 3396 if (!*sym) PetscFunctionReturn(PETSC_SUCCESS); 3397 PetscValidHeaderSpecific(*sym, PETSC_SECTION_SYM_CLASSID, 1); 3398 if (--((PetscObject)*sym)->refct > 0) { 3399 *sym = NULL; 3400 PetscFunctionReturn(PETSC_SUCCESS); 3401 } 3402 PetscTryTypeMethod(*sym, destroy); 3403 PetscCheck(!(*sym)->workout, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Work array still checked out"); 3404 for (link = (*sym)->workin; link; link = next) { 3405 PetscInt **perms = (PetscInt **)link->perms; 3406 PetscScalar **rots = (PetscScalar **)link->rots; 3407 PetscCall(PetscFree2(perms, rots)); 3408 next = link->next; 3409 PetscCall(PetscFree(link)); 3410 } 3411 (*sym)->workin = NULL; 3412 PetscCall(PetscHeaderDestroy(sym)); 3413 PetscFunctionReturn(PETSC_SUCCESS); 3414 } 3415 3416 /*@ 3417 PetscSectionSymView - Displays a section symmetry 3418 3419 Collective 3420 3421 Input Parameters: 3422 + sym - the index set 3423 - viewer - viewer used to display the set, for example `PETSC_VIEWER_STDOUT_SELF`. 3424 3425 Level: developer 3426 3427 .seealso: `PetscSectionSym`, `PetscViewer`, `PetscViewerASCIIOpen()` 3428 @*/ 3429 PetscErrorCode PetscSectionSymView(PetscSectionSym sym, PetscViewer viewer) 3430 { 3431 PetscFunctionBegin; 3432 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3433 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sym), &viewer)); 3434 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 3435 PetscCheckSameComm(sym, 1, viewer, 2); 3436 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)sym, viewer)); 3437 PetscTryTypeMethod(sym, view, viewer); 3438 PetscFunctionReturn(PETSC_SUCCESS); 3439 } 3440 3441 /*@ 3442 PetscSectionSetSym - Set the symmetries for the data referred to by the section 3443 3444 Collective 3445 3446 Input Parameters: 3447 + section - the section describing data layout 3448 - sym - the symmetry describing the affect of orientation on the access of the data 3449 3450 Level: developer 3451 3452 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetSym()`, `PetscSectionSymCreate()` 3453 @*/ 3454 PetscErrorCode PetscSectionSetSym(PetscSection section, PetscSectionSym sym) 3455 { 3456 PetscFunctionBegin; 3457 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3458 PetscCall(PetscSectionSymDestroy(§ion->sym)); 3459 if (sym) { 3460 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 2); 3461 PetscCheckSameComm(section, 1, sym, 2); 3462 PetscCall(PetscObjectReference((PetscObject)sym)); 3463 } 3464 section->sym = sym; 3465 PetscFunctionReturn(PETSC_SUCCESS); 3466 } 3467 3468 /*@ 3469 PetscSectionGetSym - Get the symmetries for the data referred to by the section 3470 3471 Not Collective 3472 3473 Input Parameter: 3474 . section - the section describing data layout 3475 3476 Output Parameter: 3477 . sym - the symmetry describing the affect of orientation on the access of the data, provided previously by `PetscSectionSetSym()` 3478 3479 Level: developer 3480 3481 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSetSym()`, `PetscSectionSymCreate()` 3482 @*/ 3483 PetscErrorCode PetscSectionGetSym(PetscSection section, PetscSectionSym *sym) 3484 { 3485 PetscFunctionBegin; 3486 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3487 *sym = section->sym; 3488 PetscFunctionReturn(PETSC_SUCCESS); 3489 } 3490 3491 /*@ 3492 PetscSectionSetFieldSym - Set the symmetries for the data referred to by a field of the section 3493 3494 Collective 3495 3496 Input Parameters: 3497 + section - the section describing data layout 3498 . field - the field number 3499 - sym - the symmetry describing the affect of orientation on the access of the data 3500 3501 Level: developer 3502 3503 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetFieldSym()`, `PetscSectionSymCreate()` 3504 @*/ 3505 PetscErrorCode PetscSectionSetFieldSym(PetscSection section, PetscInt field, PetscSectionSym sym) 3506 { 3507 PetscFunctionBegin; 3508 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3509 PetscSectionCheckValidField(field, section->numFields); 3510 PetscCall(PetscSectionSetSym(section->field[field], sym)); 3511 PetscFunctionReturn(PETSC_SUCCESS); 3512 } 3513 3514 /*@ 3515 PetscSectionGetFieldSym - Get the symmetries for the data referred to by a field of the section 3516 3517 Collective 3518 3519 Input Parameters: 3520 + section - the section describing data layout 3521 - field - the field number 3522 3523 Output Parameter: 3524 . sym - the symmetry describing the affect of orientation on the access of the data 3525 3526 Level: developer 3527 3528 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSetFieldSym()`, `PetscSectionSymCreate()` 3529 @*/ 3530 PetscErrorCode PetscSectionGetFieldSym(PetscSection section, PetscInt field, PetscSectionSym *sym) 3531 { 3532 PetscFunctionBegin; 3533 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3534 PetscSectionCheckValidField(field, section->numFields); 3535 *sym = section->field[field]->sym; 3536 PetscFunctionReturn(PETSC_SUCCESS); 3537 } 3538 3539 /*@C 3540 PetscSectionGetPointSyms - Get the symmetries for a set of points in a `PetscSection` under specific orientations. 3541 3542 Not Collective 3543 3544 Input Parameters: 3545 + section - the section 3546 . numPoints - the number of points 3547 - points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an 3548 arbitrary integer: its interpretation is up to sym. Orientations are used by `DM`: for their interpretation in that 3549 context, see `DMPlexGetConeOrientation()`). 3550 3551 Output Parameters: 3552 + perms - The permutations for the given orientations (or `NULL` if there is no symmetry or the permutation is the identity). 3553 - rots - The field rotations symmetries for the given orientations (or `NULL` if there is no symmetry or the rotations are all 3554 identity). 3555 3556 Example of usage, gathering dofs into a local array (lArray) from a section array (sArray): 3557 .vb 3558 const PetscInt **perms; 3559 const PetscScalar **rots; 3560 PetscInt lOffset; 3561 3562 PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots); 3563 for (i = 0, lOffset = 0; i < numPoints; i++) { 3564 PetscInt point = points[2*i], dof, sOffset; 3565 const PetscInt *perm = perms ? perms[i] : NULL; 3566 const PetscScalar *rot = rots ? rots[i] : NULL; 3567 3568 PetscSectionGetDof(section,point,&dof); 3569 PetscSectionGetOffset(section,point,&sOffset); 3570 3571 if (perm) {for (j = 0; j < dof; j++) {lArray[lOffset + perm[j]] = sArray[sOffset + j];}} 3572 else {for (j = 0; j < dof; j++) {lArray[lOffset + j ] = sArray[sOffset + j];}} 3573 if (rot) {for (j = 0; j < dof; j++) {lArray[lOffset + j ] *= rot[j]; }} 3574 lOffset += dof; 3575 } 3576 PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots); 3577 .ve 3578 3579 Example of usage, adding dofs into a section array (sArray) from a local array (lArray): 3580 .vb 3581 const PetscInt **perms; 3582 const PetscScalar **rots; 3583 PetscInt lOffset; 3584 3585 PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots); 3586 for (i = 0, lOffset = 0; i < numPoints; i++) { 3587 PetscInt point = points[2*i], dof, sOffset; 3588 const PetscInt *perm = perms ? perms[i] : NULL; 3589 const PetscScalar *rot = rots ? rots[i] : NULL; 3590 3591 PetscSectionGetDof(section,point,&dof); 3592 PetscSectionGetOffset(section,point,&sOff); 3593 3594 if (perm) {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset + perm[j]] * (rot ? PetscConj(rot[perm[j]]) : 1.);}} 3595 else {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset + j ] * (rot ? PetscConj(rot[ j ]) : 1.);}} 3596 offset += dof; 3597 } 3598 PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots); 3599 .ve 3600 3601 Level: developer 3602 3603 Notes: 3604 `PetscSectionSetSym()` must have been previously called to provide the symmetries to the `PetscSection` 3605 3606 Use `PetscSectionRestorePointSyms()` when finished with the data 3607 3608 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionRestorePointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()` 3609 @*/ 3610 PetscErrorCode PetscSectionGetPointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots) 3611 { 3612 PetscSectionSym sym; 3613 3614 PetscFunctionBegin; 3615 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3616 if (numPoints) PetscAssertPointer(points, 3); 3617 if (perms) *perms = NULL; 3618 if (rots) *rots = NULL; 3619 sym = section->sym; 3620 if (sym && (perms || rots)) { 3621 SymWorkLink link; 3622 3623 if (sym->workin) { 3624 link = sym->workin; 3625 sym->workin = sym->workin->next; 3626 } else { 3627 PetscCall(PetscNew(&link)); 3628 } 3629 if (numPoints > link->numPoints) { 3630 PetscInt **perms = (PetscInt **)link->perms; 3631 PetscScalar **rots = (PetscScalar **)link->rots; 3632 PetscCall(PetscFree2(perms, rots)); 3633 PetscCall(PetscMalloc2(numPoints, (PetscInt ***)&link->perms, numPoints, (PetscScalar ***)&link->rots)); 3634 link->numPoints = numPoints; 3635 } 3636 link->next = sym->workout; 3637 sym->workout = link; 3638 PetscCall(PetscArrayzero((PetscInt **)link->perms, numPoints)); 3639 PetscCall(PetscArrayzero((PetscInt **)link->rots, numPoints)); 3640 PetscUseTypeMethod(sym, getpoints, section, numPoints, points, link->perms, link->rots); 3641 if (perms) *perms = link->perms; 3642 if (rots) *rots = link->rots; 3643 } 3644 PetscFunctionReturn(PETSC_SUCCESS); 3645 } 3646 3647 /*@C 3648 PetscSectionRestorePointSyms - Restore the symmetries returned by `PetscSectionGetPointSyms()` 3649 3650 Not Collective 3651 3652 Input Parameters: 3653 + section - the section 3654 . numPoints - the number of points 3655 . points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an 3656 arbitrary integer: its interpretation is up to sym. Orientations are used by `DM`: for their interpretation in that 3657 context, see `DMPlexGetConeOrientation()`). 3658 . perms - The permutations for the given orientations: set to `NULL` at conclusion 3659 - rots - The field rotations symmetries for the given orientations: set to `NULL` at conclusion 3660 3661 Level: developer 3662 3663 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetPointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()` 3664 @*/ 3665 PetscErrorCode PetscSectionRestorePointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots) 3666 { 3667 PetscSectionSym sym; 3668 3669 PetscFunctionBegin; 3670 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3671 sym = section->sym; 3672 if (sym && (perms || rots)) { 3673 SymWorkLink *p, link; 3674 3675 for (p = &sym->workout; (link = *p); p = &link->next) { 3676 if ((perms && link->perms == *perms) || (rots && link->rots == *rots)) { 3677 *p = link->next; 3678 link->next = sym->workin; 3679 sym->workin = link; 3680 if (perms) *perms = NULL; 3681 if (rots) *rots = NULL; 3682 PetscFunctionReturn(PETSC_SUCCESS); 3683 } 3684 } 3685 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Array was not checked out"); 3686 } 3687 PetscFunctionReturn(PETSC_SUCCESS); 3688 } 3689 3690 /*@C 3691 PetscSectionGetFieldPointSyms - Get the symmetries for a set of points in a field of a `PetscSection` under specific orientations. 3692 3693 Not Collective 3694 3695 Input Parameters: 3696 + section - the section 3697 . field - the field of the section 3698 . numPoints - the number of points 3699 - points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an 3700 arbitrary integer: its interpretation is up to sym. Orientations are used by `DM`: for their interpretation in that 3701 context, see `DMPlexGetConeOrientation()`). 3702 3703 Output Parameters: 3704 + perms - The permutations for the given orientations (or `NULL` if there is no symmetry or the permutation is the identity). 3705 - rots - The field rotations symmetries for the given orientations (or `NULL` if there is no symmetry or the rotations are all 3706 identity). 3707 3708 Level: developer 3709 3710 Notes: 3711 `PetscSectionSetFieldSym()` must have been previously called to provide the symmetries to the `PetscSection` 3712 3713 Use `PetscSectionRestoreFieldPointSyms()` when finished with the data 3714 3715 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetPointSyms()`, `PetscSectionRestoreFieldPointSyms()` 3716 @*/ 3717 PetscErrorCode PetscSectionGetFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots) 3718 { 3719 PetscFunctionBegin; 3720 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3721 PetscCheck(field <= section->numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "field %" PetscInt_FMT " greater than number of fields (%" PetscInt_FMT ") in section", field, section->numFields); 3722 PetscCall(PetscSectionGetPointSyms(section->field[field], numPoints, points, perms, rots)); 3723 PetscFunctionReturn(PETSC_SUCCESS); 3724 } 3725 3726 /*@C 3727 PetscSectionRestoreFieldPointSyms - Restore the symmetries returned by `PetscSectionGetFieldPointSyms()` 3728 3729 Not Collective 3730 3731 Input Parameters: 3732 + section - the section 3733 . field - the field number 3734 . numPoints - the number of points 3735 . points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an 3736 arbitrary integer: its interpretation is up to sym. Orientations are used by `DM`: for their interpretation in that 3737 context, see `DMPlexGetConeOrientation()`). 3738 . perms - The permutations for the given orientations: set to NULL at conclusion 3739 - rots - The field rotations symmetries for the given orientations: set to NULL at conclusion 3740 3741 Level: developer 3742 3743 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionRestorePointSyms()`, `petscSectionGetFieldPointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()` 3744 @*/ 3745 PetscErrorCode PetscSectionRestoreFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots) 3746 { 3747 PetscFunctionBegin; 3748 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3749 PetscCheck(field <= section->numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "field %" PetscInt_FMT " greater than number of fields (%" PetscInt_FMT ") in section", field, section->numFields); 3750 PetscCall(PetscSectionRestorePointSyms(section->field[field], numPoints, points, perms, rots)); 3751 PetscFunctionReturn(PETSC_SUCCESS); 3752 } 3753 3754 /*@ 3755 PetscSectionSymCopy - Copy the symmetries, assuming that the point structure is compatible 3756 3757 Not Collective 3758 3759 Input Parameter: 3760 . sym - the `PetscSectionSym` 3761 3762 Output Parameter: 3763 . nsym - the equivalent symmetries 3764 3765 Level: developer 3766 3767 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()` 3768 @*/ 3769 PetscErrorCode PetscSectionSymCopy(PetscSectionSym sym, PetscSectionSym nsym) 3770 { 3771 PetscFunctionBegin; 3772 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3773 PetscValidHeaderSpecific(nsym, PETSC_SECTION_SYM_CLASSID, 2); 3774 PetscTryTypeMethod(sym, copy, nsym); 3775 PetscFunctionReturn(PETSC_SUCCESS); 3776 } 3777 3778 /*@ 3779 PetscSectionSymDistribute - Distribute the symmetries in accordance with the input `PetscSF` 3780 3781 Collective 3782 3783 Input Parameters: 3784 + sym - the `PetscSectionSym` 3785 - migrationSF - the distribution map from roots to leaves 3786 3787 Output Parameter: 3788 . dsym - the redistributed symmetries 3789 3790 Level: developer 3791 3792 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()` 3793 @*/ 3794 PetscErrorCode PetscSectionSymDistribute(PetscSectionSym sym, PetscSF migrationSF, PetscSectionSym *dsym) 3795 { 3796 PetscFunctionBegin; 3797 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3798 PetscValidHeaderSpecific(migrationSF, PETSCSF_CLASSID, 2); 3799 PetscAssertPointer(dsym, 3); 3800 PetscTryTypeMethod(sym, distribute, migrationSF, dsym); 3801 PetscFunctionReturn(PETSC_SUCCESS); 3802 } 3803 3804 /*@ 3805 PetscSectionGetUseFieldOffsets - Get the flag indicating if field offsets are used directly in a global section, rather than just the point offset 3806 3807 Not Collective 3808 3809 Input Parameter: 3810 . s - the global `PetscSection` 3811 3812 Output Parameter: 3813 . flg - the flag 3814 3815 Level: developer 3816 3817 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSetChart()`, `PetscSectionCreate()` 3818 @*/ 3819 PetscErrorCode PetscSectionGetUseFieldOffsets(PetscSection s, PetscBool *flg) 3820 { 3821 PetscFunctionBegin; 3822 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 3823 *flg = s->useFieldOff; 3824 PetscFunctionReturn(PETSC_SUCCESS); 3825 } 3826 3827 /*@ 3828 PetscSectionSetUseFieldOffsets - Set the flag to use field offsets directly in a global section, rather than just the point offset 3829 3830 Not Collective 3831 3832 Input Parameters: 3833 + s - the global `PetscSection` 3834 - flg - the flag 3835 3836 Level: developer 3837 3838 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetUseFieldOffsets()`, `PetscSectionSetChart()`, `PetscSectionCreate()` 3839 @*/ 3840 PetscErrorCode PetscSectionSetUseFieldOffsets(PetscSection s, PetscBool flg) 3841 { 3842 PetscFunctionBegin; 3843 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 3844 s->useFieldOff = flg; 3845 PetscFunctionReturn(PETSC_SUCCESS); 3846 } 3847 3848 #define PetscSectionExpandPoints_Loop(TYPE) \ 3849 do { \ 3850 PetscInt i, n, o0, o1, size; \ 3851 TYPE *a0 = (TYPE *)origArray, *a1; \ 3852 PetscCall(PetscSectionGetStorageSize(s, &size)); \ 3853 PetscCall(PetscMalloc1(size, &a1)); \ 3854 for (i = 0; i < npoints; i++) { \ 3855 PetscCall(PetscSectionGetOffset(origSection, points_[i], &o0)); \ 3856 PetscCall(PetscSectionGetOffset(s, i, &o1)); \ 3857 PetscCall(PetscSectionGetDof(s, i, &n)); \ 3858 PetscCall(PetscMemcpy(&a1[o1], &a0[o0], n * unitsize)); \ 3859 } \ 3860 *newArray = (void *)a1; \ 3861 } while (0) 3862 3863 /*@ 3864 PetscSectionExtractDofsFromArray - Extracts elements of an array corresponding to DOFs of specified points. 3865 3866 Not Collective 3867 3868 Input Parameters: 3869 + origSection - the `PetscSection` describing the layout of the array 3870 . dataType - `MPI_Datatype` describing the data type of the array (currently only `MPIU_INT`, `MPIU_SCALAR`, `MPIU_REAL`) 3871 . origArray - the array; its size must be equal to the storage size of `origSection` 3872 - points - `IS` with points to extract; its indices must lie in the chart of `origSection` 3873 3874 Output Parameters: 3875 + newSection - the new `PetscSection` describing the layout of the new array (with points renumbered 0,1,... but preserving numbers of DOFs) 3876 - newArray - the array of the extracted DOFs; its size is the storage size of `newSection` 3877 3878 Level: developer 3879 3880 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetChart()`, `PetscSectionGetDof()`, `PetscSectionGetStorageSize()`, `PetscSectionCreate()` 3881 @*/ 3882 PetscErrorCode PetscSectionExtractDofsFromArray(PetscSection origSection, MPI_Datatype dataType, const void *origArray, IS points, PetscSection *newSection, void *newArray[]) 3883 { 3884 PetscSection s; 3885 const PetscInt *points_; 3886 PetscInt i, n, npoints, pStart, pEnd; 3887 PetscMPIInt unitsize; 3888 3889 PetscFunctionBegin; 3890 PetscValidHeaderSpecific(origSection, PETSC_SECTION_CLASSID, 1); 3891 PetscAssertPointer(origArray, 3); 3892 PetscValidHeaderSpecific(points, IS_CLASSID, 4); 3893 if (newSection) PetscAssertPointer(newSection, 5); 3894 if (newArray) PetscAssertPointer(newArray, 6); 3895 PetscCallMPI(MPI_Type_size(dataType, &unitsize)); 3896 PetscCall(ISGetLocalSize(points, &npoints)); 3897 PetscCall(ISGetIndices(points, &points_)); 3898 PetscCall(PetscSectionGetChart(origSection, &pStart, &pEnd)); 3899 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 3900 PetscCall(PetscSectionSetChart(s, 0, npoints)); 3901 for (i = 0; i < npoints; i++) { 3902 PetscCheck(points_[i] >= pStart && points_[i] < pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "point %" PetscInt_FMT " (index %" PetscInt_FMT ") in input IS out of input section's chart", points_[i], i); 3903 PetscCall(PetscSectionGetDof(origSection, points_[i], &n)); 3904 PetscCall(PetscSectionSetDof(s, i, n)); 3905 } 3906 PetscCall(PetscSectionSetUp(s)); 3907 if (newArray) { 3908 if (dataType == MPIU_INT) { 3909 PetscSectionExpandPoints_Loop(PetscInt); 3910 } else if (dataType == MPIU_SCALAR) { 3911 PetscSectionExpandPoints_Loop(PetscScalar); 3912 } else if (dataType == MPIU_REAL) { 3913 PetscSectionExpandPoints_Loop(PetscReal); 3914 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "not implemented for this MPI_Datatype"); 3915 } 3916 if (newSection) { 3917 *newSection = s; 3918 } else { 3919 PetscCall(PetscSectionDestroy(&s)); 3920 } 3921 PetscCall(ISRestoreIndices(points, &points_)); 3922 PetscFunctionReturn(PETSC_SUCCESS); 3923 } 3924