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 PetscBT bst, subbst; 2068 2069 PetscCall(PetscSectionGetBlockStarts(s, &bst)); 2070 if (bst) { 2071 PetscCall(PetscBTCreate(pEnd - pStart, &subbst)); 2072 PetscCall(PetscBTCopy(subbst, pEnd - pStart, bst)); 2073 PetscCall(PetscSectionSetBlockStarts(*subs, subbst)); 2074 } 2075 PetscCall(PetscSectionSetUp(*subs)); 2076 if (maxCdof) { 2077 PetscInt *indices; 2078 2079 PetscCall(PetscMalloc1(maxCdof, &indices)); 2080 for (p = pStart; p < pEnd; ++p) { 2081 PetscInt cdof; 2082 2083 PetscCall(PetscSectionGetConstraintDof(*subs, p, &cdof)); 2084 if (cdof) { 2085 const PetscInt *oldIndices = NULL; 2086 PetscInt fdof = 0, cfdof = 0, fc, numConst = 0, fOff = 0; 2087 2088 for (f = 0; f < len; ++f) { 2089 PetscCall(PetscSectionGetFieldDof(s, p, fields[f], &fdof)); 2090 PetscCall(PetscSectionGetFieldConstraintDof(s, p, fields[f], &cfdof)); 2091 PetscCall(PetscSectionGetFieldConstraintIndices(s, p, fields[f], &oldIndices)); 2092 PetscCall(PetscSectionSetFieldConstraintIndices(*subs, p, f, oldIndices)); 2093 for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] = oldIndices[fc] + fOff; 2094 numConst += cfdof; 2095 fOff += fdof; 2096 } 2097 PetscCall(PetscSectionSetConstraintIndices(*subs, p, indices)); 2098 } 2099 } 2100 PetscCall(PetscFree(indices)); 2101 } 2102 PetscFunctionReturn(PETSC_SUCCESS); 2103 } 2104 2105 /*@ 2106 PetscSectionCreateComponentSubsection - Create a new, smaller `PetscSection` composed of only selected components 2107 2108 Collective 2109 2110 Input Parameters: 2111 + s - the `PetscSection` 2112 . len - the number of components 2113 - comps - the component numbers 2114 2115 Output Parameter: 2116 . subs - the subsection 2117 2118 Level: advanced 2119 2120 Notes: 2121 The chart of `subs` is the same as the chart of `s` 2122 2123 This will error if the section has more than one field, or if a component number is out of range 2124 2125 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreateSupersection()`, `PetscSectionCreate()` 2126 @*/ 2127 PetscErrorCode PetscSectionCreateComponentSubsection(PetscSection s, PetscInt len, const PetscInt comps[], PetscSection *subs) 2128 { 2129 PetscSectionSym sym; 2130 const char *name = NULL; 2131 PetscInt Nf, pStart, pEnd; 2132 2133 PetscFunctionBegin; 2134 if (!len) PetscFunctionReturn(PETSC_SUCCESS); 2135 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2136 PetscAssertPointer(comps, 3); 2137 PetscAssertPointer(subs, 4); 2138 PetscCall(PetscSectionGetNumFields(s, &Nf)); 2139 PetscCheck(Nf == 1, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONG, "This method can only handle one field, not %" PetscInt_FMT, Nf); 2140 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), subs)); 2141 PetscCall(PetscSectionSetNumFields(*subs, 1)); 2142 PetscCall(PetscSectionGetFieldName(s, 0, &name)); 2143 PetscCall(PetscSectionSetFieldName(*subs, 0, name)); 2144 PetscCall(PetscSectionSetFieldComponents(*subs, 0, len)); 2145 PetscCall(PetscSectionGetFieldSym(s, 0, &sym)); 2146 PetscCall(PetscSectionSetFieldSym(*subs, 0, sym)); 2147 for (PetscInt c = 0; c < len; ++c) { 2148 PetscCall(PetscSectionGetComponentName(s, 0, comps[c], &name)); 2149 PetscCall(PetscSectionSetComponentName(*subs, 0, c, name)); 2150 } 2151 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 2152 PetscCall(PetscSectionSetChart(*subs, pStart, pEnd)); 2153 for (PetscInt p = pStart; p < pEnd; ++p) { 2154 PetscInt dof, cdof, cfdof; 2155 2156 PetscCall(PetscSectionGetDof(s, p, &dof)); 2157 if (!dof) continue; 2158 PetscCall(PetscSectionGetFieldConstraintDof(s, p, 0, &cfdof)); 2159 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 2160 PetscCheck(!cdof && !cfdof, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Component selection does not work with constraints"); 2161 PetscCall(PetscSectionSetFieldDof(*subs, p, 0, len)); 2162 PetscCall(PetscSectionSetDof(*subs, p, len)); 2163 } 2164 PetscCall(PetscSectionSetUp(*subs)); 2165 PetscFunctionReturn(PETSC_SUCCESS); 2166 } 2167 2168 /*@ 2169 PetscSectionCreateSupersection - Create a new, larger section composed of multiple `PetscSection`s 2170 2171 Collective 2172 2173 Input Parameters: 2174 + s - the input sections 2175 - len - the number of input sections 2176 2177 Output Parameter: 2178 . supers - the supersection 2179 2180 Level: advanced 2181 2182 Notes: 2183 The section offsets now refer to a new, larger vector. 2184 2185 Developer Notes: 2186 Needs to explain how the sections are composed 2187 2188 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreateSubsection()`, `PetscSectionCreate()` 2189 @*/ 2190 PetscErrorCode PetscSectionCreateSupersection(PetscSection s[], PetscInt len, PetscSection *supers) 2191 { 2192 PetscInt Nf = 0, f, pStart = PETSC_INT_MAX, pEnd = 0, p, maxCdof = 0, i; 2193 2194 PetscFunctionBegin; 2195 if (!len) PetscFunctionReturn(PETSC_SUCCESS); 2196 for (i = 0; i < len; ++i) { 2197 PetscInt nf, pStarti, pEndi; 2198 2199 PetscCall(PetscSectionGetNumFields(s[i], &nf)); 2200 PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi)); 2201 pStart = PetscMin(pStart, pStarti); 2202 pEnd = PetscMax(pEnd, pEndi); 2203 Nf += nf; 2204 } 2205 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s[0]), supers)); 2206 PetscCall(PetscSectionSetNumFields(*supers, Nf)); 2207 for (i = 0, f = 0; i < len; ++i) { 2208 PetscInt nf, fi, ci; 2209 2210 PetscCall(PetscSectionGetNumFields(s[i], &nf)); 2211 for (fi = 0; fi < nf; ++fi, ++f) { 2212 const char *name = NULL; 2213 PetscInt numComp = 0; 2214 2215 PetscCall(PetscSectionGetFieldName(s[i], fi, &name)); 2216 PetscCall(PetscSectionSetFieldName(*supers, f, name)); 2217 PetscCall(PetscSectionGetFieldComponents(s[i], fi, &numComp)); 2218 PetscCall(PetscSectionSetFieldComponents(*supers, f, numComp)); 2219 for (ci = 0; ci < s[i]->numFieldComponents[fi]; ++ci) { 2220 PetscCall(PetscSectionGetComponentName(s[i], fi, ci, &name)); 2221 PetscCall(PetscSectionSetComponentName(*supers, f, ci, name)); 2222 } 2223 } 2224 } 2225 PetscCall(PetscSectionSetChart(*supers, pStart, pEnd)); 2226 for (p = pStart; p < pEnd; ++p) { 2227 PetscInt dof = 0, cdof = 0; 2228 2229 for (i = 0, f = 0; i < len; ++i) { 2230 PetscInt nf, fi, pStarti, pEndi; 2231 PetscInt fdof = 0, cfdof = 0; 2232 2233 PetscCall(PetscSectionGetNumFields(s[i], &nf)); 2234 PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi)); 2235 if ((p < pStarti) || (p >= pEndi)) continue; 2236 for (fi = 0; fi < nf; ++fi, ++f) { 2237 PetscCall(PetscSectionGetFieldDof(s[i], p, fi, &fdof)); 2238 PetscCall(PetscSectionAddFieldDof(*supers, p, f, fdof)); 2239 PetscCall(PetscSectionGetFieldConstraintDof(s[i], p, fi, &cfdof)); 2240 if (cfdof) PetscCall(PetscSectionAddFieldConstraintDof(*supers, p, f, cfdof)); 2241 dof += fdof; 2242 cdof += cfdof; 2243 } 2244 } 2245 PetscCall(PetscSectionSetDof(*supers, p, dof)); 2246 if (cdof) PetscCall(PetscSectionSetConstraintDof(*supers, p, cdof)); 2247 maxCdof = PetscMax(cdof, maxCdof); 2248 } 2249 PetscCall(PetscSectionSetUp(*supers)); 2250 if (maxCdof) { 2251 PetscInt *indices; 2252 2253 PetscCall(PetscMalloc1(maxCdof, &indices)); 2254 for (p = pStart; p < pEnd; ++p) { 2255 PetscInt cdof; 2256 2257 PetscCall(PetscSectionGetConstraintDof(*supers, p, &cdof)); 2258 if (cdof) { 2259 PetscInt dof, numConst = 0, fOff = 0; 2260 2261 for (i = 0, f = 0; i < len; ++i) { 2262 const PetscInt *oldIndices = NULL; 2263 PetscInt nf, fi, pStarti, pEndi, fdof, cfdof, fc; 2264 2265 PetscCall(PetscSectionGetNumFields(s[i], &nf)); 2266 PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi)); 2267 if ((p < pStarti) || (p >= pEndi)) continue; 2268 for (fi = 0; fi < nf; ++fi, ++f) { 2269 PetscCall(PetscSectionGetFieldDof(s[i], p, fi, &fdof)); 2270 PetscCall(PetscSectionGetFieldConstraintDof(s[i], p, fi, &cfdof)); 2271 PetscCall(PetscSectionGetFieldConstraintIndices(s[i], p, fi, &oldIndices)); 2272 for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] = oldIndices[fc]; 2273 PetscCall(PetscSectionSetFieldConstraintIndices(*supers, p, f, &indices[numConst])); 2274 for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] += fOff; 2275 numConst += cfdof; 2276 } 2277 PetscCall(PetscSectionGetDof(s[i], p, &dof)); 2278 fOff += dof; 2279 } 2280 PetscCall(PetscSectionSetConstraintIndices(*supers, p, indices)); 2281 } 2282 } 2283 PetscCall(PetscFree(indices)); 2284 } 2285 PetscFunctionReturn(PETSC_SUCCESS); 2286 } 2287 2288 static PetscErrorCode PetscSectionCreateSubplexSection_Private(PetscSection s, IS subpointIS, PetscBool renumberPoints, PetscSection *subs) 2289 { 2290 const PetscInt *points = NULL, *indices = NULL; 2291 PetscInt *spoints = NULL, *order = NULL; 2292 PetscInt numFields, f, c, numSubpoints = 0, pStart, pEnd, p, spStart, spEnd, subp; 2293 2294 PetscFunctionBegin; 2295 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2296 PetscValidHeaderSpecific(subpointIS, IS_CLASSID, 2); 2297 PetscAssertPointer(subs, 4); 2298 PetscCall(PetscSectionGetNumFields(s, &numFields)); 2299 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), subs)); 2300 if (numFields) PetscCall(PetscSectionSetNumFields(*subs, numFields)); 2301 for (f = 0; f < numFields; ++f) { 2302 const char *name = NULL; 2303 PetscInt numComp = 0; 2304 2305 PetscCall(PetscSectionGetFieldName(s, f, &name)); 2306 PetscCall(PetscSectionSetFieldName(*subs, f, name)); 2307 PetscCall(PetscSectionGetFieldComponents(s, f, &numComp)); 2308 PetscCall(PetscSectionSetFieldComponents(*subs, f, numComp)); 2309 for (c = 0; c < s->numFieldComponents[f]; ++c) { 2310 PetscCall(PetscSectionGetComponentName(s, f, c, &name)); 2311 PetscCall(PetscSectionSetComponentName(*subs, f, c, name)); 2312 } 2313 } 2314 /* For right now, we do not try to squeeze the subchart */ 2315 if (subpointIS) { 2316 PetscCall(ISGetLocalSize(subpointIS, &numSubpoints)); 2317 PetscCall(ISGetIndices(subpointIS, &points)); 2318 } 2319 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 2320 if (renumberPoints) { 2321 PetscBool sorted; 2322 2323 spStart = 0; 2324 spEnd = numSubpoints; 2325 PetscCall(ISSorted(subpointIS, &sorted)); 2326 if (!sorted) { 2327 PetscCall(PetscMalloc2(numSubpoints, &spoints, numSubpoints, &order)); 2328 PetscCall(PetscArraycpy(spoints, points, numSubpoints)); 2329 for (PetscInt i = 0; i < numSubpoints; ++i) order[i] = i; 2330 PetscCall(PetscSortIntWithArray(numSubpoints, spoints, order)); 2331 } 2332 } else { 2333 PetscCall(ISGetMinMax(subpointIS, &spStart, &spEnd)); 2334 ++spEnd; 2335 } 2336 PetscCall(PetscSectionSetChart(*subs, spStart, spEnd)); 2337 for (p = pStart; p < pEnd; ++p) { 2338 PetscInt dof, cdof, fdof = 0, cfdof = 0; 2339 2340 PetscCall(PetscFindInt(p, numSubpoints, spoints ? spoints : points, &subp)); 2341 if (subp < 0) continue; 2342 if (!renumberPoints) subp = p; 2343 else subp = order ? order[subp] : subp; 2344 for (f = 0; f < numFields; ++f) { 2345 PetscCall(PetscSectionGetFieldDof(s, p, f, &fdof)); 2346 PetscCall(PetscSectionSetFieldDof(*subs, subp, f, fdof)); 2347 PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cfdof)); 2348 if (cfdof) PetscCall(PetscSectionSetFieldConstraintDof(*subs, subp, f, cfdof)); 2349 } 2350 PetscCall(PetscSectionGetDof(s, p, &dof)); 2351 PetscCall(PetscSectionSetDof(*subs, subp, dof)); 2352 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 2353 if (cdof) PetscCall(PetscSectionSetConstraintDof(*subs, subp, cdof)); 2354 } 2355 PetscCall(PetscSectionSetUp(*subs)); 2356 /* Change offsets to original offsets */ 2357 for (p = pStart; p < pEnd; ++p) { 2358 PetscInt off, foff = 0; 2359 2360 PetscCall(PetscFindInt(p, numSubpoints, spoints ? spoints : points, &subp)); 2361 if (subp < 0) continue; 2362 if (!renumberPoints) subp = p; 2363 else subp = order ? order[subp] : subp; 2364 for (f = 0; f < numFields; ++f) { 2365 PetscCall(PetscSectionGetFieldOffset(s, p, f, &foff)); 2366 PetscCall(PetscSectionSetFieldOffset(*subs, subp, f, foff)); 2367 } 2368 PetscCall(PetscSectionGetOffset(s, p, &off)); 2369 PetscCall(PetscSectionSetOffset(*subs, subp, off)); 2370 } 2371 /* Copy constraint indices */ 2372 for (subp = spStart; subp < spEnd; ++subp) { 2373 PetscInt cdof; 2374 2375 PetscCall(PetscSectionGetConstraintDof(*subs, subp, &cdof)); 2376 if (cdof) { 2377 for (f = 0; f < numFields; ++f) { 2378 PetscCall(PetscSectionGetFieldConstraintIndices(s, points[subp - spStart], f, &indices)); 2379 PetscCall(PetscSectionSetFieldConstraintIndices(*subs, subp, f, indices)); 2380 } 2381 PetscCall(PetscSectionGetConstraintIndices(s, points[subp - spStart], &indices)); 2382 PetscCall(PetscSectionSetConstraintIndices(*subs, subp, indices)); 2383 } 2384 } 2385 if (subpointIS) PetscCall(ISRestoreIndices(subpointIS, &points)); 2386 PetscCall(PetscFree2(spoints, order)); 2387 PetscFunctionReturn(PETSC_SUCCESS); 2388 } 2389 2390 /*@ 2391 PetscSectionCreateSubmeshSection - Create a new, smaller section with support on the submesh 2392 2393 Collective 2394 2395 Input Parameters: 2396 + s - the `PetscSection` 2397 - subpointIS - a sorted list of points in the original mesh which are in the submesh 2398 2399 Output Parameter: 2400 . subs - the subsection 2401 2402 Level: advanced 2403 2404 Notes: 2405 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))` 2406 2407 Compare this with `PetscSectionCreateSubdomainSection()` that does not map the points numbers to start at zero but leaves them as before 2408 2409 Developer Notes: 2410 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` 2411 2412 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreateSubdomainSection()`, `PetscSectionCreateSubsection()`, `DMPlexGetSubpointMap()`, `PetscSectionCreate()` 2413 @*/ 2414 PetscErrorCode PetscSectionCreateSubmeshSection(PetscSection s, IS subpointIS, PetscSection *subs) 2415 { 2416 PetscFunctionBegin; 2417 PetscCall(PetscSectionCreateSubplexSection_Private(s, subpointIS, PETSC_TRUE, subs)); 2418 PetscFunctionReturn(PETSC_SUCCESS); 2419 } 2420 2421 /*@ 2422 PetscSectionCreateSubdomainSection - Create a new, smaller section with support on a subdomain of the mesh 2423 2424 Collective 2425 2426 Input Parameters: 2427 + s - the `PetscSection` 2428 - subpointMap - a sorted list of points in the original mesh which are in the subdomain 2429 2430 Output Parameter: 2431 . subs - the subsection 2432 2433 Level: advanced 2434 2435 Notes: 2436 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` 2437 is `[min(subpointMap),max(subpointMap)+1)` 2438 2439 Compare this with `PetscSectionCreateSubmeshSection()` that maps the point numbers to start at zero 2440 2441 Developer Notes: 2442 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` 2443 2444 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreateSubmeshSection()`, `PetscSectionCreateSubsection()`, `DMPlexGetSubpointMap()`, `PetscSectionCreate()` 2445 @*/ 2446 PetscErrorCode PetscSectionCreateSubdomainSection(PetscSection s, IS subpointMap, PetscSection *subs) 2447 { 2448 PetscFunctionBegin; 2449 PetscCall(PetscSectionCreateSubplexSection_Private(s, subpointMap, PETSC_FALSE, subs)); 2450 PetscFunctionReturn(PETSC_SUCCESS); 2451 } 2452 2453 static PetscErrorCode PetscSectionView_ASCII(PetscSection s, PetscViewer viewer) 2454 { 2455 PetscInt p; 2456 PetscMPIInt rank; 2457 2458 PetscFunctionBegin; 2459 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 2460 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 2461 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 2462 for (p = 0; p < s->pEnd - s->pStart; ++p) { 2463 if (s->bc && s->bc->atlasDof[p] > 0) { 2464 PetscInt b; 2465 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT " constrained", p + s->pStart, s->atlasDof[p], s->atlasOff[p])); 2466 if (s->bcIndices) { 2467 for (b = 0; b < s->bc->atlasDof[p]; ++b) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, s->bcIndices[s->bc->atlasOff[p] + b])); 2468 } 2469 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 2470 } else { 2471 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT "\n", p + s->pStart, s->atlasDof[p], s->atlasOff[p])); 2472 } 2473 } 2474 PetscCall(PetscViewerFlush(viewer)); 2475 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 2476 if (s->sym) { 2477 PetscCall(PetscViewerASCIIPushTab(viewer)); 2478 PetscCall(PetscSectionSymView(s->sym, viewer)); 2479 PetscCall(PetscViewerASCIIPopTab(viewer)); 2480 } 2481 PetscFunctionReturn(PETSC_SUCCESS); 2482 } 2483 2484 /*@ 2485 PetscSectionViewFromOptions - View the `PetscSection` based on values in the options database 2486 2487 Collective 2488 2489 Input Parameters: 2490 + A - the `PetscSection` object to view 2491 . obj - Optional object that provides the options prefix used for the options 2492 - name - command line option 2493 2494 Level: intermediate 2495 2496 Note: 2497 See `PetscObjectViewFromOptions()` for available values of `PetscViewer` and `PetscViewerFormat` 2498 2499 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionView`, `PetscObjectViewFromOptions()`, `PetscSectionCreate()`, `PetscSectionView()` 2500 @*/ 2501 PetscErrorCode PetscSectionViewFromOptions(PetscSection A, PetscObject obj, const char name[]) 2502 { 2503 PetscFunctionBegin; 2504 PetscValidHeaderSpecific(A, PETSC_SECTION_CLASSID, 1); 2505 PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name)); 2506 PetscFunctionReturn(PETSC_SUCCESS); 2507 } 2508 2509 /*@ 2510 PetscSectionView - Views a `PetscSection` 2511 2512 Collective 2513 2514 Input Parameters: 2515 + s - the `PetscSection` object to view 2516 - viewer - the viewer 2517 2518 Level: beginner 2519 2520 Note: 2521 `PetscSectionView()`, when viewer is of type `PETSCVIEWERHDF5`, only saves 2522 distribution independent data, such as dofs, offsets, constraint dofs, 2523 and constraint indices. Points that have negative dofs, for instance, 2524 are not saved as they represent points owned by other processes. 2525 Point numbering and rank assignment is currently not stored. 2526 The saved section can be loaded with `PetscSectionLoad()`. 2527 2528 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`, `PetscSectionLoad()`, `PetscViewer` 2529 @*/ 2530 PetscErrorCode PetscSectionView(PetscSection s, PetscViewer viewer) 2531 { 2532 PetscBool isascii, ishdf5; 2533 PetscInt f; 2534 2535 PetscFunctionBegin; 2536 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2537 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)s), &viewer)); 2538 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2539 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 2540 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2541 if (isascii) { 2542 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)s, viewer)); 2543 if (s->numFields) { 2544 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " fields\n", s->numFields)); 2545 for (f = 0; f < s->numFields; ++f) { 2546 PetscCall(PetscViewerASCIIPrintf(viewer, " field %" PetscInt_FMT " \"%s\" with %" PetscInt_FMT " components\n", f, s->fieldNames[f], s->numFieldComponents[f])); 2547 PetscCall(PetscSectionView_ASCII(s->field[f], viewer)); 2548 } 2549 } else { 2550 PetscCall(PetscSectionView_ASCII(s, viewer)); 2551 } 2552 } else if (ishdf5) { 2553 #if PetscDefined(HAVE_HDF5) 2554 PetscCall(PetscSectionView_HDF5_Internal(s, viewer)); 2555 #else 2556 SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2557 #endif 2558 } 2559 PetscFunctionReturn(PETSC_SUCCESS); 2560 } 2561 2562 /*@ 2563 PetscSectionLoad - Loads a `PetscSection` 2564 2565 Collective 2566 2567 Input Parameters: 2568 + s - the `PetscSection` object to load 2569 - viewer - the viewer 2570 2571 Level: beginner 2572 2573 Note: 2574 `PetscSectionLoad()`, when viewer is of type `PETSCVIEWERHDF5`, loads 2575 a section saved with `PetscSectionView()`. The number of processes 2576 used here (N) does not need to be the same as that used when saving. 2577 After calling this function, the chart of s on rank i will be set 2578 to [0, E_i), where \sum_{i=0}^{N-1}E_i equals to the total number of 2579 saved section points. 2580 2581 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`, `PetscSectionView()` 2582 @*/ 2583 PetscErrorCode PetscSectionLoad(PetscSection s, PetscViewer viewer) 2584 { 2585 PetscBool ishdf5; 2586 2587 PetscFunctionBegin; 2588 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2589 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2590 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2591 PetscCheck(ishdf5, PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "Viewer type %s not yet supported for PetscSection loading", ((PetscObject)viewer)->type_name); 2592 #if PetscDefined(HAVE_HDF5) 2593 PetscCall(PetscSectionLoad_HDF5_Internal(s, viewer)); 2594 PetscFunctionReturn(PETSC_SUCCESS); 2595 #else 2596 SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2597 #endif 2598 } 2599 2600 /*@ 2601 PetscSectionResetClosurePermutation - Remove any existing closure permutation 2602 2603 Input Parameter: 2604 . section - The `PetscSection` 2605 2606 Level: intermediate 2607 2608 .seealso: `PetscSectionSetClosurePermutation()`, `PetscSectionSetClosureIndex()`, `PetscSectionReset()` 2609 @*/ 2610 PetscErrorCode PetscSectionResetClosurePermutation(PetscSection section) 2611 { 2612 PetscSectionClosurePermVal clVal; 2613 2614 PetscFunctionBegin; 2615 if (!section->clHash) PetscFunctionReturn(PETSC_SUCCESS); 2616 kh_foreach_value(section->clHash, clVal, { 2617 PetscCall(PetscFree(clVal.perm)); 2618 PetscCall(PetscFree(clVal.invPerm)); 2619 }); 2620 kh_destroy(ClPerm, section->clHash); 2621 section->clHash = NULL; 2622 PetscFunctionReturn(PETSC_SUCCESS); 2623 } 2624 2625 /*@ 2626 PetscSectionReset - Frees all section data, the section is then as if `PetscSectionCreate()` had just been called. 2627 2628 Not Collective 2629 2630 Input Parameter: 2631 . s - the `PetscSection` 2632 2633 Level: beginner 2634 2635 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()` 2636 @*/ 2637 PetscErrorCode PetscSectionReset(PetscSection s) 2638 { 2639 PetscInt f, c; 2640 2641 PetscFunctionBegin; 2642 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2643 for (f = 0; f < s->numFields; ++f) { 2644 PetscCall(PetscSectionDestroy(&s->field[f])); 2645 PetscCall(PetscFree(s->fieldNames[f])); 2646 for (c = 0; c < s->numFieldComponents[f]; ++c) PetscCall(PetscFree(s->compNames[f][c])); 2647 PetscCall(PetscFree(s->compNames[f])); 2648 } 2649 PetscCall(PetscFree(s->numFieldComponents)); 2650 PetscCall(PetscFree(s->fieldNames)); 2651 PetscCall(PetscFree(s->compNames)); 2652 PetscCall(PetscFree(s->field)); 2653 PetscCall(PetscSectionDestroy(&s->bc)); 2654 PetscCall(PetscFree(s->bcIndices)); 2655 PetscCall(PetscFree2(s->atlasDof, s->atlasOff)); 2656 PetscCall(PetscSectionDestroy(&s->clSection)); 2657 PetscCall(ISDestroy(&s->clPoints)); 2658 PetscCall(ISDestroy(&s->perm)); 2659 PetscCall(PetscBTDestroy(&s->blockStarts)); 2660 PetscCall(PetscSectionResetClosurePermutation(s)); 2661 PetscCall(PetscSectionSymDestroy(&s->sym)); 2662 PetscCall(PetscSectionDestroy(&s->clSection)); 2663 PetscCall(ISDestroy(&s->clPoints)); 2664 PetscCall(PetscSectionInvalidateMaxDof_Internal(s)); 2665 s->pStart = -1; 2666 s->pEnd = -1; 2667 s->maxDof = 0; 2668 s->setup = PETSC_FALSE; 2669 s->numFields = 0; 2670 s->clObj = NULL; 2671 PetscFunctionReturn(PETSC_SUCCESS); 2672 } 2673 2674 /*@ 2675 PetscSectionDestroy - Frees a `PetscSection` 2676 2677 Not Collective 2678 2679 Input Parameter: 2680 . s - the `PetscSection` 2681 2682 Level: beginner 2683 2684 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionReset()` 2685 @*/ 2686 PetscErrorCode PetscSectionDestroy(PetscSection *s) 2687 { 2688 PetscFunctionBegin; 2689 if (!*s) PetscFunctionReturn(PETSC_SUCCESS); 2690 PetscValidHeaderSpecific(*s, PETSC_SECTION_CLASSID, 1); 2691 if (--((PetscObject)*s)->refct > 0) { 2692 *s = NULL; 2693 PetscFunctionReturn(PETSC_SUCCESS); 2694 } 2695 PetscCall(PetscSectionReset(*s)); 2696 PetscCall(PetscHeaderDestroy(s)); 2697 PetscFunctionReturn(PETSC_SUCCESS); 2698 } 2699 2700 static PetscErrorCode VecIntGetValuesSection_Private(const PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt **values) 2701 { 2702 const PetscInt p = point - s->pStart; 2703 2704 PetscFunctionBegin; 2705 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2); 2706 *values = &baseArray[s->atlasOff[p]]; 2707 PetscFunctionReturn(PETSC_SUCCESS); 2708 } 2709 2710 static PetscErrorCode VecIntSetValuesSection_Private(PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt values[], InsertMode mode) 2711 { 2712 PetscInt *array; 2713 const PetscInt p = point - s->pStart; 2714 const PetscInt orientation = 0; /* Needs to be included for use in closure operations */ 2715 PetscInt cDim = 0; 2716 2717 PetscFunctionBegin; 2718 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2); 2719 PetscCall(PetscSectionGetConstraintDof(s, p, &cDim)); 2720 array = &baseArray[s->atlasOff[p]]; 2721 if (!cDim) { 2722 if (orientation >= 0) { 2723 const PetscInt dim = s->atlasDof[p]; 2724 PetscInt i; 2725 2726 if (mode == INSERT_VALUES) { 2727 for (i = 0; i < dim; ++i) array[i] = values ? values[i] : i; 2728 } else { 2729 for (i = 0; i < dim; ++i) array[i] += values[i]; 2730 } 2731 } else { 2732 PetscInt offset = 0; 2733 PetscInt j = -1, field, i; 2734 2735 for (field = 0; field < s->numFields; ++field) { 2736 const PetscInt dim = s->field[field]->atlasDof[p]; 2737 2738 for (i = dim - 1; i >= 0; --i) array[++j] = values ? values[i + offset] : i + offset; 2739 offset += dim; 2740 } 2741 } 2742 } else { 2743 if (orientation >= 0) { 2744 const PetscInt dim = s->atlasDof[p]; 2745 PetscInt cInd = 0, i; 2746 const PetscInt *cDof; 2747 2748 PetscCall(PetscSectionGetConstraintIndices(s, point, &cDof)); 2749 if (mode == INSERT_VALUES) { 2750 for (i = 0; i < dim; ++i) { 2751 if ((cInd < cDim) && (i == cDof[cInd])) { 2752 ++cInd; 2753 continue; 2754 } 2755 array[i] = values ? values[i] : i; 2756 } 2757 } else { 2758 for (i = 0; i < dim; ++i) { 2759 if ((cInd < cDim) && (i == cDof[cInd])) { 2760 ++cInd; 2761 continue; 2762 } 2763 array[i] += values[i]; 2764 } 2765 } 2766 } else { 2767 const PetscInt *cDof; 2768 PetscInt offset = 0; 2769 PetscInt cOffset = 0; 2770 PetscInt j = 0, field; 2771 2772 PetscCall(PetscSectionGetConstraintIndices(s, point, &cDof)); 2773 for (field = 0; field < s->numFields; ++field) { 2774 const PetscInt dim = s->field[field]->atlasDof[p]; /* PetscSectionGetFieldDof() */ 2775 const PetscInt tDim = s->field[field]->bc->atlasDof[p]; /* PetscSectionGetFieldConstraintDof() */ 2776 const PetscInt sDim = dim - tDim; 2777 PetscInt cInd = 0, i, k; 2778 2779 for (i = 0, k = dim + offset - 1; i < dim; ++i, ++j, --k) { 2780 if ((cInd < sDim) && (j == cDof[cInd + cOffset])) { 2781 ++cInd; 2782 continue; 2783 } 2784 array[j] = values ? values[k] : k; 2785 } 2786 offset += dim; 2787 cOffset += dim - tDim; 2788 } 2789 } 2790 } 2791 PetscFunctionReturn(PETSC_SUCCESS); 2792 } 2793 2794 /*@ 2795 PetscSectionHasConstraints - Determine whether a `PetscSection` has constrained dofs 2796 2797 Not Collective 2798 2799 Input Parameter: 2800 . s - The `PetscSection` 2801 2802 Output Parameter: 2803 . hasConstraints - flag indicating that the section has constrained dofs 2804 2805 Level: intermediate 2806 2807 .seealso: [PetscSection](ch_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2808 @*/ 2809 PetscErrorCode PetscSectionHasConstraints(PetscSection s, PetscBool *hasConstraints) 2810 { 2811 PetscFunctionBegin; 2812 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2813 PetscAssertPointer(hasConstraints, 2); 2814 *hasConstraints = s->bc ? PETSC_TRUE : PETSC_FALSE; 2815 PetscFunctionReturn(PETSC_SUCCESS); 2816 } 2817 2818 /*@C 2819 PetscSectionGetConstraintIndices - Get the point dof numbers, in [0, dof), which are constrained for a given point 2820 2821 Not Collective 2822 2823 Input Parameters: 2824 + s - The `PetscSection` 2825 - point - The point 2826 2827 Output Parameter: 2828 . indices - The constrained dofs 2829 2830 Level: intermediate 2831 2832 Fortran Notes: 2833 Use `PetscSectionRestoreConstraintIndices()` when the indices are no longer needed 2834 2835 .seealso: [PetscSection](ch_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2836 @*/ 2837 PetscErrorCode PetscSectionGetConstraintIndices(PetscSection s, PetscInt point, const PetscInt *indices[]) 2838 { 2839 PetscFunctionBegin; 2840 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2841 if (s->bc) { 2842 PetscCall(VecIntGetValuesSection_Private(s->bcIndices, s->bc, point, indices)); 2843 } else *indices = NULL; 2844 PetscFunctionReturn(PETSC_SUCCESS); 2845 } 2846 2847 /*@ 2848 PetscSectionSetConstraintIndices - Set the point dof numbers, in [0, dof), which are constrained 2849 2850 Not Collective 2851 2852 Input Parameters: 2853 + s - The `PetscSection` 2854 . point - The point 2855 - indices - The constrained dofs 2856 2857 Level: intermediate 2858 2859 .seealso: [PetscSection](ch_petscsection), `PetscSectionGetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2860 @*/ 2861 PetscErrorCode PetscSectionSetConstraintIndices(PetscSection s, PetscInt point, const PetscInt indices[]) 2862 { 2863 PetscFunctionBegin; 2864 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2865 if (s->bc) { 2866 const PetscInt dof = s->atlasDof[point]; 2867 const PetscInt cdof = s->bc->atlasDof[point]; 2868 PetscInt d; 2869 2870 if (indices) 2871 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]); 2872 PetscCall(VecIntSetValuesSection_Private(s->bcIndices, s->bc, point, indices, INSERT_VALUES)); 2873 } 2874 PetscFunctionReturn(PETSC_SUCCESS); 2875 } 2876 2877 /*@C 2878 PetscSectionGetFieldConstraintIndices - Get the field dof numbers, in [0, fdof), which are constrained 2879 2880 Not Collective 2881 2882 Input Parameters: 2883 + s - The `PetscSection` 2884 . field - The field number 2885 - point - The point 2886 2887 Output Parameter: 2888 . indices - The constrained dofs sorted in ascending order, the length is returned by `PetscSectionGetConstraintDof()`. 2889 2890 Level: intermediate 2891 2892 Fortran Notes: 2893 Use `PetscSectionRestoreFieldConstraintIndices()` to restore the indices when no longer needed 2894 2895 .seealso: [PetscSection](ch_petscsection), `PetscSectionSetFieldConstraintIndices()`, `PetscSectionGetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2896 @*/ 2897 PetscErrorCode PetscSectionGetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt *indices[]) 2898 { 2899 PetscFunctionBegin; 2900 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2901 PetscAssertPointer(indices, 4); 2902 PetscSectionCheckValidField(field, s->numFields); 2903 PetscCall(PetscSectionGetConstraintIndices(s->field[field], point, indices)); 2904 PetscFunctionReturn(PETSC_SUCCESS); 2905 } 2906 2907 /*@ 2908 PetscSectionSetFieldConstraintIndices - Set the field dof numbers, in [0, fdof), which are constrained 2909 2910 Not Collective 2911 2912 Input Parameters: 2913 + s - The `PetscSection` 2914 . point - The point 2915 . field - The field number 2916 - indices - The constrained dofs 2917 2918 Level: intermediate 2919 2920 .seealso: [PetscSection](ch_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetFieldConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2921 @*/ 2922 PetscErrorCode PetscSectionSetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt indices[]) 2923 { 2924 PetscFunctionBegin; 2925 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2926 PetscSectionCheckValidField(field, s->numFields); 2927 PetscCall(PetscSectionSetConstraintIndices(s->field[field], point, indices)); 2928 PetscFunctionReturn(PETSC_SUCCESS); 2929 } 2930 2931 /*@ 2932 PetscSectionPermute - Reorder the section according to the input point permutation 2933 2934 Collective 2935 2936 Input Parameters: 2937 + section - The `PetscSection` object 2938 - permutation - The point permutation, old point p becomes new point perm[p] 2939 2940 Output Parameter: 2941 . sectionNew - The permuted `PetscSection` 2942 2943 Level: intermediate 2944 2945 Note: 2946 The data and the access to the data via `PetscSectionGetFieldOffset()` and `PetscSectionGetOffset()` are both changed in `sectionNew` 2947 2948 Compare to `PetscSectionSetPermutation()` 2949 2950 .seealso: [PetscSection](ch_petscsection), `IS`, `PetscSection`, `MatPermute()`, `PetscSectionSetPermutation()` 2951 @*/ 2952 PetscErrorCode PetscSectionPermute(PetscSection section, IS permutation, PetscSection *sectionNew) 2953 { 2954 PetscSection s = section, sNew; 2955 const PetscInt *perm; 2956 PetscInt numFields, f, c, numPoints, pStart, pEnd, p; 2957 2958 PetscFunctionBegin; 2959 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 2960 PetscValidHeaderSpecific(permutation, IS_CLASSID, 2); 2961 PetscAssertPointer(sectionNew, 3); 2962 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), &sNew)); 2963 PetscCall(PetscSectionGetNumFields(s, &numFields)); 2964 if (numFields) PetscCall(PetscSectionSetNumFields(sNew, numFields)); 2965 for (f = 0; f < numFields; ++f) { 2966 const char *name; 2967 PetscInt numComp; 2968 2969 PetscCall(PetscSectionGetFieldName(s, f, &name)); 2970 PetscCall(PetscSectionSetFieldName(sNew, f, name)); 2971 PetscCall(PetscSectionGetFieldComponents(s, f, &numComp)); 2972 PetscCall(PetscSectionSetFieldComponents(sNew, f, numComp)); 2973 for (c = 0; c < s->numFieldComponents[f]; ++c) { 2974 PetscCall(PetscSectionGetComponentName(s, f, c, &name)); 2975 PetscCall(PetscSectionSetComponentName(sNew, f, c, name)); 2976 } 2977 } 2978 PetscCall(ISGetLocalSize(permutation, &numPoints)); 2979 PetscCall(ISGetIndices(permutation, &perm)); 2980 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 2981 PetscCall(PetscSectionSetChart(sNew, pStart, pEnd)); 2982 PetscCheck(numPoints >= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Permutation size %" PetscInt_FMT " is less than largest Section point %" PetscInt_FMT, numPoints, pEnd); 2983 for (p = pStart; p < pEnd; ++p) { 2984 PetscInt dof, cdof; 2985 2986 PetscCall(PetscSectionGetDof(s, p, &dof)); 2987 PetscCall(PetscSectionSetDof(sNew, perm[p], dof)); 2988 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 2989 if (cdof) PetscCall(PetscSectionSetConstraintDof(sNew, perm[p], cdof)); 2990 for (f = 0; f < numFields; ++f) { 2991 PetscCall(PetscSectionGetFieldDof(s, p, f, &dof)); 2992 PetscCall(PetscSectionSetFieldDof(sNew, perm[p], f, dof)); 2993 PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof)); 2994 if (cdof) PetscCall(PetscSectionSetFieldConstraintDof(sNew, perm[p], f, cdof)); 2995 } 2996 } 2997 PetscCall(PetscSectionSetUp(sNew)); 2998 for (p = pStart; p < pEnd; ++p) { 2999 const PetscInt *cind; 3000 PetscInt cdof; 3001 3002 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 3003 if (cdof) { 3004 PetscCall(PetscSectionGetConstraintIndices(s, p, &cind)); 3005 PetscCall(PetscSectionSetConstraintIndices(sNew, perm[p], cind)); 3006 } 3007 for (f = 0; f < numFields; ++f) { 3008 PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof)); 3009 if (cdof) { 3010 PetscCall(PetscSectionGetFieldConstraintIndices(s, p, f, &cind)); 3011 PetscCall(PetscSectionSetFieldConstraintIndices(sNew, perm[p], f, cind)); 3012 } 3013 } 3014 } 3015 PetscCall(ISRestoreIndices(permutation, &perm)); 3016 *sectionNew = sNew; 3017 PetscFunctionReturn(PETSC_SUCCESS); 3018 } 3019 3020 /*@ 3021 PetscSectionSetClosureIndex - Create an internal data structure to speed up closure queries. 3022 3023 Collective 3024 3025 Input Parameters: 3026 + section - The `PetscSection` 3027 . obj - A `PetscObject` which serves as the key for this index 3028 . clSection - `PetscSection` giving the size of the closure of each point 3029 - clPoints - `IS` giving the points in each closure 3030 3031 Level: advanced 3032 3033 Note: 3034 This function creates an internal map from each point to its closure. We compress out closure points with no dofs in this section. 3035 3036 Developer Notes: 3037 The information provided here is completely opaque 3038 3039 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetClosureIndex()`, `DMPlexCreateClosureIndex()` 3040 @*/ 3041 PetscErrorCode PetscSectionSetClosureIndex(PetscSection section, PetscObject obj, PetscSection clSection, IS clPoints) 3042 { 3043 PetscFunctionBegin; 3044 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3045 PetscValidHeaderSpecific(clSection, PETSC_SECTION_CLASSID, 3); 3046 PetscValidHeaderSpecific(clPoints, IS_CLASSID, 4); 3047 if (section->clObj != obj) PetscCall(PetscSectionResetClosurePermutation(section)); 3048 section->clObj = obj; 3049 PetscCall(PetscObjectReference((PetscObject)clSection)); 3050 PetscCall(PetscObjectReference((PetscObject)clPoints)); 3051 PetscCall(PetscSectionDestroy(§ion->clSection)); 3052 PetscCall(ISDestroy(§ion->clPoints)); 3053 section->clSection = clSection; 3054 section->clPoints = clPoints; 3055 PetscFunctionReturn(PETSC_SUCCESS); 3056 } 3057 3058 /*@ 3059 PetscSectionGetClosureIndex - Get the cache of points in the closure of each point in the section set with `PetscSectionSetClosureIndex()` 3060 3061 Collective 3062 3063 Input Parameters: 3064 + section - The `PetscSection` 3065 - obj - A `PetscObject` which serves as the key for this index 3066 3067 Output Parameters: 3068 + clSection - `PetscSection` giving the size of the closure of each point 3069 - clPoints - `IS` giving the points in each closure 3070 3071 Level: advanced 3072 3073 .seealso: [PetscSection](ch_petscsection), `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()` 3074 @*/ 3075 PetscErrorCode PetscSectionGetClosureIndex(PetscSection section, PetscObject obj, PetscSection *clSection, IS *clPoints) 3076 { 3077 PetscFunctionBegin; 3078 if (section->clObj == obj) { 3079 if (clSection) *clSection = section->clSection; 3080 if (clPoints) *clPoints = section->clPoints; 3081 } else { 3082 if (clSection) *clSection = NULL; 3083 if (clPoints) *clPoints = NULL; 3084 } 3085 PetscFunctionReturn(PETSC_SUCCESS); 3086 } 3087 3088 PetscErrorCode PetscSectionSetClosurePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, PetscCopyMode mode, PetscInt *clPerm) 3089 { 3090 PetscInt i; 3091 khiter_t iter; 3092 int new_entry; 3093 PetscSectionClosurePermKey key = {depth, clSize}; 3094 PetscSectionClosurePermVal *val; 3095 3096 PetscFunctionBegin; 3097 if (section->clObj != obj) { 3098 PetscCall(PetscSectionDestroy(§ion->clSection)); 3099 PetscCall(ISDestroy(§ion->clPoints)); 3100 } 3101 section->clObj = obj; 3102 if (!section->clHash) PetscCall(PetscClPermCreate(§ion->clHash)); 3103 iter = kh_put(ClPerm, section->clHash, key, &new_entry); 3104 val = &kh_val(section->clHash, iter); 3105 if (!new_entry) { 3106 PetscCall(PetscFree(val->perm)); 3107 PetscCall(PetscFree(val->invPerm)); 3108 } 3109 if (mode == PETSC_COPY_VALUES) { 3110 PetscCall(PetscMalloc1(clSize, &val->perm)); 3111 PetscCall(PetscArraycpy(val->perm, clPerm, clSize)); 3112 } else if (mode == PETSC_OWN_POINTER) { 3113 val->perm = clPerm; 3114 } else SETERRQ(PetscObjectComm(obj), PETSC_ERR_SUP, "Do not support borrowed arrays"); 3115 PetscCall(PetscMalloc1(clSize, &val->invPerm)); 3116 for (i = 0; i < clSize; ++i) val->invPerm[clPerm[i]] = i; 3117 PetscFunctionReturn(PETSC_SUCCESS); 3118 } 3119 3120 /*@ 3121 PetscSectionSetClosurePermutation - Set the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex. 3122 3123 Not Collective 3124 3125 Input Parameters: 3126 + section - The `PetscSection` 3127 . obj - A `PetscObject` which serves as the key for this index (usually a `DM`) 3128 . depth - Depth of points on which to apply the given permutation 3129 - perm - Permutation of the cell dof closure 3130 3131 Level: intermediate 3132 3133 Notes: 3134 The specified permutation will only be applied to points at depth whose closure size matches the length of perm. In a 3135 mixed-topology or variable-degree finite element space, this function can be called multiple times at each depth for 3136 each topology and degree. 3137 3138 This approach assumes that (depth, len(perm)) uniquely identifies the desired permutation; this might not be true for 3139 exotic/enriched spaces on mixed topology meshes. 3140 3141 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `IS`, `PetscSectionGetClosurePermutation()`, `PetscSectionGetClosureIndex()`, `DMPlexCreateClosureIndex()`, `PetscCopyMode` 3142 @*/ 3143 PetscErrorCode PetscSectionSetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, IS perm) 3144 { 3145 const PetscInt *clPerm = NULL; 3146 PetscInt clSize = 0; 3147 3148 PetscFunctionBegin; 3149 if (perm) { 3150 PetscCall(ISGetLocalSize(perm, &clSize)); 3151 PetscCall(ISGetIndices(perm, &clPerm)); 3152 } 3153 PetscCall(PetscSectionSetClosurePermutation_Internal(section, obj, depth, clSize, PETSC_COPY_VALUES, (PetscInt *)clPerm)); 3154 if (perm) PetscCall(ISRestoreIndices(perm, &clPerm)); 3155 PetscFunctionReturn(PETSC_SUCCESS); 3156 } 3157 3158 static PetscErrorCode PetscSectionGetClosurePermutation_Private(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[]) 3159 { 3160 PetscFunctionBegin; 3161 if (section->clObj == obj) { 3162 PetscSectionClosurePermKey k = {depth, size}; 3163 PetscSectionClosurePermVal v; 3164 3165 PetscCall(PetscClPermGet(section->clHash, k, &v)); 3166 if (perm) *perm = v.perm; 3167 } else { 3168 if (perm) *perm = NULL; 3169 } 3170 PetscFunctionReturn(PETSC_SUCCESS); 3171 } 3172 3173 /*@ 3174 PetscSectionGetClosurePermutation - Get the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex. 3175 3176 Not Collective 3177 3178 Input Parameters: 3179 + section - The `PetscSection` 3180 . obj - A `PetscObject` which serves as the key for this index (usually a DM) 3181 . depth - Depth stratum on which to obtain closure permutation 3182 - clSize - Closure size to be permuted (e.g., may vary with element topology and degree) 3183 3184 Output Parameter: 3185 . perm - The dof closure permutation 3186 3187 Level: intermediate 3188 3189 Note: 3190 The user must destroy the `IS` that is returned. 3191 3192 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `IS`, `PetscSectionSetClosurePermutation()`, `PetscSectionGetClosureInversePermutation()`, `PetscSectionGetClosureIndex()`, `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()` 3193 @*/ 3194 PetscErrorCode PetscSectionGetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm) 3195 { 3196 const PetscInt *clPerm = NULL; 3197 3198 PetscFunctionBegin; 3199 PetscCall(PetscSectionGetClosurePermutation_Private(section, obj, depth, clSize, &clPerm)); 3200 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); 3201 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm)); 3202 PetscFunctionReturn(PETSC_SUCCESS); 3203 } 3204 3205 PetscErrorCode PetscSectionGetClosureInversePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[]) 3206 { 3207 PetscFunctionBegin; 3208 if (section->clObj == obj && section->clHash) { 3209 PetscSectionClosurePermKey k = {depth, size}; 3210 PetscSectionClosurePermVal v; 3211 PetscCall(PetscClPermGet(section->clHash, k, &v)); 3212 if (perm) *perm = v.invPerm; 3213 } else { 3214 if (perm) *perm = NULL; 3215 } 3216 PetscFunctionReturn(PETSC_SUCCESS); 3217 } 3218 3219 /*@ 3220 PetscSectionGetClosureInversePermutation - Get the inverse dof permutation for the closure of each cell in the section, meaning clPerm[oldIndex] = newIndex. 3221 3222 Not Collective 3223 3224 Input Parameters: 3225 + section - The `PetscSection` 3226 . obj - A `PetscObject` which serves as the key for this index (usually a `DM`) 3227 . depth - Depth stratum on which to obtain closure permutation 3228 - clSize - Closure size to be permuted (e.g., may vary with element topology and degree) 3229 3230 Output Parameter: 3231 . perm - The dof closure permutation 3232 3233 Level: intermediate 3234 3235 Note: 3236 The user must destroy the `IS` that is returned. 3237 3238 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `IS`, `PetscSectionSetClosurePermutation()`, `PetscSectionGetClosureIndex()`, `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()` 3239 @*/ 3240 PetscErrorCode PetscSectionGetClosureInversePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm) 3241 { 3242 const PetscInt *clPerm = NULL; 3243 3244 PetscFunctionBegin; 3245 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, obj, depth, clSize, &clPerm)); 3246 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm)); 3247 PetscFunctionReturn(PETSC_SUCCESS); 3248 } 3249 3250 /*@ 3251 PetscSectionGetField - Get the `PetscSection` associated with a single field 3252 3253 Input Parameters: 3254 + s - The `PetscSection` 3255 - field - The field number 3256 3257 Output Parameter: 3258 . subs - The `PetscSection` for the given field, note the chart of `subs` is not set 3259 3260 Level: intermediate 3261 3262 Note: 3263 Does not increase the reference count of the selected sub-section. There is no matching `PetscSectionRestoreField()` 3264 3265 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `IS`, `PetscSectionSetNumFields()` 3266 @*/ 3267 PetscErrorCode PetscSectionGetField(PetscSection s, PetscInt field, PetscSection *subs) 3268 { 3269 PetscFunctionBegin; 3270 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 3271 PetscAssertPointer(subs, 3); 3272 PetscSectionCheckValidField(field, s->numFields); 3273 *subs = s->field[field]; 3274 PetscFunctionReturn(PETSC_SUCCESS); 3275 } 3276 3277 PetscClassId PETSC_SECTION_SYM_CLASSID; 3278 PetscFunctionList PetscSectionSymList = NULL; 3279 3280 /*@ 3281 PetscSectionSymCreate - Creates an empty `PetscSectionSym` object. 3282 3283 Collective 3284 3285 Input Parameter: 3286 . comm - the MPI communicator 3287 3288 Output Parameter: 3289 . sym - pointer to the new set of symmetries 3290 3291 Level: developer 3292 3293 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSym`, `PetscSectionSymDestroy()` 3294 @*/ 3295 PetscErrorCode PetscSectionSymCreate(MPI_Comm comm, PetscSectionSym *sym) 3296 { 3297 PetscFunctionBegin; 3298 PetscAssertPointer(sym, 2); 3299 PetscCall(ISInitializePackage()); 3300 3301 PetscCall(PetscHeaderCreate(*sym, PETSC_SECTION_SYM_CLASSID, "PetscSectionSym", "Section Symmetry", "IS", comm, PetscSectionSymDestroy, PetscSectionSymView)); 3302 PetscFunctionReturn(PETSC_SUCCESS); 3303 } 3304 3305 /*@ 3306 PetscSectionSymSetType - Builds a `PetscSectionSym`, for a particular implementation. 3307 3308 Collective 3309 3310 Input Parameters: 3311 + sym - The section symmetry object 3312 - method - The name of the section symmetry type 3313 3314 Level: developer 3315 3316 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymGetType()`, `PetscSectionSymCreate()` 3317 @*/ 3318 PetscErrorCode PetscSectionSymSetType(PetscSectionSym sym, PetscSectionSymType method) 3319 { 3320 PetscErrorCode (*r)(PetscSectionSym); 3321 PetscBool match; 3322 3323 PetscFunctionBegin; 3324 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3325 PetscCall(PetscObjectTypeCompare((PetscObject)sym, method, &match)); 3326 if (match) PetscFunctionReturn(PETSC_SUCCESS); 3327 3328 PetscCall(PetscFunctionListFind(PetscSectionSymList, method, &r)); 3329 PetscCheck(r, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscSectionSym type: %s", method); 3330 PetscTryTypeMethod(sym, destroy); 3331 sym->ops->destroy = NULL; 3332 3333 PetscCall((*r)(sym)); 3334 PetscCall(PetscObjectChangeTypeName((PetscObject)sym, method)); 3335 PetscFunctionReturn(PETSC_SUCCESS); 3336 } 3337 3338 /*@ 3339 PetscSectionSymGetType - Gets the section symmetry type name (as a string) from the `PetscSectionSym`. 3340 3341 Not Collective 3342 3343 Input Parameter: 3344 . sym - The section symmetry 3345 3346 Output Parameter: 3347 . type - The index set type name 3348 3349 Level: developer 3350 3351 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymSetType()`, `PetscSectionSymCreate()` 3352 @*/ 3353 PetscErrorCode PetscSectionSymGetType(PetscSectionSym sym, PetscSectionSymType *type) 3354 { 3355 PetscFunctionBegin; 3356 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3357 PetscAssertPointer(type, 2); 3358 *type = ((PetscObject)sym)->type_name; 3359 PetscFunctionReturn(PETSC_SUCCESS); 3360 } 3361 3362 /*@C 3363 PetscSectionSymRegister - Registers a new section symmetry implementation 3364 3365 Not Collective, No Fortran Support 3366 3367 Input Parameters: 3368 + sname - The name of a new user-defined creation routine 3369 - function - The creation routine itself 3370 3371 Level: developer 3372 3373 Notes: 3374 `PetscSectionSymRegister()` may be called multiple times to add several user-defined vectors 3375 3376 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymCreate()`, `PetscSectionSymSetType()` 3377 @*/ 3378 PetscErrorCode PetscSectionSymRegister(const char sname[], PetscErrorCode (*function)(PetscSectionSym)) 3379 { 3380 PetscFunctionBegin; 3381 PetscCall(ISInitializePackage()); 3382 PetscCall(PetscFunctionListAdd(&PetscSectionSymList, sname, function)); 3383 PetscFunctionReturn(PETSC_SUCCESS); 3384 } 3385 3386 /*@ 3387 PetscSectionSymDestroy - Destroys a section symmetry. 3388 3389 Collective 3390 3391 Input Parameter: 3392 . sym - the section symmetry 3393 3394 Level: developer 3395 3396 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()` 3397 @*/ 3398 PetscErrorCode PetscSectionSymDestroy(PetscSectionSym *sym) 3399 { 3400 SymWorkLink link, next; 3401 3402 PetscFunctionBegin; 3403 if (!*sym) PetscFunctionReturn(PETSC_SUCCESS); 3404 PetscValidHeaderSpecific(*sym, PETSC_SECTION_SYM_CLASSID, 1); 3405 if (--((PetscObject)*sym)->refct > 0) { 3406 *sym = NULL; 3407 PetscFunctionReturn(PETSC_SUCCESS); 3408 } 3409 PetscTryTypeMethod(*sym, destroy); 3410 PetscCheck(!(*sym)->workout, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Work array still checked out"); 3411 for (link = (*sym)->workin; link; link = next) { 3412 PetscInt **perms = (PetscInt **)link->perms; 3413 PetscScalar **rots = (PetscScalar **)link->rots; 3414 PetscCall(PetscFree2(perms, rots)); 3415 next = link->next; 3416 PetscCall(PetscFree(link)); 3417 } 3418 (*sym)->workin = NULL; 3419 PetscCall(PetscHeaderDestroy(sym)); 3420 PetscFunctionReturn(PETSC_SUCCESS); 3421 } 3422 3423 /*@ 3424 PetscSectionSymView - Displays a section symmetry 3425 3426 Collective 3427 3428 Input Parameters: 3429 + sym - the index set 3430 - viewer - viewer used to display the set, for example `PETSC_VIEWER_STDOUT_SELF`. 3431 3432 Level: developer 3433 3434 .seealso: `PetscSectionSym`, `PetscViewer`, `PetscViewerASCIIOpen()` 3435 @*/ 3436 PetscErrorCode PetscSectionSymView(PetscSectionSym sym, PetscViewer viewer) 3437 { 3438 PetscFunctionBegin; 3439 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3440 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sym), &viewer)); 3441 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 3442 PetscCheckSameComm(sym, 1, viewer, 2); 3443 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)sym, viewer)); 3444 PetscTryTypeMethod(sym, view, viewer); 3445 PetscFunctionReturn(PETSC_SUCCESS); 3446 } 3447 3448 /*@ 3449 PetscSectionSetSym - Set the symmetries for the data referred to by the section 3450 3451 Collective 3452 3453 Input Parameters: 3454 + section - the section describing data layout 3455 - sym - the symmetry describing the affect of orientation on the access of the data 3456 3457 Level: developer 3458 3459 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetSym()`, `PetscSectionSymCreate()` 3460 @*/ 3461 PetscErrorCode PetscSectionSetSym(PetscSection section, PetscSectionSym sym) 3462 { 3463 PetscFunctionBegin; 3464 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3465 PetscCall(PetscSectionSymDestroy(§ion->sym)); 3466 if (sym) { 3467 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 2); 3468 PetscCheckSameComm(section, 1, sym, 2); 3469 PetscCall(PetscObjectReference((PetscObject)sym)); 3470 } 3471 section->sym = sym; 3472 PetscFunctionReturn(PETSC_SUCCESS); 3473 } 3474 3475 /*@ 3476 PetscSectionGetSym - Get the symmetries for the data referred to by the section 3477 3478 Not Collective 3479 3480 Input Parameter: 3481 . section - the section describing data layout 3482 3483 Output Parameter: 3484 . sym - the symmetry describing the affect of orientation on the access of the data, provided previously by `PetscSectionSetSym()` 3485 3486 Level: developer 3487 3488 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSetSym()`, `PetscSectionSymCreate()` 3489 @*/ 3490 PetscErrorCode PetscSectionGetSym(PetscSection section, PetscSectionSym *sym) 3491 { 3492 PetscFunctionBegin; 3493 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3494 *sym = section->sym; 3495 PetscFunctionReturn(PETSC_SUCCESS); 3496 } 3497 3498 /*@ 3499 PetscSectionSetFieldSym - Set the symmetries for the data referred to by a field of the section 3500 3501 Collective 3502 3503 Input Parameters: 3504 + section - the section describing data layout 3505 . field - the field number 3506 - sym - the symmetry describing the affect of orientation on the access of the data 3507 3508 Level: developer 3509 3510 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetFieldSym()`, `PetscSectionSymCreate()` 3511 @*/ 3512 PetscErrorCode PetscSectionSetFieldSym(PetscSection section, PetscInt field, PetscSectionSym sym) 3513 { 3514 PetscFunctionBegin; 3515 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3516 PetscSectionCheckValidField(field, section->numFields); 3517 PetscCall(PetscSectionSetSym(section->field[field], sym)); 3518 PetscFunctionReturn(PETSC_SUCCESS); 3519 } 3520 3521 /*@ 3522 PetscSectionGetFieldSym - Get the symmetries for the data referred to by a field of the section 3523 3524 Collective 3525 3526 Input Parameters: 3527 + section - the section describing data layout 3528 - field - the field number 3529 3530 Output Parameter: 3531 . sym - the symmetry describing the affect of orientation on the access of the data 3532 3533 Level: developer 3534 3535 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSetFieldSym()`, `PetscSectionSymCreate()` 3536 @*/ 3537 PetscErrorCode PetscSectionGetFieldSym(PetscSection section, PetscInt field, PetscSectionSym *sym) 3538 { 3539 PetscFunctionBegin; 3540 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3541 PetscSectionCheckValidField(field, section->numFields); 3542 *sym = section->field[field]->sym; 3543 PetscFunctionReturn(PETSC_SUCCESS); 3544 } 3545 3546 /*@C 3547 PetscSectionGetPointSyms - Get the symmetries for a set of points in a `PetscSection` under specific orientations. 3548 3549 Not Collective 3550 3551 Input Parameters: 3552 + section - the section 3553 . numPoints - the number of points 3554 - points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an 3555 arbitrary integer: its interpretation is up to sym. Orientations are used by `DM`: for their interpretation in that 3556 context, see `DMPlexGetConeOrientation()`). 3557 3558 Output Parameters: 3559 + perms - The permutations for the given orientations (or `NULL` if there is no symmetry or the permutation is the identity). 3560 - rots - The field rotations symmetries for the given orientations (or `NULL` if there is no symmetry or the rotations are all 3561 identity). 3562 3563 Example of usage, gathering dofs into a local array (lArray) from a section array (sArray): 3564 .vb 3565 const PetscInt **perms; 3566 const PetscScalar **rots; 3567 PetscInt lOffset; 3568 3569 PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots); 3570 for (i = 0, lOffset = 0; i < numPoints; i++) { 3571 PetscInt point = points[2*i], dof, sOffset; 3572 const PetscInt *perm = perms ? perms[i] : NULL; 3573 const PetscScalar *rot = rots ? rots[i] : NULL; 3574 3575 PetscSectionGetDof(section,point,&dof); 3576 PetscSectionGetOffset(section,point,&sOffset); 3577 3578 if (perm) {for (j = 0; j < dof; j++) {lArray[lOffset + perm[j]] = sArray[sOffset + j];}} 3579 else {for (j = 0; j < dof; j++) {lArray[lOffset + j ] = sArray[sOffset + j];}} 3580 if (rot) {for (j = 0; j < dof; j++) {lArray[lOffset + j ] *= rot[j]; }} 3581 lOffset += dof; 3582 } 3583 PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots); 3584 .ve 3585 3586 Example of usage, adding dofs into a section array (sArray) from a local array (lArray): 3587 .vb 3588 const PetscInt **perms; 3589 const PetscScalar **rots; 3590 PetscInt lOffset; 3591 3592 PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots); 3593 for (i = 0, lOffset = 0; i < numPoints; i++) { 3594 PetscInt point = points[2*i], dof, sOffset; 3595 const PetscInt *perm = perms ? perms[i] : NULL; 3596 const PetscScalar *rot = rots ? rots[i] : NULL; 3597 3598 PetscSectionGetDof(section,point,&dof); 3599 PetscSectionGetOffset(section,point,&sOff); 3600 3601 if (perm) {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset + perm[j]] * (rot ? PetscConj(rot[perm[j]]) : 1.);}} 3602 else {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset + j ] * (rot ? PetscConj(rot[ j ]) : 1.);}} 3603 offset += dof; 3604 } 3605 PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots); 3606 .ve 3607 3608 Level: developer 3609 3610 Notes: 3611 `PetscSectionSetSym()` must have been previously called to provide the symmetries to the `PetscSection` 3612 3613 Use `PetscSectionRestorePointSyms()` when finished with the data 3614 3615 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionRestorePointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()` 3616 @*/ 3617 PetscErrorCode PetscSectionGetPointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots) 3618 { 3619 PetscSectionSym sym; 3620 3621 PetscFunctionBegin; 3622 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3623 if (numPoints) PetscAssertPointer(points, 3); 3624 if (perms) *perms = NULL; 3625 if (rots) *rots = NULL; 3626 sym = section->sym; 3627 if (sym && (perms || rots)) { 3628 SymWorkLink link; 3629 3630 if (sym->workin) { 3631 link = sym->workin; 3632 sym->workin = sym->workin->next; 3633 } else { 3634 PetscCall(PetscNew(&link)); 3635 } 3636 if (numPoints > link->numPoints) { 3637 PetscInt **perms = (PetscInt **)link->perms; 3638 PetscScalar **rots = (PetscScalar **)link->rots; 3639 PetscCall(PetscFree2(perms, rots)); 3640 PetscCall(PetscMalloc2(numPoints, (PetscInt ***)&link->perms, numPoints, (PetscScalar ***)&link->rots)); 3641 link->numPoints = numPoints; 3642 } 3643 link->next = sym->workout; 3644 sym->workout = link; 3645 PetscCall(PetscArrayzero((PetscInt **)link->perms, numPoints)); 3646 PetscCall(PetscArrayzero((PetscInt **)link->rots, numPoints)); 3647 PetscUseTypeMethod(sym, getpoints, section, numPoints, points, link->perms, link->rots); 3648 if (perms) *perms = link->perms; 3649 if (rots) *rots = link->rots; 3650 } 3651 PetscFunctionReturn(PETSC_SUCCESS); 3652 } 3653 3654 /*@C 3655 PetscSectionRestorePointSyms - Restore the symmetries returned by `PetscSectionGetPointSyms()` 3656 3657 Not Collective 3658 3659 Input Parameters: 3660 + section - the section 3661 . numPoints - the number of points 3662 . points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an 3663 arbitrary integer: its interpretation is up to sym. Orientations are used by `DM`: for their interpretation in that 3664 context, see `DMPlexGetConeOrientation()`). 3665 . perms - The permutations for the given orientations: set to `NULL` at conclusion 3666 - rots - The field rotations symmetries for the given orientations: set to `NULL` at conclusion 3667 3668 Level: developer 3669 3670 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetPointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()` 3671 @*/ 3672 PetscErrorCode PetscSectionRestorePointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots) 3673 { 3674 PetscSectionSym sym; 3675 3676 PetscFunctionBegin; 3677 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3678 sym = section->sym; 3679 if (sym && (perms || rots)) { 3680 SymWorkLink *p, link; 3681 3682 for (p = &sym->workout; (link = *p); p = &link->next) { 3683 if ((perms && link->perms == *perms) || (rots && link->rots == *rots)) { 3684 *p = link->next; 3685 link->next = sym->workin; 3686 sym->workin = link; 3687 if (perms) *perms = NULL; 3688 if (rots) *rots = NULL; 3689 PetscFunctionReturn(PETSC_SUCCESS); 3690 } 3691 } 3692 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Array was not checked out"); 3693 } 3694 PetscFunctionReturn(PETSC_SUCCESS); 3695 } 3696 3697 /*@C 3698 PetscSectionGetFieldPointSyms - Get the symmetries for a set of points in a field of a `PetscSection` under specific orientations. 3699 3700 Not Collective 3701 3702 Input Parameters: 3703 + section - the section 3704 . field - the field of the section 3705 . numPoints - the number of points 3706 - points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an 3707 arbitrary integer: its interpretation is up to sym. Orientations are used by `DM`: for their interpretation in that 3708 context, see `DMPlexGetConeOrientation()`). 3709 3710 Output Parameters: 3711 + perms - The permutations for the given orientations (or `NULL` if there is no symmetry or the permutation is the identity). 3712 - rots - The field rotations symmetries for the given orientations (or `NULL` if there is no symmetry or the rotations are all 3713 identity). 3714 3715 Level: developer 3716 3717 Notes: 3718 `PetscSectionSetFieldSym()` must have been previously called to provide the symmetries to the `PetscSection` 3719 3720 Use `PetscSectionRestoreFieldPointSyms()` when finished with the data 3721 3722 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetPointSyms()`, `PetscSectionRestoreFieldPointSyms()` 3723 @*/ 3724 PetscErrorCode PetscSectionGetFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots) 3725 { 3726 PetscFunctionBegin; 3727 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3728 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); 3729 PetscCall(PetscSectionGetPointSyms(section->field[field], numPoints, points, perms, rots)); 3730 PetscFunctionReturn(PETSC_SUCCESS); 3731 } 3732 3733 /*@C 3734 PetscSectionRestoreFieldPointSyms - Restore the symmetries returned by `PetscSectionGetFieldPointSyms()` 3735 3736 Not Collective 3737 3738 Input Parameters: 3739 + section - the section 3740 . field - the field number 3741 . numPoints - the number of points 3742 . points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an 3743 arbitrary integer: its interpretation is up to sym. Orientations are used by `DM`: for their interpretation in that 3744 context, see `DMPlexGetConeOrientation()`). 3745 . perms - The permutations for the given orientations: set to NULL at conclusion 3746 - rots - The field rotations symmetries for the given orientations: set to NULL at conclusion 3747 3748 Level: developer 3749 3750 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionRestorePointSyms()`, `petscSectionGetFieldPointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()` 3751 @*/ 3752 PetscErrorCode PetscSectionRestoreFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots) 3753 { 3754 PetscFunctionBegin; 3755 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3756 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); 3757 PetscCall(PetscSectionRestorePointSyms(section->field[field], numPoints, points, perms, rots)); 3758 PetscFunctionReturn(PETSC_SUCCESS); 3759 } 3760 3761 /*@ 3762 PetscSectionSymCopy - Copy the symmetries, assuming that the point structure is compatible 3763 3764 Not Collective 3765 3766 Input Parameter: 3767 . sym - the `PetscSectionSym` 3768 3769 Output Parameter: 3770 . nsym - the equivalent symmetries 3771 3772 Level: developer 3773 3774 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()` 3775 @*/ 3776 PetscErrorCode PetscSectionSymCopy(PetscSectionSym sym, PetscSectionSym nsym) 3777 { 3778 PetscFunctionBegin; 3779 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3780 PetscValidHeaderSpecific(nsym, PETSC_SECTION_SYM_CLASSID, 2); 3781 PetscTryTypeMethod(sym, copy, nsym); 3782 PetscFunctionReturn(PETSC_SUCCESS); 3783 } 3784 3785 /*@ 3786 PetscSectionSymDistribute - Distribute the symmetries in accordance with the input `PetscSF` 3787 3788 Collective 3789 3790 Input Parameters: 3791 + sym - the `PetscSectionSym` 3792 - migrationSF - the distribution map from roots to leaves 3793 3794 Output Parameter: 3795 . dsym - the redistributed symmetries 3796 3797 Level: developer 3798 3799 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()` 3800 @*/ 3801 PetscErrorCode PetscSectionSymDistribute(PetscSectionSym sym, PetscSF migrationSF, PetscSectionSym *dsym) 3802 { 3803 PetscFunctionBegin; 3804 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3805 PetscValidHeaderSpecific(migrationSF, PETSCSF_CLASSID, 2); 3806 PetscAssertPointer(dsym, 3); 3807 PetscTryTypeMethod(sym, distribute, migrationSF, dsym); 3808 PetscFunctionReturn(PETSC_SUCCESS); 3809 } 3810 3811 /*@ 3812 PetscSectionGetUseFieldOffsets - Get the flag indicating if field offsets are used directly in a global section, rather than just the point offset 3813 3814 Not Collective 3815 3816 Input Parameter: 3817 . s - the global `PetscSection` 3818 3819 Output Parameter: 3820 . flg - the flag 3821 3822 Level: developer 3823 3824 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSetChart()`, `PetscSectionCreate()` 3825 @*/ 3826 PetscErrorCode PetscSectionGetUseFieldOffsets(PetscSection s, PetscBool *flg) 3827 { 3828 PetscFunctionBegin; 3829 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 3830 *flg = s->useFieldOff; 3831 PetscFunctionReturn(PETSC_SUCCESS); 3832 } 3833 3834 /*@ 3835 PetscSectionSetUseFieldOffsets - Set the flag to use field offsets directly in a global section, rather than just the point offset 3836 3837 Not Collective 3838 3839 Input Parameters: 3840 + s - the global `PetscSection` 3841 - flg - the flag 3842 3843 Level: developer 3844 3845 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetUseFieldOffsets()`, `PetscSectionSetChart()`, `PetscSectionCreate()` 3846 @*/ 3847 PetscErrorCode PetscSectionSetUseFieldOffsets(PetscSection s, PetscBool flg) 3848 { 3849 PetscFunctionBegin; 3850 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 3851 s->useFieldOff = flg; 3852 PetscFunctionReturn(PETSC_SUCCESS); 3853 } 3854 3855 #define PetscSectionExpandPoints_Loop(TYPE) \ 3856 do { \ 3857 PetscInt i, n, o0, o1, size; \ 3858 TYPE *a0 = (TYPE *)origArray, *a1; \ 3859 PetscCall(PetscSectionGetStorageSize(s, &size)); \ 3860 PetscCall(PetscMalloc1(size, &a1)); \ 3861 for (i = 0; i < npoints; i++) { \ 3862 PetscCall(PetscSectionGetOffset(origSection, points_[i], &o0)); \ 3863 PetscCall(PetscSectionGetOffset(s, i, &o1)); \ 3864 PetscCall(PetscSectionGetDof(s, i, &n)); \ 3865 PetscCall(PetscMemcpy(&a1[o1], &a0[o0], n * unitsize)); \ 3866 } \ 3867 *newArray = (void *)a1; \ 3868 } while (0) 3869 3870 /*@ 3871 PetscSectionExtractDofsFromArray - Extracts elements of an array corresponding to DOFs of specified points. 3872 3873 Not Collective 3874 3875 Input Parameters: 3876 + origSection - the `PetscSection` describing the layout of the array 3877 . dataType - `MPI_Datatype` describing the data type of the array (currently only `MPIU_INT`, `MPIU_SCALAR`, `MPIU_REAL`) 3878 . origArray - the array; its size must be equal to the storage size of `origSection` 3879 - points - `IS` with points to extract; its indices must lie in the chart of `origSection` 3880 3881 Output Parameters: 3882 + newSection - the new `PetscSection` describing the layout of the new array (with points renumbered 0,1,... but preserving numbers of DOFs) 3883 - newArray - the array of the extracted DOFs; its size is the storage size of `newSection` 3884 3885 Level: developer 3886 3887 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetChart()`, `PetscSectionGetDof()`, `PetscSectionGetStorageSize()`, `PetscSectionCreate()` 3888 @*/ 3889 PetscErrorCode PetscSectionExtractDofsFromArray(PetscSection origSection, MPI_Datatype dataType, const void *origArray, IS points, PetscSection *newSection, void *newArray[]) 3890 { 3891 PetscSection s; 3892 const PetscInt *points_; 3893 PetscInt i, n, npoints, pStart, pEnd; 3894 PetscMPIInt unitsize; 3895 3896 PetscFunctionBegin; 3897 PetscValidHeaderSpecific(origSection, PETSC_SECTION_CLASSID, 1); 3898 PetscAssertPointer(origArray, 3); 3899 PetscValidHeaderSpecific(points, IS_CLASSID, 4); 3900 if (newSection) PetscAssertPointer(newSection, 5); 3901 if (newArray) PetscAssertPointer(newArray, 6); 3902 PetscCallMPI(MPI_Type_size(dataType, &unitsize)); 3903 PetscCall(ISGetLocalSize(points, &npoints)); 3904 PetscCall(ISGetIndices(points, &points_)); 3905 PetscCall(PetscSectionGetChart(origSection, &pStart, &pEnd)); 3906 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 3907 PetscCall(PetscSectionSetChart(s, 0, npoints)); 3908 for (i = 0; i < npoints; i++) { 3909 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); 3910 PetscCall(PetscSectionGetDof(origSection, points_[i], &n)); 3911 PetscCall(PetscSectionSetDof(s, i, n)); 3912 } 3913 PetscCall(PetscSectionSetUp(s)); 3914 if (newArray) { 3915 if (dataType == MPIU_INT) { 3916 PetscSectionExpandPoints_Loop(PetscInt); 3917 } else if (dataType == MPIU_SCALAR) { 3918 PetscSectionExpandPoints_Loop(PetscScalar); 3919 } else if (dataType == MPIU_REAL) { 3920 PetscSectionExpandPoints_Loop(PetscReal); 3921 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "not implemented for this MPI_Datatype"); 3922 } 3923 if (newSection) { 3924 *newSection = s; 3925 } else { 3926 PetscCall(PetscSectionDestroy(&s)); 3927 } 3928 PetscCall(ISRestoreIndices(points, &points_)); 3929 PetscFunctionReturn(PETSC_SUCCESS); 3930 } 3931