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, MPI_C_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) PetscCall(PetscSectionGetDof(s->bc, point, numDof)); 1118 else *numDof = 0; 1119 PetscFunctionReturn(PETSC_SUCCESS); 1120 } 1121 1122 /*@ 1123 PetscSectionSetConstraintDof - Set the number of constrained degrees of freedom associated with a given point. 1124 1125 Not Collective 1126 1127 Input Parameters: 1128 + s - the `PetscSection` 1129 . point - the point 1130 - numDof - the number of dof which are fixed by constraints 1131 1132 Level: intermediate 1133 1134 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSetDof()`, `PetscSectionGetConstraintDof()`, `PetscSectionCreate()` 1135 @*/ 1136 PetscErrorCode PetscSectionSetConstraintDof(PetscSection s, PetscInt point, PetscInt numDof) 1137 { 1138 PetscFunctionBegin; 1139 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1140 if (numDof) { 1141 PetscCall(PetscSectionCheckConstraints_Private(s)); 1142 PetscCall(PetscSectionSetDof(s->bc, point, numDof)); 1143 } 1144 PetscFunctionReturn(PETSC_SUCCESS); 1145 } 1146 1147 /*@ 1148 PetscSectionAddConstraintDof - Increment the number of constrained degrees of freedom associated with a given point. 1149 1150 Not Collective 1151 1152 Input Parameters: 1153 + s - the `PetscSection` 1154 . point - the point 1155 - numDof - the number of additional dof which are fixed by constraints 1156 1157 Level: intermediate 1158 1159 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionAddDof()`, `PetscSectionGetConstraintDof()`, `PetscSectionCreate()` 1160 @*/ 1161 PetscErrorCode PetscSectionAddConstraintDof(PetscSection s, PetscInt point, PetscInt numDof) 1162 { 1163 PetscFunctionBegin; 1164 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1165 if (numDof) { 1166 PetscCall(PetscSectionCheckConstraints_Private(s)); 1167 PetscCall(PetscSectionAddDof(s->bc, point, numDof)); 1168 } 1169 PetscFunctionReturn(PETSC_SUCCESS); 1170 } 1171 1172 /*@ 1173 PetscSectionGetFieldConstraintDof - Return the number of constrained degrees of freedom associated with a given field on a point. 1174 1175 Not Collective 1176 1177 Input Parameters: 1178 + s - the `PetscSection` 1179 . point - the point 1180 - field - the field 1181 1182 Output Parameter: 1183 . numDof - the number of dof which are fixed by constraints 1184 1185 Level: intermediate 1186 1187 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetFieldConstraintDof()`, `PetscSectionCreate()` 1188 @*/ 1189 PetscErrorCode PetscSectionGetFieldConstraintDof(PetscSection s, PetscInt point, PetscInt field, PetscInt *numDof) 1190 { 1191 PetscFunctionBegin; 1192 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1193 PetscAssertPointer(numDof, 4); 1194 PetscSectionCheckValidField(field, s->numFields); 1195 PetscCall(PetscSectionGetConstraintDof(s->field[field], point, numDof)); 1196 PetscFunctionReturn(PETSC_SUCCESS); 1197 } 1198 1199 /*@ 1200 PetscSectionSetFieldConstraintDof - Set the number of constrained degrees of freedom associated with a given field on a point. 1201 1202 Not Collective 1203 1204 Input Parameters: 1205 + s - the `PetscSection` 1206 . point - the point 1207 . field - the field 1208 - numDof - the number of dof which are fixed by constraints 1209 1210 Level: intermediate 1211 1212 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSetDof()`, `PetscSectionGetFieldConstraintDof()`, `PetscSectionCreate()` 1213 @*/ 1214 PetscErrorCode PetscSectionSetFieldConstraintDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof) 1215 { 1216 PetscFunctionBegin; 1217 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1218 PetscSectionCheckValidField(field, s->numFields); 1219 PetscCall(PetscSectionSetConstraintDof(s->field[field], point, numDof)); 1220 PetscFunctionReturn(PETSC_SUCCESS); 1221 } 1222 1223 /*@ 1224 PetscSectionAddFieldConstraintDof - Increment the number of constrained degrees of freedom associated with a given field on a point. 1225 1226 Not Collective 1227 1228 Input Parameters: 1229 + s - the `PetscSection` 1230 . point - the point 1231 . field - the field 1232 - numDof - the number of additional dof which are fixed by constraints 1233 1234 Level: intermediate 1235 1236 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionAddDof()`, `PetscSectionGetFieldConstraintDof()`, `PetscSectionCreate()` 1237 @*/ 1238 PetscErrorCode PetscSectionAddFieldConstraintDof(PetscSection s, PetscInt point, PetscInt field, PetscInt numDof) 1239 { 1240 PetscFunctionBegin; 1241 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1242 PetscSectionCheckValidField(field, s->numFields); 1243 PetscCall(PetscSectionAddConstraintDof(s->field[field], point, numDof)); 1244 PetscFunctionReturn(PETSC_SUCCESS); 1245 } 1246 1247 /*@ 1248 PetscSectionSetUpBC - Setup the subsections describing boundary conditions. 1249 1250 Not Collective 1251 1252 Input Parameter: 1253 . s - the `PetscSection` 1254 1255 Level: advanced 1256 1257 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSetUp()`, `PetscSectionCreate()` 1258 @*/ 1259 PetscErrorCode PetscSectionSetUpBC(PetscSection s) 1260 { 1261 PetscFunctionBegin; 1262 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1263 if (s->bc) { 1264 const PetscInt last = (s->bc->pEnd - s->bc->pStart) - 1; 1265 1266 PetscCall(PetscSectionSetUp(s->bc)); 1267 if (last >= 0) PetscCall(PetscMalloc1(s->bc->atlasOff[last] + s->bc->atlasDof[last], &s->bcIndices)); 1268 else s->bcIndices = NULL; 1269 } 1270 PetscFunctionReturn(PETSC_SUCCESS); 1271 } 1272 1273 /*@ 1274 PetscSectionSetUp - Calculate offsets based upon the number of degrees of freedom for each point in preparation for use of the `PetscSection` 1275 1276 Not Collective 1277 1278 Input Parameter: 1279 . s - the `PetscSection` 1280 1281 Level: intermediate 1282 1283 Notes: 1284 If used, `PetscSectionSetPermutation()` must be called before this routine. 1285 1286 `PetscSectionSetPointMajor()`, cannot be called after this routine. 1287 1288 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionSetPermutation()` 1289 @*/ 1290 PetscErrorCode PetscSectionSetUp(PetscSection s) 1291 { 1292 PetscInt f; 1293 const PetscInt *pind = NULL; 1294 PetscCount offset = 0; 1295 1296 PetscFunctionBegin; 1297 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1298 if (s->setup) PetscFunctionReturn(PETSC_SUCCESS); 1299 s->setup = PETSC_TRUE; 1300 /* Set offsets and field offsets for all points */ 1301 /* Assume that all fields have the same chart */ 1302 PetscCheck(s->includesConstraints, PETSC_COMM_SELF, PETSC_ERR_SUP, "PetscSectionSetUp is currently unsupported for includesConstraints = PETSC_TRUE"); 1303 if (s->perm) PetscCall(ISGetIndices(s->perm, &pind)); 1304 if (s->pointMajor) { 1305 PetscCount foff; 1306 for (PetscInt p = 0; p < s->pEnd - s->pStart; ++p) { 1307 const PetscInt q = pind ? pind[p] : p; 1308 1309 /* Set point offset */ 1310 PetscCall(PetscIntCast(offset, &s->atlasOff[q])); 1311 offset += s->atlasDof[q]; 1312 /* Set field offset */ 1313 for (f = 0, foff = s->atlasOff[q]; f < s->numFields; ++f) { 1314 PetscSection sf = s->field[f]; 1315 1316 PetscCall(PetscIntCast(foff, &sf->atlasOff[q])); 1317 foff += sf->atlasDof[q]; 1318 } 1319 } 1320 } else { 1321 /* Set field offsets for all points */ 1322 for (f = 0; f < s->numFields; ++f) { 1323 PetscSection sf = s->field[f]; 1324 1325 for (PetscInt p = 0; p < s->pEnd - s->pStart; ++p) { 1326 const PetscInt q = pind ? pind[p] : p; 1327 1328 PetscCall(PetscIntCast(offset, &sf->atlasOff[q])); 1329 offset += sf->atlasDof[q]; 1330 } 1331 } 1332 /* Disable point offsets since these are unused */ 1333 for (PetscInt p = 0; p < s->pEnd - s->pStart; ++p) s->atlasOff[p] = -1; 1334 } 1335 if (s->perm) PetscCall(ISRestoreIndices(s->perm, &pind)); 1336 /* Setup BC sections */ 1337 PetscCall(PetscSectionSetUpBC(s)); 1338 for (f = 0; f < s->numFields; ++f) PetscCall(PetscSectionSetUpBC(s->field[f])); 1339 PetscFunctionReturn(PETSC_SUCCESS); 1340 } 1341 1342 /*@ 1343 PetscSectionGetMaxDof - Return the maximum number of degrees of freedom on any point in the `PetscSection` 1344 1345 Not Collective 1346 1347 Input Parameter: 1348 . s - the `PetscSection` 1349 1350 Output Parameter: 1351 . maxDof - the maximum dof 1352 1353 Level: intermediate 1354 1355 Notes: 1356 The returned number is up-to-date without need for `PetscSectionSetUp()`. 1357 1358 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 1359 the maximum over all points of the value returned by `PetscSectionGetDof()` on this MPI process 1360 1361 Developer Notes: 1362 The returned number is calculated lazily and stashed. 1363 1364 A call to `PetscSectionInvalidateMaxDof_Internal()` invalidates the stashed value. 1365 1366 `PetscSectionInvalidateMaxDof_Internal()` is called in `PetscSectionSetDof()`, `PetscSectionAddDof()` and `PetscSectionReset()` 1367 1368 It should also be called every time `atlasDof` is modified directly. 1369 1370 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetDof()`, `PetscSectionAddDof()`, `PetscSectionCreate()` 1371 @*/ 1372 PetscErrorCode PetscSectionGetMaxDof(PetscSection s, PetscInt *maxDof) 1373 { 1374 PetscInt p; 1375 1376 PetscFunctionBegin; 1377 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1378 PetscAssertPointer(maxDof, 2); 1379 if (s->maxDof == PETSC_INT_MIN) { 1380 s->maxDof = 0; 1381 for (p = 0; p < s->pEnd - s->pStart; ++p) s->maxDof = PetscMax(s->maxDof, s->atlasDof[p]); 1382 } 1383 *maxDof = s->maxDof; 1384 PetscFunctionReturn(PETSC_SUCCESS); 1385 } 1386 1387 /*@ 1388 PetscSectionGetStorageSize - Return the size of an array or local `Vec` capable of holding all the degrees of freedom defined in a `PetscSection` 1389 1390 Not Collective 1391 1392 Input Parameter: 1393 . s - the `PetscSection` 1394 1395 Output Parameter: 1396 . size - the size of an array which can hold all the dofs 1397 1398 Level: intermediate 1399 1400 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionGetConstrainedStorageSize()`, `PetscSectionCreate()` 1401 @*/ 1402 PetscErrorCode PetscSectionGetStorageSize(PetscSection s, PetscInt *size) 1403 { 1404 PetscInt64 n = 0; 1405 1406 PetscFunctionBegin; 1407 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1408 PetscAssertPointer(size, 2); 1409 for (PetscInt p = 0; p < s->pEnd - s->pStart; ++p) n += s->atlasDof[p] > 0 ? s->atlasDof[p] : 0; 1410 PetscCall(PetscIntCast(n, size)); 1411 PetscFunctionReturn(PETSC_SUCCESS); 1412 } 1413 1414 /*@ 1415 PetscSectionGetConstrainedStorageSize - Return the size of an array or local `Vec` capable of holding all unconstrained degrees of freedom in a `PetscSection` 1416 1417 Not Collective 1418 1419 Input Parameter: 1420 . s - the `PetscSection` 1421 1422 Output Parameter: 1423 . size - the size of an array which can hold all unconstrained dofs 1424 1425 Level: intermediate 1426 1427 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetStorageSize()`, `PetscSectionGetOffset()`, `PetscSectionCreate()` 1428 @*/ 1429 PetscErrorCode PetscSectionGetConstrainedStorageSize(PetscSection s, PetscInt *size) 1430 { 1431 PetscInt64 n = 0; 1432 1433 PetscFunctionBegin; 1434 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1435 PetscAssertPointer(size, 2); 1436 for (PetscInt p = 0; p < s->pEnd - s->pStart; ++p) { 1437 const PetscInt cdof = s->bc ? s->bc->atlasDof[p] : 0; 1438 n += s->atlasDof[p] > 0 ? s->atlasDof[p] - cdof : 0; 1439 } 1440 PetscCall(PetscIntCast(n, size)); 1441 PetscFunctionReturn(PETSC_SUCCESS); 1442 } 1443 1444 /*@ 1445 PetscSectionCreateGlobalSection - Create a parallel section describing the global layout using 1446 a local (sequential) `PetscSection` on each MPI process and a `PetscSF` describing the section point overlap. 1447 1448 Input Parameters: 1449 + s - The `PetscSection` for the local field layout 1450 . sf - The `PetscSF` describing parallel layout of the section points (leaves are unowned local points) 1451 . usePermutation - By default this is `PETSC_TRUE`, meaning any permutation of the local section is transferred to the global section 1452 . includeConstraints - By default this is `PETSC_FALSE`, meaning that the global field vector will not possess constrained dofs 1453 - localOffsets - If `PETSC_TRUE`, use local rather than global offsets for the points 1454 1455 Output Parameter: 1456 . gsection - The `PetscSection` for the global field layout 1457 1458 Level: intermediate 1459 1460 Notes: 1461 On each MPI process `gsection` inherits the chart of the `s` on that process. 1462 1463 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`. 1464 In those locations the value of size is -(size+1) and the value of the offset on the remote process is -(off+1). 1465 1466 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionCreateGlobalSectionCensored()` 1467 @*/ 1468 PetscErrorCode PetscSectionCreateGlobalSection(PetscSection s, PetscSF sf, PetscBool usePermutation, PetscBool includeConstraints, PetscBool localOffsets, PetscSection *gsection) 1469 { 1470 PetscSection gs; 1471 const PetscInt *pind = NULL; 1472 PetscInt *recv = NULL, *neg = NULL; 1473 PetscInt pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots, nlocal, maxleaf; 1474 PetscInt numFields, f, numComponents; 1475 PetscInt foff; 1476 1477 PetscFunctionBegin; 1478 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1479 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2); 1480 PetscValidLogicalCollectiveBool(s, usePermutation, 3); 1481 PetscValidLogicalCollectiveBool(s, includeConstraints, 4); 1482 PetscValidLogicalCollectiveBool(s, localOffsets, 5); 1483 PetscAssertPointer(gsection, 6); 1484 PetscCheck(s->pointMajor, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for field major ordering"); 1485 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), &gs)); 1486 PetscCall(PetscSectionGetNumFields(s, &numFields)); 1487 if (numFields > 0) PetscCall(PetscSectionSetNumFields(gs, numFields)); 1488 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 1489 PetscCall(PetscSectionSetChart(gs, pStart, pEnd)); 1490 gs->includesConstraints = includeConstraints; 1491 PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL)); 1492 nlocal = nroots; /* The local/leaf space matches global/root space */ 1493 /* Must allocate for all points visible to SF, which may be more than this section */ 1494 if (nroots >= 0) { /* nroots < 0 means that the graph has not been set, only happens in serial */ 1495 PetscCall(PetscSFGetLeafRange(sf, NULL, &maxleaf)); 1496 PetscCheck(nroots >= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "SF roots %" PetscInt_FMT " < pEnd %" PetscInt_FMT, nroots, pEnd); 1497 PetscCheck(maxleaf < nroots, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Max local leaf %" PetscInt_FMT " >= nroots %" PetscInt_FMT, maxleaf, nroots); 1498 PetscCall(PetscMalloc2(nroots, &neg, nlocal, &recv)); 1499 PetscCall(PetscArrayzero(neg, nroots)); 1500 } 1501 /* Mark all local points with negative dof */ 1502 for (p = pStart; p < pEnd; ++p) { 1503 PetscCall(PetscSectionGetDof(s, p, &dof)); 1504 PetscCall(PetscSectionSetDof(gs, p, dof)); 1505 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 1506 if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetConstraintDof(gs, p, cdof)); 1507 if (neg) neg[p] = -(dof + 1); 1508 } 1509 PetscCall(PetscSectionSetUpBC(gs)); 1510 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])); 1511 if (nroots >= 0) { 1512 PetscCall(PetscArrayzero(recv, nlocal)); 1513 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, recv, MPI_REPLACE)); 1514 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, recv, MPI_REPLACE)); 1515 for (p = pStart; p < pEnd; ++p) { 1516 if (recv[p] < 0) { 1517 gs->atlasDof[p - pStart] = recv[p]; 1518 PetscCall(PetscSectionGetDof(s, p, &dof)); 1519 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); 1520 } 1521 } 1522 } 1523 /* Calculate new sizes, get process offset, and calculate point offsets */ 1524 if (usePermutation && s->perm) PetscCall(ISGetIndices(s->perm, &pind)); 1525 for (p = 0, off = 0; p < pEnd - pStart; ++p) { 1526 const PetscInt q = pind ? pind[p] : p; 1527 1528 cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[q] : 0; 1529 gs->atlasOff[q] = off; 1530 off += gs->atlasDof[q] > 0 ? gs->atlasDof[q] - cdof : 0; 1531 } 1532 if (!localOffsets) { 1533 PetscCallMPI(MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)sf))); 1534 globalOff -= off; 1535 } 1536 for (p = pStart, off = 0; p < pEnd; ++p) { 1537 gs->atlasOff[p - pStart] += globalOff; 1538 if (neg) neg[p] = -(gs->atlasOff[p - pStart] + 1); 1539 } 1540 if (usePermutation && s->perm) PetscCall(ISRestoreIndices(s->perm, &pind)); 1541 /* Put in negative offsets for ghost points */ 1542 if (nroots >= 0) { 1543 PetscCall(PetscArrayzero(recv, nlocal)); 1544 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, recv, MPI_REPLACE)); 1545 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, recv, MPI_REPLACE)); 1546 for (p = pStart; p < pEnd; ++p) { 1547 if (recv[p] < 0) gs->atlasOff[p - pStart] = recv[p]; 1548 } 1549 } 1550 PetscCall(PetscFree2(neg, recv)); 1551 /* Set field dofs/offsets/constraints */ 1552 for (f = 0; f < numFields; ++f) { 1553 const char *name; 1554 1555 gs->field[f]->includesConstraints = includeConstraints; 1556 PetscCall(PetscSectionGetFieldComponents(s, f, &numComponents)); 1557 PetscCall(PetscSectionSetFieldComponents(gs, f, numComponents)); 1558 PetscCall(PetscSectionGetFieldName(s, f, &name)); 1559 PetscCall(PetscSectionSetFieldName(gs, f, name)); 1560 } 1561 for (p = pStart; p < pEnd; ++p) { 1562 PetscCall(PetscSectionGetOffset(gs, p, &off)); 1563 for (f = 0, foff = off; f < numFields; ++f) { 1564 PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof)); 1565 if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetFieldConstraintDof(gs, p, f, cdof)); 1566 PetscCall(PetscSectionGetFieldDof(s, p, f, &dof)); 1567 PetscCall(PetscSectionSetFieldDof(gs, p, f, off < 0 ? -(dof + 1) : dof)); 1568 PetscCall(PetscSectionSetFieldOffset(gs, p, f, foff)); 1569 PetscCall(PetscSectionGetFieldConstraintDof(gs, p, f, &cdof)); 1570 foff = off < 0 ? foff - (dof - cdof) : foff + (dof - cdof); 1571 } 1572 } 1573 for (f = 0; f < numFields; ++f) { 1574 PetscSection gfs = gs->field[f]; 1575 1576 PetscCall(PetscSectionSetUpBC(gfs)); 1577 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])); 1578 } 1579 gs->setup = PETSC_TRUE; 1580 PetscCall(PetscSectionViewFromOptions(gs, NULL, "-global_section_view")); 1581 *gsection = gs; 1582 PetscFunctionReturn(PETSC_SUCCESS); 1583 } 1584 1585 /*@ 1586 PetscSectionCreateGlobalSectionCensored - Create a `PetscSection` describing the globallayout using 1587 a local (sequential) `PetscSection` on each MPI process and an `PetscSF` describing the section point overlap. 1588 1589 Input Parameters: 1590 + s - The `PetscSection` for the local field layout 1591 . sf - The `PetscSF` describing parallel layout of the section points 1592 . includeConstraints - By default this is `PETSC_FALSE`, meaning that the global vector will not possess constrained dofs 1593 . numExcludes - The number of exclusion ranges, this must have the same value on all MPI processes 1594 - 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 1595 1596 Output Parameter: 1597 . gsection - The `PetscSection` for the global field layout 1598 1599 Level: advanced 1600 1601 Notes: 1602 On each MPI process `gsection` inherits the chart of the `s` on that process. 1603 1604 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`. 1605 In those locations the value of size is -(size+1) and the value of the offset on the remote process is -(off+1). 1606 1607 This routine augments `PetscSectionCreateGlobalSection()` by allowing one to exclude certain ranges in the chart of the `PetscSection` 1608 1609 Developer Notes: 1610 This is a terrible function name 1611 1612 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()` 1613 @*/ 1614 PetscErrorCode PetscSectionCreateGlobalSectionCensored(PetscSection s, PetscSF sf, PetscBool includeConstraints, PetscInt numExcludes, const PetscInt excludes[], PetscSection *gsection) 1615 { 1616 const PetscInt *pind = NULL; 1617 PetscInt *neg = NULL, *tmpOff = NULL; 1618 PetscInt pStart, pEnd, p, e, dof, cdof, globalOff = 0, nroots; 1619 PetscInt off; 1620 1621 PetscFunctionBegin; 1622 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1623 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2); 1624 PetscAssertPointer(gsection, 6); 1625 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), gsection)); 1626 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 1627 PetscCall(PetscSectionSetChart(*gsection, pStart, pEnd)); 1628 PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL)); 1629 if (nroots >= 0) { 1630 PetscCheck(nroots >= pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %" PetscInt_FMT " < %" PetscInt_FMT " section size", nroots, pEnd - pStart); 1631 PetscCall(PetscCalloc1(nroots, &neg)); 1632 if (nroots > pEnd - pStart) { 1633 PetscCall(PetscCalloc1(nroots, &tmpOff)); 1634 } else { 1635 tmpOff = &(*gsection)->atlasDof[-pStart]; 1636 } 1637 } 1638 /* Mark ghost points with negative dof */ 1639 for (p = pStart; p < pEnd; ++p) { 1640 for (e = 0; e < numExcludes; ++e) { 1641 if ((p >= excludes[e * 2 + 0]) && (p < excludes[e * 2 + 1])) { 1642 PetscCall(PetscSectionSetDof(*gsection, p, 0)); 1643 break; 1644 } 1645 } 1646 if (e < numExcludes) continue; 1647 PetscCall(PetscSectionGetDof(s, p, &dof)); 1648 PetscCall(PetscSectionSetDof(*gsection, p, dof)); 1649 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 1650 if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetConstraintDof(*gsection, p, cdof)); 1651 if (neg) neg[p] = -(dof + 1); 1652 } 1653 PetscCall(PetscSectionSetUpBC(*gsection)); 1654 if (nroots >= 0) { 1655 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE)); 1656 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE)); 1657 if (nroots > pEnd - pStart) { 1658 for (p = pStart; p < pEnd; ++p) { 1659 if (tmpOff[p] < 0) (*gsection)->atlasDof[p - pStart] = tmpOff[p]; 1660 } 1661 } 1662 } 1663 /* Calculate new sizes, get process offset, and calculate point offsets */ 1664 if (s->perm) PetscCall(ISGetIndices(s->perm, &pind)); 1665 for (p = 0, off = 0; p < pEnd - pStart; ++p) { 1666 const PetscInt q = pind ? pind[p] : p; 1667 1668 cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[q] : 0; 1669 (*gsection)->atlasOff[q] = off; 1670 off += (*gsection)->atlasDof[q] > 0 ? (*gsection)->atlasDof[q] - cdof : 0; 1671 } 1672 PetscCallMPI(MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)s))); 1673 globalOff -= off; 1674 for (p = 0, off = 0; p < pEnd - pStart; ++p) { 1675 (*gsection)->atlasOff[p] += globalOff; 1676 if (neg) neg[p + pStart] = -((*gsection)->atlasOff[p] + 1); 1677 } 1678 if (s->perm) PetscCall(ISRestoreIndices(s->perm, &pind)); 1679 /* Put in negative offsets for ghost points */ 1680 if (nroots >= 0) { 1681 if (nroots == pEnd - pStart) tmpOff = &(*gsection)->atlasOff[-pStart]; 1682 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE)); 1683 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE)); 1684 if (nroots > pEnd - pStart) { 1685 for (p = pStart; p < pEnd; ++p) { 1686 if (tmpOff[p] < 0) (*gsection)->atlasOff[p - pStart] = tmpOff[p]; 1687 } 1688 } 1689 } 1690 if (nroots >= 0 && nroots > pEnd - pStart) PetscCall(PetscFree(tmpOff)); 1691 PetscCall(PetscFree(neg)); 1692 PetscFunctionReturn(PETSC_SUCCESS); 1693 } 1694 1695 /*@ 1696 PetscSectionGetPointLayout - Get a `PetscLayout` for the points with nonzero dof counts of the unnamed default field within this `PetscSection`s local chart 1697 1698 Collective 1699 1700 Input Parameters: 1701 + comm - The `MPI_Comm` 1702 - s - The `PetscSection` 1703 1704 Output Parameter: 1705 . layout - The point layout for the data that defines the section 1706 1707 Level: advanced 1708 1709 Notes: 1710 `PetscSectionGetValueLayout()` provides similar information but counting the total number of degrees of freedom on the MPI process (excluding constrained 1711 degrees of freedom). 1712 1713 This count includes constrained degrees of freedom 1714 1715 This is usually called on the default global section. 1716 1717 Example: 1718 .vb 1719 The chart is [2,5), point 2 has 2 dof, point 3 has 0 dof, point 4 has 1 dof 1720 The local size of the `PetscLayout` is 2 since 2 points have a non-zero number of dof 1721 .ve 1722 1723 Developer Notes: 1724 I find the names of these two functions extremely non-informative 1725 1726 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetValueLayout()`, `PetscSectionCreate()` 1727 @*/ 1728 PetscErrorCode PetscSectionGetPointLayout(MPI_Comm comm, PetscSection s, PetscLayout *layout) 1729 { 1730 PetscInt pStart, pEnd, p, localSize = 0; 1731 1732 PetscFunctionBegin; 1733 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 1734 for (p = pStart; p < pEnd; ++p) { 1735 PetscInt dof; 1736 1737 PetscCall(PetscSectionGetDof(s, p, &dof)); 1738 if (dof >= 0) ++localSize; 1739 } 1740 PetscCall(PetscLayoutCreate(comm, layout)); 1741 PetscCall(PetscLayoutSetLocalSize(*layout, localSize)); 1742 PetscCall(PetscLayoutSetBlockSize(*layout, 1)); 1743 PetscCall(PetscLayoutSetUp(*layout)); 1744 PetscFunctionReturn(PETSC_SUCCESS); 1745 } 1746 1747 /*@ 1748 PetscSectionGetValueLayout - Get the `PetscLayout` associated with the section dofs of a `PetscSection` 1749 1750 Collective 1751 1752 Input Parameters: 1753 + comm - The `MPI_Comm` 1754 - s - The `PetscSection` 1755 1756 Output Parameter: 1757 . layout - The dof layout for the section 1758 1759 Level: advanced 1760 1761 Notes: 1762 `PetscSectionGetPointLayout()` provides similar information but only counting the number of points with nonzero degrees of freedom and 1763 including the constrained degrees of freedom 1764 1765 This is usually called for the default global section. 1766 1767 Example: 1768 .vb 1769 The chart is [2,5), point 2 has 4 dof (2 constrained), point 3 has 0 dof, point 4 has 1 dof (not constrained) 1770 The local size of the `PetscLayout` is 3 since there are 3 unconstrained degrees of freedom on this MPI process 1771 .ve 1772 1773 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetPointLayout()`, `PetscSectionCreate()` 1774 @*/ 1775 PetscErrorCode PetscSectionGetValueLayout(MPI_Comm comm, PetscSection s, PetscLayout *layout) 1776 { 1777 PetscInt pStart, pEnd, p, localSize = 0; 1778 1779 PetscFunctionBegin; 1780 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2); 1781 PetscAssertPointer(layout, 3); 1782 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 1783 for (p = pStart; p < pEnd; ++p) { 1784 PetscInt dof, cdof; 1785 1786 PetscCall(PetscSectionGetDof(s, p, &dof)); 1787 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 1788 if (dof - cdof > 0) localSize += dof - cdof; 1789 } 1790 PetscCall(PetscLayoutCreate(comm, layout)); 1791 PetscCall(PetscLayoutSetLocalSize(*layout, localSize)); 1792 PetscCall(PetscLayoutSetBlockSize(*layout, 1)); 1793 PetscCall(PetscLayoutSetUp(*layout)); 1794 PetscFunctionReturn(PETSC_SUCCESS); 1795 } 1796 1797 /*@ 1798 PetscSectionGetOffset - Return the offset into an array or `Vec` for the dof associated with the given point. 1799 1800 Not Collective 1801 1802 Input Parameters: 1803 + s - the `PetscSection` 1804 - point - the point 1805 1806 Output Parameter: 1807 . offset - the offset 1808 1809 Level: intermediate 1810 1811 Notes: 1812 In a global section, `offset` will be negative for points not owned by this process. 1813 1814 This is for the unnamed default field in the `PetscSection` not the named fields 1815 1816 The `offset` values are different depending on a value set with `PetscSectionSetPointMajor()` 1817 1818 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionCreate()`, `PetscSectionSetPointMajor()` 1819 @*/ 1820 PetscErrorCode PetscSectionGetOffset(PetscSection s, PetscInt point, PetscInt *offset) 1821 { 1822 PetscFunctionBegin; 1823 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1824 PetscAssertPointer(offset, 3); 1825 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); 1826 *offset = s->atlasOff[point - s->pStart]; 1827 PetscFunctionReturn(PETSC_SUCCESS); 1828 } 1829 1830 /*@ 1831 PetscSectionSetOffset - Set the offset into an array or `Vec` for the dof associated with the given point. 1832 1833 Not Collective 1834 1835 Input Parameters: 1836 + s - the `PetscSection` 1837 . point - the point 1838 - offset - the offset, these values may be negative indicating the values are off process 1839 1840 Level: developer 1841 1842 Note: 1843 The user usually does not call this function, but uses `PetscSectionSetUp()` 1844 1845 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionCreate()`, `PetscSectionSetUp()` 1846 @*/ 1847 PetscErrorCode PetscSectionSetOffset(PetscSection s, PetscInt point, PetscInt offset) 1848 { 1849 PetscFunctionBegin; 1850 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1851 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); 1852 s->atlasOff[point - s->pStart] = offset; 1853 PetscFunctionReturn(PETSC_SUCCESS); 1854 } 1855 1856 /*@ 1857 PetscSectionGetFieldOffset - Return the offset into an array or `Vec` for the field dof associated with the given point. 1858 1859 Not Collective 1860 1861 Input Parameters: 1862 + s - the `PetscSection` 1863 . point - the point 1864 - field - the field 1865 1866 Output Parameter: 1867 . offset - the offset 1868 1869 Level: intermediate 1870 1871 Notes: 1872 In a global section, `offset` will be negative for points not owned by this process. 1873 1874 The `offset` values are different depending on a value set with `PetscSectionSetPointMajor()` 1875 1876 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()`, `PetscSectionGetFieldPointOffset()` 1877 @*/ 1878 PetscErrorCode PetscSectionGetFieldOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt *offset) 1879 { 1880 PetscFunctionBegin; 1881 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1882 PetscAssertPointer(offset, 4); 1883 PetscSectionCheckValidField(field, s->numFields); 1884 PetscCall(PetscSectionGetOffset(s->field[field], point, offset)); 1885 PetscFunctionReturn(PETSC_SUCCESS); 1886 } 1887 1888 /*@ 1889 PetscSectionSetFieldOffset - Set the offset into an array or `Vec` for the dof associated with the given field at a point. 1890 1891 Not Collective 1892 1893 Input Parameters: 1894 + s - the `PetscSection` 1895 . point - the point 1896 . field - the field 1897 - offset - the offset, these values may be negative indicating the values are off process 1898 1899 Level: developer 1900 1901 Note: 1902 The user usually does not call this function, but uses `PetscSectionSetUp()` 1903 1904 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionSetOffset()`, `PetscSectionCreate()`, `PetscSectionSetUp()` 1905 @*/ 1906 PetscErrorCode PetscSectionSetFieldOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt offset) 1907 { 1908 PetscFunctionBegin; 1909 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1910 PetscSectionCheckValidField(field, s->numFields); 1911 PetscCall(PetscSectionSetOffset(s->field[field], point, offset)); 1912 PetscFunctionReturn(PETSC_SUCCESS); 1913 } 1914 1915 /*@ 1916 PetscSectionGetFieldPointOffset - Return the offset for the first field dof associated with the given point relative to the offset for that point for the 1917 unnamed default field's first dof 1918 1919 Not Collective 1920 1921 Input Parameters: 1922 + s - the `PetscSection` 1923 . point - the point 1924 - field - the field 1925 1926 Output Parameter: 1927 . offset - the offset 1928 1929 Level: advanced 1930 1931 Note: 1932 This ignores constraints 1933 1934 Example: 1935 .vb 1936 if PetscSectionSetPointMajor(s,PETSC_TRUE) 1937 The unnamed default field has 3 dof at `point` 1938 Field 0 has 2 dof at `point` 1939 Then PetscSectionGetFieldPointOffset(s,point,1,&offset) returns and offset of 5 1940 .ve 1941 1942 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()`, `PetscSectionGetFieldOffset()` 1943 @*/ 1944 PetscErrorCode PetscSectionGetFieldPointOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt *offset) 1945 { 1946 PetscInt off, foff; 1947 1948 PetscFunctionBegin; 1949 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1950 PetscAssertPointer(offset, 4); 1951 PetscSectionCheckValidField(field, s->numFields); 1952 PetscCall(PetscSectionGetOffset(s, point, &off)); 1953 PetscCall(PetscSectionGetOffset(s->field[field], point, &foff)); 1954 *offset = foff - off; 1955 PetscFunctionReturn(PETSC_SUCCESS); 1956 } 1957 1958 /*@ 1959 PetscSectionGetOffsetRange - Return the full range of offsets [`start`, `end`) for a `PetscSection` 1960 1961 Not Collective 1962 1963 Input Parameter: 1964 . s - the `PetscSection` 1965 1966 Output Parameters: 1967 + start - the minimum offset 1968 - end - one more than the maximum offset 1969 1970 Level: intermediate 1971 1972 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()` 1973 @*/ 1974 PetscErrorCode PetscSectionGetOffsetRange(PetscSection s, PetscInt *start, PetscInt *end) 1975 { 1976 PetscInt os = 0, oe = 0, pStart, pEnd, p; 1977 1978 PetscFunctionBegin; 1979 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1980 if (s->atlasOff) { 1981 os = s->atlasOff[0]; 1982 oe = s->atlasOff[0]; 1983 } 1984 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 1985 for (p = 0; p < pEnd - pStart; ++p) { 1986 PetscInt dof = s->atlasDof[p], off = s->atlasOff[p]; 1987 1988 if (off >= 0) { 1989 os = PetscMin(os, off); 1990 oe = PetscMax(oe, off + dof); 1991 } 1992 } 1993 if (start) *start = os; 1994 if (end) *end = oe; 1995 PetscFunctionReturn(PETSC_SUCCESS); 1996 } 1997 1998 /*@ 1999 PetscSectionCreateSubsection - Create a new, smaller `PetscSection` composed of only selected fields 2000 2001 Collective 2002 2003 Input Parameters: 2004 + s - the `PetscSection` 2005 . len - the number of subfields 2006 - fields - the subfield numbers 2007 2008 Output Parameter: 2009 . subs - the subsection 2010 2011 Level: advanced 2012 2013 Notes: 2014 The chart of `subs` is the same as the chart of `s` 2015 2016 This will error if a fieldnumber is out of range 2017 2018 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreateSupersection()`, `PetscSectionCreate()` 2019 @*/ 2020 PetscErrorCode PetscSectionCreateSubsection(PetscSection s, PetscInt len, const PetscInt fields[], PetscSection *subs) 2021 { 2022 PetscInt nF, f, c, pStart, pEnd, p, maxCdof = 0; 2023 2024 PetscFunctionBegin; 2025 if (!len) PetscFunctionReturn(PETSC_SUCCESS); 2026 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2027 PetscAssertPointer(fields, 3); 2028 PetscAssertPointer(subs, 4); 2029 PetscCall(PetscSectionGetNumFields(s, &nF)); 2030 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); 2031 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), subs)); 2032 PetscCall(PetscSectionSetNumFields(*subs, len)); 2033 for (f = 0; f < len; ++f) { 2034 const char *name = NULL; 2035 PetscInt numComp = 0; 2036 PetscSectionSym sym; 2037 2038 PetscCall(PetscSectionGetFieldName(s, fields[f], &name)); 2039 PetscCall(PetscSectionSetFieldName(*subs, f, name)); 2040 PetscCall(PetscSectionGetFieldComponents(s, fields[f], &numComp)); 2041 PetscCall(PetscSectionSetFieldComponents(*subs, f, numComp)); 2042 for (c = 0; c < s->numFieldComponents[fields[f]]; ++c) { 2043 PetscCall(PetscSectionGetComponentName(s, fields[f], c, &name)); 2044 PetscCall(PetscSectionSetComponentName(*subs, f, c, name)); 2045 } 2046 PetscCall(PetscSectionGetFieldSym(s, fields[f], &sym)); 2047 PetscCall(PetscSectionSetFieldSym(*subs, f, sym)); 2048 } 2049 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 2050 PetscCall(PetscSectionSetChart(*subs, pStart, pEnd)); 2051 for (p = pStart; p < pEnd; ++p) { 2052 PetscInt dof = 0, cdof = 0, fdof = 0, cfdof = 0; 2053 2054 for (f = 0; f < len; ++f) { 2055 PetscCall(PetscSectionGetFieldDof(s, p, fields[f], &fdof)); 2056 PetscCall(PetscSectionSetFieldDof(*subs, p, f, fdof)); 2057 PetscCall(PetscSectionGetFieldConstraintDof(s, p, fields[f], &cfdof)); 2058 if (cfdof) PetscCall(PetscSectionSetFieldConstraintDof(*subs, p, f, cfdof)); 2059 dof += fdof; 2060 cdof += cfdof; 2061 } 2062 PetscCall(PetscSectionSetDof(*subs, p, dof)); 2063 if (cdof) PetscCall(PetscSectionSetConstraintDof(*subs, p, cdof)); 2064 maxCdof = PetscMax(cdof, maxCdof); 2065 } 2066 PetscBT bst, subbst; 2067 2068 PetscCall(PetscSectionGetBlockStarts(s, &bst)); 2069 if (bst) { 2070 PetscCall(PetscBTCreate(pEnd - pStart, &subbst)); 2071 PetscCall(PetscBTCopy(subbst, pEnd - pStart, bst)); 2072 PetscCall(PetscSectionSetBlockStarts(*subs, subbst)); 2073 } 2074 PetscCall(PetscSectionSetUp(*subs)); 2075 if (maxCdof) { 2076 PetscInt *indices; 2077 2078 PetscCall(PetscMalloc1(maxCdof, &indices)); 2079 for (p = pStart; p < pEnd; ++p) { 2080 PetscInt cdof; 2081 2082 PetscCall(PetscSectionGetConstraintDof(*subs, p, &cdof)); 2083 if (cdof) { 2084 const PetscInt *oldIndices = NULL; 2085 PetscInt fdof = 0, cfdof = 0, fc, numConst = 0, fOff = 0; 2086 2087 for (f = 0; f < len; ++f) { 2088 PetscCall(PetscSectionGetFieldDof(s, p, fields[f], &fdof)); 2089 PetscCall(PetscSectionGetFieldConstraintDof(s, p, fields[f], &cfdof)); 2090 PetscCall(PetscSectionGetFieldConstraintIndices(s, p, fields[f], &oldIndices)); 2091 PetscCall(PetscSectionSetFieldConstraintIndices(*subs, p, f, oldIndices)); 2092 for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] = oldIndices[fc] + fOff; 2093 numConst += cfdof; 2094 fOff += fdof; 2095 } 2096 PetscCall(PetscSectionSetConstraintIndices(*subs, p, indices)); 2097 } 2098 } 2099 PetscCall(PetscFree(indices)); 2100 } 2101 PetscFunctionReturn(PETSC_SUCCESS); 2102 } 2103 2104 /*@ 2105 PetscSectionCreateComponentSubsection - Create a new, smaller `PetscSection` composed of only selected components 2106 2107 Collective 2108 2109 Input Parameters: 2110 + s - the `PetscSection` 2111 . len - the number of components 2112 - comps - the component numbers 2113 2114 Output Parameter: 2115 . subs - the subsection 2116 2117 Level: advanced 2118 2119 Notes: 2120 The chart of `subs` is the same as the chart of `s` 2121 2122 This will error if the section has more than one field, or if a component number is out of range 2123 2124 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreateSupersection()`, `PetscSectionCreate()` 2125 @*/ 2126 PetscErrorCode PetscSectionCreateComponentSubsection(PetscSection s, PetscInt len, const PetscInt comps[], PetscSection *subs) 2127 { 2128 PetscSectionSym sym; 2129 const char *name = NULL; 2130 PetscInt Nf, pStart, pEnd; 2131 2132 PetscFunctionBegin; 2133 if (!len) PetscFunctionReturn(PETSC_SUCCESS); 2134 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2135 PetscAssertPointer(comps, 3); 2136 PetscAssertPointer(subs, 4); 2137 PetscCall(PetscSectionGetNumFields(s, &Nf)); 2138 PetscCheck(Nf == 1, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONG, "This method can only handle one field, not %" PetscInt_FMT, Nf); 2139 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), subs)); 2140 PetscCall(PetscSectionSetNumFields(*subs, 1)); 2141 PetscCall(PetscSectionGetFieldName(s, 0, &name)); 2142 PetscCall(PetscSectionSetFieldName(*subs, 0, name)); 2143 PetscCall(PetscSectionSetFieldComponents(*subs, 0, len)); 2144 PetscCall(PetscSectionGetFieldSym(s, 0, &sym)); 2145 PetscCall(PetscSectionSetFieldSym(*subs, 0, sym)); 2146 for (PetscInt c = 0; c < len; ++c) { 2147 PetscCall(PetscSectionGetComponentName(s, 0, comps[c], &name)); 2148 PetscCall(PetscSectionSetComponentName(*subs, 0, c, name)); 2149 } 2150 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 2151 PetscCall(PetscSectionSetChart(*subs, pStart, pEnd)); 2152 for (PetscInt p = pStart; p < pEnd; ++p) { 2153 PetscInt dof, cdof, cfdof; 2154 2155 PetscCall(PetscSectionGetDof(s, p, &dof)); 2156 if (!dof) continue; 2157 PetscCall(PetscSectionGetFieldConstraintDof(s, p, 0, &cfdof)); 2158 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 2159 PetscCheck(!cdof && !cfdof, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Component selection does not work with constraints"); 2160 PetscCall(PetscSectionSetFieldDof(*subs, p, 0, len)); 2161 PetscCall(PetscSectionSetDof(*subs, p, len)); 2162 } 2163 PetscCall(PetscSectionSetUp(*subs)); 2164 PetscFunctionReturn(PETSC_SUCCESS); 2165 } 2166 2167 /*@ 2168 PetscSectionCreateSupersection - Create a new, larger section composed of multiple `PetscSection`s 2169 2170 Collective 2171 2172 Input Parameters: 2173 + s - the input sections 2174 - len - the number of input sections 2175 2176 Output Parameter: 2177 . supers - the supersection 2178 2179 Level: advanced 2180 2181 Notes: 2182 The section offsets now refer to a new, larger vector. 2183 2184 Developer Notes: 2185 Needs to explain how the sections are composed 2186 2187 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreateSubsection()`, `PetscSectionCreate()` 2188 @*/ 2189 PetscErrorCode PetscSectionCreateSupersection(PetscSection s[], PetscInt len, PetscSection *supers) 2190 { 2191 PetscInt Nf = 0, f, pStart = PETSC_INT_MAX, pEnd = 0, p, maxCdof = 0, i; 2192 2193 PetscFunctionBegin; 2194 if (!len) PetscFunctionReturn(PETSC_SUCCESS); 2195 for (i = 0; i < len; ++i) { 2196 PetscInt nf, pStarti, pEndi; 2197 2198 PetscCall(PetscSectionGetNumFields(s[i], &nf)); 2199 PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi)); 2200 pStart = PetscMin(pStart, pStarti); 2201 pEnd = PetscMax(pEnd, pEndi); 2202 Nf += nf; 2203 } 2204 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s[0]), supers)); 2205 PetscCall(PetscSectionSetNumFields(*supers, Nf)); 2206 for (i = 0, f = 0; i < len; ++i) { 2207 PetscInt nf, fi, ci; 2208 2209 PetscCall(PetscSectionGetNumFields(s[i], &nf)); 2210 for (fi = 0; fi < nf; ++fi, ++f) { 2211 const char *name = NULL; 2212 PetscInt numComp = 0; 2213 2214 PetscCall(PetscSectionGetFieldName(s[i], fi, &name)); 2215 PetscCall(PetscSectionSetFieldName(*supers, f, name)); 2216 PetscCall(PetscSectionGetFieldComponents(s[i], fi, &numComp)); 2217 PetscCall(PetscSectionSetFieldComponents(*supers, f, numComp)); 2218 for (ci = 0; ci < s[i]->numFieldComponents[fi]; ++ci) { 2219 PetscCall(PetscSectionGetComponentName(s[i], fi, ci, &name)); 2220 PetscCall(PetscSectionSetComponentName(*supers, f, ci, name)); 2221 } 2222 } 2223 } 2224 PetscCall(PetscSectionSetChart(*supers, pStart, pEnd)); 2225 for (p = pStart; p < pEnd; ++p) { 2226 PetscInt dof = 0, cdof = 0; 2227 2228 for (i = 0, f = 0; i < len; ++i) { 2229 PetscInt nf, fi, pStarti, pEndi; 2230 PetscInt fdof = 0, cfdof = 0; 2231 2232 PetscCall(PetscSectionGetNumFields(s[i], &nf)); 2233 PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi)); 2234 if ((p < pStarti) || (p >= pEndi)) continue; 2235 for (fi = 0; fi < nf; ++fi, ++f) { 2236 PetscCall(PetscSectionGetFieldDof(s[i], p, fi, &fdof)); 2237 PetscCall(PetscSectionAddFieldDof(*supers, p, f, fdof)); 2238 PetscCall(PetscSectionGetFieldConstraintDof(s[i], p, fi, &cfdof)); 2239 if (cfdof) PetscCall(PetscSectionAddFieldConstraintDof(*supers, p, f, cfdof)); 2240 dof += fdof; 2241 cdof += cfdof; 2242 } 2243 } 2244 PetscCall(PetscSectionSetDof(*supers, p, dof)); 2245 if (cdof) PetscCall(PetscSectionSetConstraintDof(*supers, p, cdof)); 2246 maxCdof = PetscMax(cdof, maxCdof); 2247 } 2248 PetscCall(PetscSectionSetUp(*supers)); 2249 if (maxCdof) { 2250 PetscInt *indices; 2251 2252 PetscCall(PetscMalloc1(maxCdof, &indices)); 2253 for (p = pStart; p < pEnd; ++p) { 2254 PetscInt cdof; 2255 2256 PetscCall(PetscSectionGetConstraintDof(*supers, p, &cdof)); 2257 if (cdof) { 2258 PetscInt dof, numConst = 0, fOff = 0; 2259 2260 for (i = 0, f = 0; i < len; ++i) { 2261 const PetscInt *oldIndices = NULL; 2262 PetscInt nf, fi, pStarti, pEndi, fdof, cfdof, fc; 2263 2264 PetscCall(PetscSectionGetNumFields(s[i], &nf)); 2265 PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi)); 2266 if ((p < pStarti) || (p >= pEndi)) continue; 2267 for (fi = 0; fi < nf; ++fi, ++f) { 2268 PetscCall(PetscSectionGetFieldDof(s[i], p, fi, &fdof)); 2269 PetscCall(PetscSectionGetFieldConstraintDof(s[i], p, fi, &cfdof)); 2270 PetscCall(PetscSectionGetFieldConstraintIndices(s[i], p, fi, &oldIndices)); 2271 for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] = oldIndices[fc]; 2272 PetscCall(PetscSectionSetFieldConstraintIndices(*supers, p, f, &indices[numConst])); 2273 for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] += fOff; 2274 numConst += cfdof; 2275 } 2276 PetscCall(PetscSectionGetDof(s[i], p, &dof)); 2277 fOff += dof; 2278 } 2279 PetscCall(PetscSectionSetConstraintIndices(*supers, p, indices)); 2280 } 2281 } 2282 PetscCall(PetscFree(indices)); 2283 } 2284 PetscFunctionReturn(PETSC_SUCCESS); 2285 } 2286 2287 static PetscErrorCode PetscSectionCreateSubplexSection_Private(PetscSection s, IS subpointIS, PetscBool renumberPoints, PetscSection *subs) 2288 { 2289 const PetscInt *points = NULL, *indices = NULL; 2290 PetscInt *spoints = NULL, *order = NULL; 2291 PetscInt numFields, f, c, numSubpoints = 0, pStart, pEnd, p, spStart, spEnd, subp; 2292 2293 PetscFunctionBegin; 2294 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2295 PetscValidHeaderSpecific(subpointIS, IS_CLASSID, 2); 2296 PetscAssertPointer(subs, 4); 2297 PetscCall(PetscSectionGetNumFields(s, &numFields)); 2298 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), subs)); 2299 if (numFields) PetscCall(PetscSectionSetNumFields(*subs, numFields)); 2300 for (f = 0; f < numFields; ++f) { 2301 const char *name = NULL; 2302 PetscInt numComp = 0; 2303 2304 PetscCall(PetscSectionGetFieldName(s, f, &name)); 2305 PetscCall(PetscSectionSetFieldName(*subs, f, name)); 2306 PetscCall(PetscSectionGetFieldComponents(s, f, &numComp)); 2307 PetscCall(PetscSectionSetFieldComponents(*subs, f, numComp)); 2308 for (c = 0; c < s->numFieldComponents[f]; ++c) { 2309 PetscCall(PetscSectionGetComponentName(s, f, c, &name)); 2310 PetscCall(PetscSectionSetComponentName(*subs, f, c, name)); 2311 } 2312 } 2313 /* For right now, we do not try to squeeze the subchart */ 2314 if (subpointIS) { 2315 PetscCall(ISGetLocalSize(subpointIS, &numSubpoints)); 2316 PetscCall(ISGetIndices(subpointIS, &points)); 2317 } 2318 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 2319 if (renumberPoints) { 2320 PetscBool sorted; 2321 2322 spStart = 0; 2323 spEnd = numSubpoints; 2324 PetscCall(ISSorted(subpointIS, &sorted)); 2325 if (!sorted) { 2326 PetscCall(PetscMalloc2(numSubpoints, &spoints, numSubpoints, &order)); 2327 PetscCall(PetscArraycpy(spoints, points, numSubpoints)); 2328 for (PetscInt i = 0; i < numSubpoints; ++i) order[i] = i; 2329 PetscCall(PetscSortIntWithArray(numSubpoints, spoints, order)); 2330 } 2331 } else { 2332 PetscCall(ISGetMinMax(subpointIS, &spStart, &spEnd)); 2333 ++spEnd; 2334 } 2335 PetscCall(PetscSectionSetChart(*subs, spStart, spEnd)); 2336 for (p = pStart; p < pEnd; ++p) { 2337 PetscInt dof, cdof, fdof = 0, cfdof = 0; 2338 2339 PetscCall(PetscFindInt(p, numSubpoints, spoints ? spoints : points, &subp)); 2340 if (subp < 0) continue; 2341 if (!renumberPoints) subp = p; 2342 else subp = order ? order[subp] : subp; 2343 for (f = 0; f < numFields; ++f) { 2344 PetscCall(PetscSectionGetFieldDof(s, p, f, &fdof)); 2345 PetscCall(PetscSectionSetFieldDof(*subs, subp, f, fdof)); 2346 PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cfdof)); 2347 if (cfdof) PetscCall(PetscSectionSetFieldConstraintDof(*subs, subp, f, cfdof)); 2348 } 2349 PetscCall(PetscSectionGetDof(s, p, &dof)); 2350 PetscCall(PetscSectionSetDof(*subs, subp, dof)); 2351 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 2352 if (cdof) PetscCall(PetscSectionSetConstraintDof(*subs, subp, cdof)); 2353 } 2354 PetscCall(PetscSectionSetUp(*subs)); 2355 /* Change offsets to original offsets */ 2356 for (p = pStart; p < pEnd; ++p) { 2357 PetscInt off, foff = 0; 2358 2359 PetscCall(PetscFindInt(p, numSubpoints, spoints ? spoints : points, &subp)); 2360 if (subp < 0) continue; 2361 if (!renumberPoints) subp = p; 2362 else subp = order ? order[subp] : subp; 2363 for (f = 0; f < numFields; ++f) { 2364 PetscCall(PetscSectionGetFieldOffset(s, p, f, &foff)); 2365 PetscCall(PetscSectionSetFieldOffset(*subs, subp, f, foff)); 2366 } 2367 PetscCall(PetscSectionGetOffset(s, p, &off)); 2368 PetscCall(PetscSectionSetOffset(*subs, subp, off)); 2369 } 2370 /* Copy constraint indices */ 2371 for (subp = spStart; subp < spEnd; ++subp) { 2372 PetscInt cdof; 2373 2374 PetscCall(PetscSectionGetConstraintDof(*subs, subp, &cdof)); 2375 if (cdof) { 2376 for (f = 0; f < numFields; ++f) { 2377 PetscCall(PetscSectionGetFieldConstraintIndices(s, points[subp - spStart], f, &indices)); 2378 PetscCall(PetscSectionSetFieldConstraintIndices(*subs, subp, f, indices)); 2379 } 2380 PetscCall(PetscSectionGetConstraintIndices(s, points[subp - spStart], &indices)); 2381 PetscCall(PetscSectionSetConstraintIndices(*subs, subp, indices)); 2382 } 2383 } 2384 if (subpointIS) PetscCall(ISRestoreIndices(subpointIS, &points)); 2385 PetscCall(PetscFree2(spoints, order)); 2386 PetscFunctionReturn(PETSC_SUCCESS); 2387 } 2388 2389 /*@ 2390 PetscSectionCreateSubmeshSection - Create a new, smaller section with support on the submesh 2391 2392 Collective 2393 2394 Input Parameters: 2395 + s - the `PetscSection` 2396 - subpointIS - a sorted list of points in the original mesh which are in the submesh 2397 2398 Output Parameter: 2399 . subs - the subsection 2400 2401 Level: advanced 2402 2403 Notes: 2404 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))` 2405 2406 Compare this with `PetscSectionCreateSubdomainSection()` that does not map the points numbers to start at zero but leaves them as before 2407 2408 Developer Notes: 2409 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` 2410 2411 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreateSubdomainSection()`, `PetscSectionCreateSubsection()`, `DMPlexGetSubpointMap()`, `PetscSectionCreate()` 2412 @*/ 2413 PetscErrorCode PetscSectionCreateSubmeshSection(PetscSection s, IS subpointIS, PetscSection *subs) 2414 { 2415 PetscFunctionBegin; 2416 PetscCall(PetscSectionCreateSubplexSection_Private(s, subpointIS, PETSC_TRUE, subs)); 2417 PetscFunctionReturn(PETSC_SUCCESS); 2418 } 2419 2420 /*@ 2421 PetscSectionCreateSubdomainSection - Create a new, smaller section with support on a subdomain of the mesh 2422 2423 Collective 2424 2425 Input Parameters: 2426 + s - the `PetscSection` 2427 - subpointMap - a sorted list of points in the original mesh which are in the subdomain 2428 2429 Output Parameter: 2430 . subs - the subsection 2431 2432 Level: advanced 2433 2434 Notes: 2435 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` 2436 is `[min(subpointMap),max(subpointMap)+1)` 2437 2438 Compare this with `PetscSectionCreateSubmeshSection()` that maps the point numbers to start at zero 2439 2440 Developer Notes: 2441 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` 2442 2443 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreateSubmeshSection()`, `PetscSectionCreateSubsection()`, `DMPlexGetSubpointMap()`, `PetscSectionCreate()` 2444 @*/ 2445 PetscErrorCode PetscSectionCreateSubdomainSection(PetscSection s, IS subpointMap, PetscSection *subs) 2446 { 2447 PetscFunctionBegin; 2448 PetscCall(PetscSectionCreateSubplexSection_Private(s, subpointMap, PETSC_FALSE, subs)); 2449 PetscFunctionReturn(PETSC_SUCCESS); 2450 } 2451 2452 static PetscErrorCode PetscSectionView_ASCII(PetscSection s, PetscViewer viewer) 2453 { 2454 PetscInt p; 2455 PetscMPIInt rank; 2456 2457 PetscFunctionBegin; 2458 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 2459 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 2460 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 2461 for (p = 0; p < s->pEnd - s->pStart; ++p) { 2462 if (s->bc && s->bc->atlasDof[p] > 0) { 2463 PetscInt b; 2464 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT " constrained", p + s->pStart, s->atlasDof[p], s->atlasOff[p])); 2465 if (s->bcIndices) { 2466 for (b = 0; b < s->bc->atlasDof[p]; ++b) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, s->bcIndices[s->bc->atlasOff[p] + b])); 2467 } 2468 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 2469 } else { 2470 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT "\n", p + s->pStart, s->atlasDof[p], s->atlasOff[p])); 2471 } 2472 } 2473 PetscCall(PetscViewerFlush(viewer)); 2474 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 2475 if (s->sym) { 2476 PetscCall(PetscViewerASCIIPushTab(viewer)); 2477 PetscCall(PetscSectionSymView(s->sym, viewer)); 2478 PetscCall(PetscViewerASCIIPopTab(viewer)); 2479 } 2480 PetscFunctionReturn(PETSC_SUCCESS); 2481 } 2482 2483 /*@ 2484 PetscSectionViewFromOptions - View the `PetscSection` based on values in the options database 2485 2486 Collective 2487 2488 Input Parameters: 2489 + A - the `PetscSection` object to view 2490 . obj - Optional object that provides the options prefix used for the options 2491 - name - command line option 2492 2493 Level: intermediate 2494 2495 Note: 2496 See `PetscObjectViewFromOptions()` for available values of `PetscViewer` and `PetscViewerFormat` 2497 2498 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionView`, `PetscObjectViewFromOptions()`, `PetscSectionCreate()`, `PetscSectionView()` 2499 @*/ 2500 PetscErrorCode PetscSectionViewFromOptions(PetscSection A, PetscObject obj, const char name[]) 2501 { 2502 PetscFunctionBegin; 2503 PetscValidHeaderSpecific(A, PETSC_SECTION_CLASSID, 1); 2504 PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name)); 2505 PetscFunctionReturn(PETSC_SUCCESS); 2506 } 2507 2508 /*@ 2509 PetscSectionView - Views a `PetscSection` 2510 2511 Collective 2512 2513 Input Parameters: 2514 + s - the `PetscSection` object to view 2515 - viewer - the viewer 2516 2517 Level: beginner 2518 2519 Note: 2520 `PetscSectionView()`, when viewer is of type `PETSCVIEWERHDF5`, only saves 2521 distribution independent data, such as dofs, offsets, constraint dofs, 2522 and constraint indices. Points that have negative dofs, for instance, 2523 are not saved as they represent points owned by other processes. 2524 Point numbering and rank assignment is currently not stored. 2525 The saved section can be loaded with `PetscSectionLoad()`. 2526 2527 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`, `PetscSectionLoad()`, `PetscViewer` 2528 @*/ 2529 PetscErrorCode PetscSectionView(PetscSection s, PetscViewer viewer) 2530 { 2531 PetscBool isascii, ishdf5; 2532 PetscInt f; 2533 2534 PetscFunctionBegin; 2535 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2536 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)s), &viewer)); 2537 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2538 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 2539 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2540 if (isascii) { 2541 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)s, viewer)); 2542 if (s->numFields) { 2543 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " fields\n", s->numFields)); 2544 for (f = 0; f < s->numFields; ++f) { 2545 PetscCall(PetscViewerASCIIPrintf(viewer, " field %" PetscInt_FMT " \"%s\" with %" PetscInt_FMT " components\n", f, s->fieldNames[f], s->numFieldComponents[f])); 2546 PetscCall(PetscSectionView_ASCII(s->field[f], viewer)); 2547 } 2548 } else { 2549 PetscCall(PetscSectionView_ASCII(s, viewer)); 2550 } 2551 } else if (ishdf5) { 2552 #if PetscDefined(HAVE_HDF5) 2553 PetscCall(PetscSectionView_HDF5_Internal(s, viewer)); 2554 #else 2555 SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2556 #endif 2557 } 2558 PetscFunctionReturn(PETSC_SUCCESS); 2559 } 2560 2561 /*@ 2562 PetscSectionLoad - Loads a `PetscSection` 2563 2564 Collective 2565 2566 Input Parameters: 2567 + s - the `PetscSection` object to load 2568 - viewer - the viewer 2569 2570 Level: beginner 2571 2572 Note: 2573 `PetscSectionLoad()`, when viewer is of type `PETSCVIEWERHDF5`, loads 2574 a section saved with `PetscSectionView()`. The number of processes 2575 used here (N) does not need to be the same as that used when saving. 2576 After calling this function, the chart of s on rank i will be set 2577 to [0, E_i), where \sum_{i=0}^{N-1}E_i equals to the total number of 2578 saved section points. 2579 2580 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`, `PetscSectionView()` 2581 @*/ 2582 PetscErrorCode PetscSectionLoad(PetscSection s, PetscViewer viewer) 2583 { 2584 PetscBool ishdf5; 2585 2586 PetscFunctionBegin; 2587 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2588 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2589 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2590 PetscCheck(ishdf5, PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "Viewer type %s not yet supported for PetscSection loading", ((PetscObject)viewer)->type_name); 2591 #if PetscDefined(HAVE_HDF5) 2592 PetscCall(PetscSectionLoad_HDF5_Internal(s, viewer)); 2593 PetscFunctionReturn(PETSC_SUCCESS); 2594 #else 2595 SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2596 #endif 2597 } 2598 2599 static inline PetscErrorCode PrintArrayElement(void *array, PetscDataType data_type, PetscCount index, PetscViewer viewer) 2600 { 2601 PetscFunctionBeginUser; 2602 switch (data_type) { 2603 case PETSC_INT: { 2604 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %2" PetscInt_FMT, ((PetscInt *)array)[index])); 2605 break; 2606 } 2607 case PETSC_INT32: { 2608 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %2" PetscInt32_FMT, ((PetscInt32 *)array)[index])); 2609 break; 2610 } 2611 case PETSC_INT64: { 2612 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %2" PetscInt64_FMT, ((PetscInt64 *)array)[index])); 2613 break; 2614 } 2615 case PETSC_COUNT: { 2616 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %2" PetscCount_FMT, ((PetscCount *)array)[index])); 2617 break; 2618 } 2619 // PETSC_SCALAR is set to the appropriate type 2620 case PETSC_DOUBLE: { 2621 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", ((double *)array)[index])); 2622 break; 2623 } 2624 case PETSC_FLOAT: { 2625 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)((float *)array)[index])); 2626 break; 2627 } 2628 #if defined(PETSC_USE_REAL___FLOAT128) 2629 case PETSC___FLOAT128: { 2630 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)((PetscReal *)array)[index])); 2631 break; 2632 } 2633 #endif 2634 #if defined(PETSC_USE_REAL___FP16) 2635 case PETSC___FP16: { 2636 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)((PetscReal *)array)[index])); 2637 break; 2638 } 2639 #endif 2640 #if defined(PETSC_HAVE_COMPLEX) 2641 case PETSC_COMPLEX: { 2642 PetscComplex v = ((PetscComplex *)array)[index]; 2643 if (PetscImaginaryPartComplex(v) > 0.0) { 2644 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g + %g i", (double)PetscRealPartComplex(v), (double)PetscImaginaryPartComplex(v))); 2645 } else if (PetscImaginaryPartComplex(v) < 0.0) { 2646 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g - %g i", (double)PetscRealPartComplex(v), (double)(-PetscImaginaryPartComplex(v)))); 2647 } else { 2648 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %g", (double)PetscRealPartComplex(v))); 2649 } 2650 break; 2651 } 2652 #endif 2653 default: 2654 SETERRQ(PetscObjectComm((PetscObject)viewer), PETSC_ERR_SUP, "PetscDataType %d (%s) not supported", data_type, PetscDataTypes[data_type]); 2655 } 2656 PetscFunctionReturn(PETSC_SUCCESS); 2657 } 2658 2659 PetscErrorCode PetscSectionArrayView_ASCII_Internal(PetscSection s, void *array, PetscDataType data_type, PetscViewer viewer) 2660 { 2661 PetscInt p, i; 2662 PetscMPIInt rank; 2663 2664 PetscFunctionBegin; 2665 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 2666 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 2667 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 2668 for (p = 0; p < s->pEnd - s->pStart; ++p) { 2669 if (s->bc && (s->bc->atlasDof[p] > 0)) { 2670 PetscInt b; 2671 2672 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p + s->pStart, s->atlasDof[p], s->atlasOff[p])); 2673 for (i = s->atlasOff[p]; i < s->atlasOff[p] + s->atlasDof[p]; ++i) PetscCall(PrintArrayElement(array, data_type, i, viewer)); 2674 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " constrained")); 2675 for (b = 0; b < s->bc->atlasDof[p]; ++b) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, s->bcIndices[s->bc->atlasOff[p] + b])); 2676 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 2677 } else { 2678 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dof %2" PetscInt_FMT " offset %3" PetscInt_FMT, p + s->pStart, s->atlasDof[p], s->atlasOff[p])); 2679 for (i = s->atlasOff[p]; i < s->atlasOff[p] + s->atlasDof[p]; ++i) PetscCall(PrintArrayElement(array, data_type, i, viewer)); 2680 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 2681 } 2682 } 2683 PetscCall(PetscViewerFlush(viewer)); 2684 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 2685 PetscFunctionReturn(PETSC_SUCCESS); 2686 } 2687 2688 /*@ 2689 PetscSectionArrayView - View an array, using the section to structure the values 2690 2691 Collective 2692 2693 Input Parameters: 2694 + s - the organizing `PetscSection` 2695 . array - the array of values 2696 . data_type - the `PetscDataType` of the array 2697 - viewer - the `PetscViewer` 2698 2699 Level: developer 2700 2701 .seealso: `PetscSection`, `PetscViewer`, `PetscSectionCreate()`, `VecSetValuesSection()`, `PetscSectionVecView()` 2702 @*/ 2703 PetscErrorCode PetscSectionArrayView(PetscSection s, void *array, PetscDataType data_type, PetscViewer viewer) 2704 { 2705 PetscBool isascii; 2706 PetscInt f; 2707 2708 PetscFunctionBegin; 2709 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2710 if (!array) { 2711 PetscInt size; 2712 PetscCall(PetscSectionGetStorageSize(s, &size)); 2713 PetscCheck(size == 0, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_SIZ, "NULL array passed, but section's storage size is non-zero"); 2714 } else PetscAssertPointer(array, 2); 2715 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)s), &viewer)); 2716 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 4); 2717 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 2718 if (isascii) { 2719 if (s->numFields) { 2720 PetscCall(PetscViewerASCIIPrintf(viewer, "Array with %" PetscInt_FMT " fields\n", s->numFields)); 2721 for (f = 0; f < s->numFields; ++f) { 2722 PetscCall(PetscViewerASCIIPrintf(viewer, " field %" PetscInt_FMT " with %" PetscInt_FMT " components\n", f, s->numFieldComponents[f])); 2723 PetscCall(PetscSectionArrayView_ASCII_Internal(s->field[f], array, data_type, viewer)); 2724 } 2725 } else { 2726 PetscCall(PetscSectionArrayView_ASCII_Internal(s, array, data_type, viewer)); 2727 } 2728 } 2729 PetscFunctionReturn(PETSC_SUCCESS); 2730 } 2731 2732 /*@ 2733 PetscSectionResetClosurePermutation - Remove any existing closure permutation 2734 2735 Input Parameter: 2736 . section - The `PetscSection` 2737 2738 Level: intermediate 2739 2740 .seealso: `PetscSectionSetClosurePermutation()`, `PetscSectionSetClosureIndex()`, `PetscSectionReset()` 2741 @*/ 2742 PetscErrorCode PetscSectionResetClosurePermutation(PetscSection section) 2743 { 2744 PetscSectionClosurePermVal clVal; 2745 2746 PetscFunctionBegin; 2747 if (!section->clHash) PetscFunctionReturn(PETSC_SUCCESS); 2748 kh_foreach_value(section->clHash, clVal, { 2749 PetscCall(PetscFree(clVal.perm)); 2750 PetscCall(PetscFree(clVal.invPerm)); 2751 }); 2752 kh_destroy(ClPerm, section->clHash); 2753 section->clHash = NULL; 2754 PetscFunctionReturn(PETSC_SUCCESS); 2755 } 2756 2757 /*@ 2758 PetscSectionReset - Frees all section data, the section is then as if `PetscSectionCreate()` had just been called. 2759 2760 Not Collective 2761 2762 Input Parameter: 2763 . s - the `PetscSection` 2764 2765 Level: beginner 2766 2767 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()` 2768 @*/ 2769 PetscErrorCode PetscSectionReset(PetscSection s) 2770 { 2771 PetscInt f, c; 2772 2773 PetscFunctionBegin; 2774 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2775 for (f = 0; f < s->numFields; ++f) { 2776 PetscCall(PetscSectionDestroy(&s->field[f])); 2777 PetscCall(PetscFree(s->fieldNames[f])); 2778 for (c = 0; c < s->numFieldComponents[f]; ++c) PetscCall(PetscFree(s->compNames[f][c])); 2779 PetscCall(PetscFree(s->compNames[f])); 2780 } 2781 PetscCall(PetscFree(s->numFieldComponents)); 2782 PetscCall(PetscFree(s->fieldNames)); 2783 PetscCall(PetscFree(s->compNames)); 2784 PetscCall(PetscFree(s->field)); 2785 PetscCall(PetscSectionDestroy(&s->bc)); 2786 PetscCall(PetscFree(s->bcIndices)); 2787 PetscCall(PetscFree2(s->atlasDof, s->atlasOff)); 2788 PetscCall(PetscSectionDestroy(&s->clSection)); 2789 PetscCall(ISDestroy(&s->clPoints)); 2790 PetscCall(ISDestroy(&s->perm)); 2791 PetscCall(PetscBTDestroy(&s->blockStarts)); 2792 PetscCall(PetscSectionResetClosurePermutation(s)); 2793 PetscCall(PetscSectionSymDestroy(&s->sym)); 2794 PetscCall(PetscSectionDestroy(&s->clSection)); 2795 PetscCall(ISDestroy(&s->clPoints)); 2796 PetscCall(PetscSectionInvalidateMaxDof_Internal(s)); 2797 s->pStart = -1; 2798 s->pEnd = -1; 2799 s->maxDof = 0; 2800 s->setup = PETSC_FALSE; 2801 s->numFields = 0; 2802 s->clObj = NULL; 2803 PetscFunctionReturn(PETSC_SUCCESS); 2804 } 2805 2806 /*@ 2807 PetscSectionDestroy - Frees a `PetscSection` 2808 2809 Not Collective 2810 2811 Input Parameter: 2812 . s - the `PetscSection` 2813 2814 Level: beginner 2815 2816 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionReset()` 2817 @*/ 2818 PetscErrorCode PetscSectionDestroy(PetscSection *s) 2819 { 2820 PetscFunctionBegin; 2821 if (!*s) PetscFunctionReturn(PETSC_SUCCESS); 2822 PetscValidHeaderSpecific(*s, PETSC_SECTION_CLASSID, 1); 2823 if (--((PetscObject)*s)->refct > 0) { 2824 *s = NULL; 2825 PetscFunctionReturn(PETSC_SUCCESS); 2826 } 2827 PetscCall(PetscSectionReset(*s)); 2828 PetscCall(PetscHeaderDestroy(s)); 2829 PetscFunctionReturn(PETSC_SUCCESS); 2830 } 2831 2832 static PetscErrorCode VecIntGetValuesSection_Private(const PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt **values) 2833 { 2834 const PetscInt p = point - s->pStart; 2835 2836 PetscFunctionBegin; 2837 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2); 2838 *values = &baseArray[s->atlasOff[p]]; 2839 PetscFunctionReturn(PETSC_SUCCESS); 2840 } 2841 2842 static PetscErrorCode VecIntSetValuesSection_Private(PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt values[], InsertMode mode) 2843 { 2844 PetscInt *array; 2845 const PetscInt p = point - s->pStart; 2846 const PetscInt orientation = 0; /* Needs to be included for use in closure operations */ 2847 PetscInt cDim = 0; 2848 2849 PetscFunctionBegin; 2850 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2); 2851 PetscCall(PetscSectionGetConstraintDof(s, p, &cDim)); 2852 array = &baseArray[s->atlasOff[p]]; 2853 if (!cDim) { 2854 if (orientation >= 0) { 2855 const PetscInt dim = s->atlasDof[p]; 2856 PetscInt i; 2857 2858 if (mode == INSERT_VALUES) { 2859 for (i = 0; i < dim; ++i) array[i] = values ? values[i] : i; 2860 } else { 2861 for (i = 0; i < dim; ++i) array[i] += values[i]; 2862 } 2863 } else { 2864 PetscInt offset = 0; 2865 PetscInt j = -1, field, i; 2866 2867 for (field = 0; field < s->numFields; ++field) { 2868 const PetscInt dim = s->field[field]->atlasDof[p]; 2869 2870 for (i = dim - 1; i >= 0; --i) array[++j] = values ? values[i + offset] : i + offset; 2871 offset += dim; 2872 } 2873 } 2874 } else { 2875 if (orientation >= 0) { 2876 const PetscInt dim = s->atlasDof[p]; 2877 PetscInt cInd = 0, i; 2878 const PetscInt *cDof; 2879 2880 PetscCall(PetscSectionGetConstraintIndices(s, point, &cDof)); 2881 if (mode == INSERT_VALUES) { 2882 for (i = 0; i < dim; ++i) { 2883 if ((cInd < cDim) && (i == cDof[cInd])) { 2884 ++cInd; 2885 continue; 2886 } 2887 array[i] = values ? values[i] : i; 2888 } 2889 } else { 2890 for (i = 0; i < dim; ++i) { 2891 if ((cInd < cDim) && (i == cDof[cInd])) { 2892 ++cInd; 2893 continue; 2894 } 2895 array[i] += values[i]; 2896 } 2897 } 2898 } else { 2899 const PetscInt *cDof; 2900 PetscInt offset = 0; 2901 PetscInt cOffset = 0; 2902 PetscInt j = 0, field; 2903 2904 PetscCall(PetscSectionGetConstraintIndices(s, point, &cDof)); 2905 for (field = 0; field < s->numFields; ++field) { 2906 const PetscInt dim = s->field[field]->atlasDof[p]; /* PetscSectionGetFieldDof() */ 2907 const PetscInt tDim = s->field[field]->bc->atlasDof[p]; /* PetscSectionGetFieldConstraintDof() */ 2908 const PetscInt sDim = dim - tDim; 2909 PetscInt cInd = 0, i, k; 2910 2911 for (i = 0, k = dim + offset - 1; i < dim; ++i, ++j, --k) { 2912 if ((cInd < sDim) && (j == cDof[cInd + cOffset])) { 2913 ++cInd; 2914 continue; 2915 } 2916 array[j] = values ? values[k] : k; 2917 } 2918 offset += dim; 2919 cOffset += dim - tDim; 2920 } 2921 } 2922 } 2923 PetscFunctionReturn(PETSC_SUCCESS); 2924 } 2925 2926 /*@ 2927 PetscSectionHasConstraints - Determine whether a `PetscSection` has constrained dofs 2928 2929 Not Collective 2930 2931 Input Parameter: 2932 . s - The `PetscSection` 2933 2934 Output Parameter: 2935 . hasConstraints - flag indicating that the section has constrained dofs 2936 2937 Level: intermediate 2938 2939 .seealso: [PetscSection](ch_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2940 @*/ 2941 PetscErrorCode PetscSectionHasConstraints(PetscSection s, PetscBool *hasConstraints) 2942 { 2943 PetscFunctionBegin; 2944 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2945 PetscAssertPointer(hasConstraints, 2); 2946 *hasConstraints = s->bc ? PETSC_TRUE : PETSC_FALSE; 2947 PetscFunctionReturn(PETSC_SUCCESS); 2948 } 2949 2950 /*@C 2951 PetscSectionGetConstraintIndices - Get the point dof numbers, in [0, dof), which are constrained for a given point 2952 2953 Not Collective 2954 2955 Input Parameters: 2956 + s - The `PetscSection` 2957 - point - The point 2958 2959 Output Parameter: 2960 . indices - The constrained dofs 2961 2962 Level: intermediate 2963 2964 Fortran Notes: 2965 Use `PetscSectionRestoreConstraintIndices()` when the indices are no longer needed 2966 2967 .seealso: [PetscSection](ch_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2968 @*/ 2969 PetscErrorCode PetscSectionGetConstraintIndices(PetscSection s, PetscInt point, const PetscInt *indices[]) 2970 { 2971 PetscFunctionBegin; 2972 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2973 if (s->bc) PetscCall(VecIntGetValuesSection_Private(s->bcIndices, s->bc, point, indices)); 2974 else *indices = NULL; 2975 PetscFunctionReturn(PETSC_SUCCESS); 2976 } 2977 2978 /*@ 2979 PetscSectionSetConstraintIndices - Set the point dof numbers, in [0, dof), which are constrained 2980 2981 Not Collective 2982 2983 Input Parameters: 2984 + s - The `PetscSection` 2985 . point - The point 2986 - indices - The constrained dofs 2987 2988 Level: intermediate 2989 2990 .seealso: [PetscSection](ch_petscsection), `PetscSectionGetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2991 @*/ 2992 PetscErrorCode PetscSectionSetConstraintIndices(PetscSection s, PetscInt point, const PetscInt indices[]) 2993 { 2994 PetscFunctionBegin; 2995 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2996 if (s->bc) { 2997 const PetscInt dof = s->atlasDof[point]; 2998 const PetscInt cdof = s->bc->atlasDof[point]; 2999 PetscInt d; 3000 3001 if (indices) 3002 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]); 3003 PetscCall(VecIntSetValuesSection_Private(s->bcIndices, s->bc, point, indices, INSERT_VALUES)); 3004 } 3005 PetscFunctionReturn(PETSC_SUCCESS); 3006 } 3007 3008 /*@C 3009 PetscSectionGetFieldConstraintIndices - Get the field dof numbers, in [0, fdof), which are constrained 3010 3011 Not Collective 3012 3013 Input Parameters: 3014 + s - The `PetscSection` 3015 . field - The field number 3016 - point - The point 3017 3018 Output Parameter: 3019 . indices - The constrained dofs sorted in ascending order, the length is returned by `PetscSectionGetConstraintDof()`. 3020 3021 Level: intermediate 3022 3023 Fortran Notes: 3024 Use `PetscSectionRestoreFieldConstraintIndices()` to restore the indices when no longer needed 3025 3026 .seealso: [PetscSection](ch_petscsection), `PetscSectionSetFieldConstraintIndices()`, `PetscSectionGetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 3027 @*/ 3028 PetscErrorCode PetscSectionGetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt *indices[]) 3029 { 3030 PetscFunctionBegin; 3031 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 3032 PetscAssertPointer(indices, 4); 3033 PetscSectionCheckValidField(field, s->numFields); 3034 PetscCall(PetscSectionGetConstraintIndices(s->field[field], point, indices)); 3035 PetscFunctionReturn(PETSC_SUCCESS); 3036 } 3037 3038 /*@ 3039 PetscSectionSetFieldConstraintIndices - Set the field dof numbers, in [0, fdof), which are constrained 3040 3041 Not Collective 3042 3043 Input Parameters: 3044 + s - The `PetscSection` 3045 . point - The point 3046 . field - The field number 3047 - indices - The constrained dofs 3048 3049 Level: intermediate 3050 3051 .seealso: [PetscSection](ch_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetFieldConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 3052 @*/ 3053 PetscErrorCode PetscSectionSetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt indices[]) 3054 { 3055 PetscFunctionBegin; 3056 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 3057 PetscSectionCheckValidField(field, s->numFields); 3058 PetscCall(PetscSectionSetConstraintIndices(s->field[field], point, indices)); 3059 PetscFunctionReturn(PETSC_SUCCESS); 3060 } 3061 3062 /*@ 3063 PetscSectionPermute - Reorder the section according to the input point permutation 3064 3065 Collective 3066 3067 Input Parameters: 3068 + section - The `PetscSection` object 3069 - permutation - The point permutation, old point p becomes new point perm[p] 3070 3071 Output Parameter: 3072 . sectionNew - The permuted `PetscSection` 3073 3074 Level: intermediate 3075 3076 Note: 3077 The data and the access to the data via `PetscSectionGetFieldOffset()` and `PetscSectionGetOffset()` are both changed in `sectionNew` 3078 3079 Compare to `PetscSectionSetPermutation()` 3080 3081 .seealso: [PetscSection](ch_petscsection), `IS`, `PetscSection`, `MatPermute()`, `PetscSectionSetPermutation()` 3082 @*/ 3083 PetscErrorCode PetscSectionPermute(PetscSection section, IS permutation, PetscSection *sectionNew) 3084 { 3085 PetscSection s = section, sNew; 3086 const PetscInt *perm; 3087 PetscInt numFields, f, c, numPoints, pStart, pEnd, p; 3088 3089 PetscFunctionBegin; 3090 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3091 PetscValidHeaderSpecific(permutation, IS_CLASSID, 2); 3092 PetscAssertPointer(sectionNew, 3); 3093 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), &sNew)); 3094 PetscCall(PetscSectionGetNumFields(s, &numFields)); 3095 if (numFields) PetscCall(PetscSectionSetNumFields(sNew, numFields)); 3096 for (f = 0; f < numFields; ++f) { 3097 const char *name; 3098 PetscInt numComp; 3099 3100 PetscCall(PetscSectionGetFieldName(s, f, &name)); 3101 PetscCall(PetscSectionSetFieldName(sNew, f, name)); 3102 PetscCall(PetscSectionGetFieldComponents(s, f, &numComp)); 3103 PetscCall(PetscSectionSetFieldComponents(sNew, f, numComp)); 3104 for (c = 0; c < s->numFieldComponents[f]; ++c) { 3105 PetscCall(PetscSectionGetComponentName(s, f, c, &name)); 3106 PetscCall(PetscSectionSetComponentName(sNew, f, c, name)); 3107 } 3108 } 3109 PetscCall(ISGetLocalSize(permutation, &numPoints)); 3110 PetscCall(ISGetIndices(permutation, &perm)); 3111 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 3112 PetscCall(PetscSectionSetChart(sNew, pStart, pEnd)); 3113 PetscCheck(numPoints >= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Permutation size %" PetscInt_FMT " is less than largest Section point %" PetscInt_FMT, numPoints, pEnd); 3114 for (p = pStart; p < pEnd; ++p) { 3115 PetscInt dof, cdof; 3116 3117 PetscCall(PetscSectionGetDof(s, p, &dof)); 3118 PetscCall(PetscSectionSetDof(sNew, perm[p], dof)); 3119 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 3120 if (cdof) PetscCall(PetscSectionSetConstraintDof(sNew, perm[p], cdof)); 3121 for (f = 0; f < numFields; ++f) { 3122 PetscCall(PetscSectionGetFieldDof(s, p, f, &dof)); 3123 PetscCall(PetscSectionSetFieldDof(sNew, perm[p], f, dof)); 3124 PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof)); 3125 if (cdof) PetscCall(PetscSectionSetFieldConstraintDof(sNew, perm[p], f, cdof)); 3126 } 3127 } 3128 PetscCall(PetscSectionSetUp(sNew)); 3129 for (p = pStart; p < pEnd; ++p) { 3130 const PetscInt *cind; 3131 PetscInt cdof; 3132 3133 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 3134 if (cdof) { 3135 PetscCall(PetscSectionGetConstraintIndices(s, p, &cind)); 3136 PetscCall(PetscSectionSetConstraintIndices(sNew, perm[p], cind)); 3137 } 3138 for (f = 0; f < numFields; ++f) { 3139 PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof)); 3140 if (cdof) { 3141 PetscCall(PetscSectionGetFieldConstraintIndices(s, p, f, &cind)); 3142 PetscCall(PetscSectionSetFieldConstraintIndices(sNew, perm[p], f, cind)); 3143 } 3144 } 3145 } 3146 PetscCall(ISRestoreIndices(permutation, &perm)); 3147 *sectionNew = sNew; 3148 PetscFunctionReturn(PETSC_SUCCESS); 3149 } 3150 3151 /*@ 3152 PetscSectionSetClosureIndex - Create an internal data structure to speed up closure queries. 3153 3154 Collective 3155 3156 Input Parameters: 3157 + section - The `PetscSection` 3158 . obj - A `PetscObject` which serves as the key for this index 3159 . clSection - `PetscSection` giving the size of the closure of each point 3160 - clPoints - `IS` giving the points in each closure 3161 3162 Level: advanced 3163 3164 Note: 3165 This function creates an internal map from each point to its closure. We compress out closure points with no dofs in this section. 3166 3167 Developer Notes: 3168 The information provided here is completely opaque 3169 3170 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionGetClosureIndex()`, `DMPlexCreateClosureIndex()` 3171 @*/ 3172 PetscErrorCode PetscSectionSetClosureIndex(PetscSection section, PetscObject obj, PetscSection clSection, IS clPoints) 3173 { 3174 PetscFunctionBegin; 3175 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3176 PetscValidHeaderSpecific(clSection, PETSC_SECTION_CLASSID, 3); 3177 PetscValidHeaderSpecific(clPoints, IS_CLASSID, 4); 3178 if (section->clObj != obj) PetscCall(PetscSectionResetClosurePermutation(section)); 3179 section->clObj = obj; 3180 PetscCall(PetscObjectReference((PetscObject)clSection)); 3181 PetscCall(PetscObjectReference((PetscObject)clPoints)); 3182 PetscCall(PetscSectionDestroy(§ion->clSection)); 3183 PetscCall(ISDestroy(§ion->clPoints)); 3184 section->clSection = clSection; 3185 section->clPoints = clPoints; 3186 PetscFunctionReturn(PETSC_SUCCESS); 3187 } 3188 3189 /*@ 3190 PetscSectionGetClosureIndex - Get the cache of points in the closure of each point in the section set with `PetscSectionSetClosureIndex()` 3191 3192 Collective 3193 3194 Input Parameters: 3195 + section - The `PetscSection` 3196 - obj - A `PetscObject` which serves as the key for this index 3197 3198 Output Parameters: 3199 + clSection - `PetscSection` giving the size of the closure of each point 3200 - clPoints - `IS` giving the points in each closure 3201 3202 Level: advanced 3203 3204 .seealso: [PetscSection](ch_petscsection), `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()` 3205 @*/ 3206 PetscErrorCode PetscSectionGetClosureIndex(PetscSection section, PetscObject obj, PetscSection *clSection, IS *clPoints) 3207 { 3208 PetscFunctionBegin; 3209 if (section->clObj == obj) { 3210 if (clSection) *clSection = section->clSection; 3211 if (clPoints) *clPoints = section->clPoints; 3212 } else { 3213 if (clSection) *clSection = NULL; 3214 if (clPoints) *clPoints = NULL; 3215 } 3216 PetscFunctionReturn(PETSC_SUCCESS); 3217 } 3218 3219 PetscErrorCode PetscSectionSetClosurePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, PetscCopyMode mode, PetscInt *clPerm) 3220 { 3221 PetscInt i; 3222 khiter_t iter; 3223 int new_entry; 3224 PetscSectionClosurePermKey key = {depth, clSize}; 3225 PetscSectionClosurePermVal *val; 3226 3227 PetscFunctionBegin; 3228 if (section->clObj != obj) { 3229 PetscCall(PetscSectionDestroy(§ion->clSection)); 3230 PetscCall(ISDestroy(§ion->clPoints)); 3231 } 3232 section->clObj = obj; 3233 if (!section->clHash) PetscCall(PetscClPermCreate(§ion->clHash)); 3234 iter = kh_put(ClPerm, section->clHash, key, &new_entry); 3235 val = &kh_val(section->clHash, iter); 3236 if (!new_entry) { 3237 PetscCall(PetscFree(val->perm)); 3238 PetscCall(PetscFree(val->invPerm)); 3239 } 3240 if (mode == PETSC_COPY_VALUES) { 3241 PetscCall(PetscMalloc1(clSize, &val->perm)); 3242 PetscCall(PetscArraycpy(val->perm, clPerm, clSize)); 3243 } else if (mode == PETSC_OWN_POINTER) { 3244 val->perm = clPerm; 3245 } else SETERRQ(PetscObjectComm(obj), PETSC_ERR_SUP, "Do not support borrowed arrays"); 3246 PetscCall(PetscMalloc1(clSize, &val->invPerm)); 3247 for (i = 0; i < clSize; ++i) val->invPerm[clPerm[i]] = i; 3248 PetscFunctionReturn(PETSC_SUCCESS); 3249 } 3250 3251 /*@ 3252 PetscSectionSetClosurePermutation - Set the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex. 3253 3254 Not Collective 3255 3256 Input Parameters: 3257 + section - The `PetscSection` 3258 . obj - A `PetscObject` which serves as the key for this index (usually a `DM`) 3259 . depth - Depth of points on which to apply the given permutation 3260 - perm - Permutation of the cell dof closure 3261 3262 Level: intermediate 3263 3264 Notes: 3265 The specified permutation will only be applied to points at depth whose closure size matches the length of perm. In a 3266 mixed-topology or variable-degree finite element space, this function can be called multiple times at each depth for 3267 each topology and degree. 3268 3269 This approach assumes that (depth, len(perm)) uniquely identifies the desired permutation; this might not be true for 3270 exotic/enriched spaces on mixed topology meshes. 3271 3272 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `IS`, `PetscSectionGetClosurePermutation()`, `PetscSectionGetClosureIndex()`, `DMPlexCreateClosureIndex()`, `PetscCopyMode` 3273 @*/ 3274 PetscErrorCode PetscSectionSetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, IS perm) 3275 { 3276 const PetscInt *clPerm = NULL; 3277 PetscInt clSize = 0; 3278 3279 PetscFunctionBegin; 3280 if (perm) { 3281 PetscCall(ISGetLocalSize(perm, &clSize)); 3282 PetscCall(ISGetIndices(perm, &clPerm)); 3283 } 3284 PetscCall(PetscSectionSetClosurePermutation_Internal(section, obj, depth, clSize, PETSC_COPY_VALUES, (PetscInt *)clPerm)); 3285 if (perm) PetscCall(ISRestoreIndices(perm, &clPerm)); 3286 PetscFunctionReturn(PETSC_SUCCESS); 3287 } 3288 3289 static PetscErrorCode PetscSectionGetClosurePermutation_Private(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[]) 3290 { 3291 PetscFunctionBegin; 3292 if (section->clObj == obj) { 3293 PetscSectionClosurePermKey k = {depth, size}; 3294 PetscSectionClosurePermVal v; 3295 3296 PetscCall(PetscClPermGet(section->clHash, k, &v)); 3297 if (perm) *perm = v.perm; 3298 } else { 3299 if (perm) *perm = NULL; 3300 } 3301 PetscFunctionReturn(PETSC_SUCCESS); 3302 } 3303 3304 /*@ 3305 PetscSectionGetClosurePermutation - Get the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex. 3306 3307 Not Collective 3308 3309 Input Parameters: 3310 + section - The `PetscSection` 3311 . obj - A `PetscObject` which serves as the key for this index (usually a DM) 3312 . depth - Depth stratum on which to obtain closure permutation 3313 - clSize - Closure size to be permuted (e.g., may vary with element topology and degree) 3314 3315 Output Parameter: 3316 . perm - The dof closure permutation 3317 3318 Level: intermediate 3319 3320 Note: 3321 The user must destroy the `IS` that is returned. 3322 3323 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `IS`, `PetscSectionSetClosurePermutation()`, `PetscSectionGetClosureInversePermutation()`, `PetscSectionGetClosureIndex()`, `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()` 3324 @*/ 3325 PetscErrorCode PetscSectionGetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm) 3326 { 3327 const PetscInt *clPerm = NULL; 3328 3329 PetscFunctionBegin; 3330 PetscCall(PetscSectionGetClosurePermutation_Private(section, obj, depth, clSize, &clPerm)); 3331 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); 3332 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm)); 3333 PetscFunctionReturn(PETSC_SUCCESS); 3334 } 3335 3336 PetscErrorCode PetscSectionGetClosureInversePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[]) 3337 { 3338 PetscFunctionBegin; 3339 if (section->clObj == obj && section->clHash) { 3340 PetscSectionClosurePermKey k = {depth, size}; 3341 PetscSectionClosurePermVal v; 3342 PetscCall(PetscClPermGet(section->clHash, k, &v)); 3343 if (perm) *perm = v.invPerm; 3344 } else { 3345 if (perm) *perm = NULL; 3346 } 3347 PetscFunctionReturn(PETSC_SUCCESS); 3348 } 3349 3350 /*@ 3351 PetscSectionGetClosureInversePermutation - Get the inverse dof permutation for the closure of each cell in the section, meaning clPerm[oldIndex] = newIndex. 3352 3353 Not Collective 3354 3355 Input Parameters: 3356 + section - The `PetscSection` 3357 . obj - A `PetscObject` which serves as the key for this index (usually a `DM`) 3358 . depth - Depth stratum on which to obtain closure permutation 3359 - clSize - Closure size to be permuted (e.g., may vary with element topology and degree) 3360 3361 Output Parameter: 3362 . perm - The dof closure permutation 3363 3364 Level: intermediate 3365 3366 Note: 3367 The user must destroy the `IS` that is returned. 3368 3369 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `IS`, `PetscSectionSetClosurePermutation()`, `PetscSectionGetClosureIndex()`, `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()` 3370 @*/ 3371 PetscErrorCode PetscSectionGetClosureInversePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm) 3372 { 3373 const PetscInt *clPerm = NULL; 3374 3375 PetscFunctionBegin; 3376 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, obj, depth, clSize, &clPerm)); 3377 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm)); 3378 PetscFunctionReturn(PETSC_SUCCESS); 3379 } 3380 3381 /*@ 3382 PetscSectionGetField - Get the `PetscSection` associated with a single field 3383 3384 Input Parameters: 3385 + s - The `PetscSection` 3386 - field - The field number 3387 3388 Output Parameter: 3389 . subs - The `PetscSection` for the given field, note the chart of `subs` is not set 3390 3391 Level: intermediate 3392 3393 Note: 3394 Does not increase the reference count of the selected sub-section. There is no matching `PetscSectionRestoreField()` 3395 3396 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `IS`, `PetscSectionSetNumFields()` 3397 @*/ 3398 PetscErrorCode PetscSectionGetField(PetscSection s, PetscInt field, PetscSection *subs) 3399 { 3400 PetscFunctionBegin; 3401 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 3402 PetscAssertPointer(subs, 3); 3403 PetscSectionCheckValidField(field, s->numFields); 3404 *subs = s->field[field]; 3405 PetscFunctionReturn(PETSC_SUCCESS); 3406 } 3407 3408 PetscClassId PETSC_SECTION_SYM_CLASSID; 3409 PetscFunctionList PetscSectionSymList = NULL; 3410 3411 /*@ 3412 PetscSectionSymCreate - Creates an empty `PetscSectionSym` object. 3413 3414 Collective 3415 3416 Input Parameter: 3417 . comm - the MPI communicator 3418 3419 Output Parameter: 3420 . sym - pointer to the new set of symmetries 3421 3422 Level: developer 3423 3424 .seealso: [PetscSection](ch_petscsection), `PetscSection`, `PetscSectionSym`, `PetscSectionSymDestroy()` 3425 @*/ 3426 PetscErrorCode PetscSectionSymCreate(MPI_Comm comm, PetscSectionSym *sym) 3427 { 3428 PetscFunctionBegin; 3429 PetscAssertPointer(sym, 2); 3430 PetscCall(ISInitializePackage()); 3431 3432 PetscCall(PetscHeaderCreate(*sym, PETSC_SECTION_SYM_CLASSID, "PetscSectionSym", "Section Symmetry", "IS", comm, PetscSectionSymDestroy, PetscSectionSymView)); 3433 PetscFunctionReturn(PETSC_SUCCESS); 3434 } 3435 3436 /*@ 3437 PetscSectionSymSetType - Builds a `PetscSectionSym`, for a particular implementation. 3438 3439 Collective 3440 3441 Input Parameters: 3442 + sym - The section symmetry object 3443 - method - The name of the section symmetry type 3444 3445 Level: developer 3446 3447 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymGetType()`, `PetscSectionSymCreate()` 3448 @*/ 3449 PetscErrorCode PetscSectionSymSetType(PetscSectionSym sym, PetscSectionSymType method) 3450 { 3451 PetscErrorCode (*r)(PetscSectionSym); 3452 PetscBool match; 3453 3454 PetscFunctionBegin; 3455 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3456 PetscCall(PetscObjectTypeCompare((PetscObject)sym, method, &match)); 3457 if (match) PetscFunctionReturn(PETSC_SUCCESS); 3458 3459 PetscCall(PetscFunctionListFind(PetscSectionSymList, method, &r)); 3460 PetscCheck(r, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscSectionSym type: %s", method); 3461 PetscTryTypeMethod(sym, destroy); 3462 sym->ops->destroy = NULL; 3463 3464 PetscCall((*r)(sym)); 3465 PetscCall(PetscObjectChangeTypeName((PetscObject)sym, method)); 3466 PetscFunctionReturn(PETSC_SUCCESS); 3467 } 3468 3469 /*@ 3470 PetscSectionSymGetType - Gets the section symmetry type name (as a string) from the `PetscSectionSym`. 3471 3472 Not Collective 3473 3474 Input Parameter: 3475 . sym - The section symmetry 3476 3477 Output Parameter: 3478 . type - The index set type name 3479 3480 Level: developer 3481 3482 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymSetType()`, `PetscSectionSymCreate()` 3483 @*/ 3484 PetscErrorCode PetscSectionSymGetType(PetscSectionSym sym, PetscSectionSymType *type) 3485 { 3486 PetscFunctionBegin; 3487 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3488 PetscAssertPointer(type, 2); 3489 *type = ((PetscObject)sym)->type_name; 3490 PetscFunctionReturn(PETSC_SUCCESS); 3491 } 3492 3493 /*@C 3494 PetscSectionSymRegister - Registers a new section symmetry implementation 3495 3496 Not Collective, No Fortran Support 3497 3498 Input Parameters: 3499 + sname - The name of a new user-defined creation routine 3500 - function - The creation routine itself 3501 3502 Level: developer 3503 3504 Notes: 3505 `PetscSectionSymRegister()` may be called multiple times to add several user-defined vectors 3506 3507 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymCreate()`, `PetscSectionSymSetType()` 3508 @*/ 3509 PetscErrorCode PetscSectionSymRegister(const char sname[], PetscErrorCode (*function)(PetscSectionSym)) 3510 { 3511 PetscFunctionBegin; 3512 PetscCall(ISInitializePackage()); 3513 PetscCall(PetscFunctionListAdd(&PetscSectionSymList, sname, function)); 3514 PetscFunctionReturn(PETSC_SUCCESS); 3515 } 3516 3517 /*@ 3518 PetscSectionSymDestroy - Destroys a section symmetry. 3519 3520 Collective 3521 3522 Input Parameter: 3523 . sym - the section symmetry 3524 3525 Level: developer 3526 3527 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()` 3528 @*/ 3529 PetscErrorCode PetscSectionSymDestroy(PetscSectionSym *sym) 3530 { 3531 SymWorkLink link, next; 3532 3533 PetscFunctionBegin; 3534 if (!*sym) PetscFunctionReturn(PETSC_SUCCESS); 3535 PetscValidHeaderSpecific(*sym, PETSC_SECTION_SYM_CLASSID, 1); 3536 if (--((PetscObject)*sym)->refct > 0) { 3537 *sym = NULL; 3538 PetscFunctionReturn(PETSC_SUCCESS); 3539 } 3540 PetscTryTypeMethod(*sym, destroy); 3541 PetscCheck(!(*sym)->workout, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Work array still checked out"); 3542 for (link = (*sym)->workin; link; link = next) { 3543 PetscInt **perms = (PetscInt **)link->perms; 3544 PetscScalar **rots = (PetscScalar **)link->rots; 3545 PetscCall(PetscFree2(perms, rots)); 3546 next = link->next; 3547 PetscCall(PetscFree(link)); 3548 } 3549 (*sym)->workin = NULL; 3550 PetscCall(PetscHeaderDestroy(sym)); 3551 PetscFunctionReturn(PETSC_SUCCESS); 3552 } 3553 3554 /*@ 3555 PetscSectionSymView - Displays a section symmetry 3556 3557 Collective 3558 3559 Input Parameters: 3560 + sym - the index set 3561 - viewer - viewer used to display the set, for example `PETSC_VIEWER_STDOUT_SELF`. 3562 3563 Level: developer 3564 3565 .seealso: `PetscSectionSym`, `PetscViewer`, `PetscViewerASCIIOpen()` 3566 @*/ 3567 PetscErrorCode PetscSectionSymView(PetscSectionSym sym, PetscViewer viewer) 3568 { 3569 PetscFunctionBegin; 3570 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3571 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sym), &viewer)); 3572 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 3573 PetscCheckSameComm(sym, 1, viewer, 2); 3574 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)sym, viewer)); 3575 PetscTryTypeMethod(sym, view, viewer); 3576 PetscFunctionReturn(PETSC_SUCCESS); 3577 } 3578 3579 /*@ 3580 PetscSectionSetSym - Set the symmetries for the data referred to by the section 3581 3582 Collective 3583 3584 Input Parameters: 3585 + section - the section describing data layout 3586 - sym - the symmetry describing the affect of orientation on the access of the data 3587 3588 Level: developer 3589 3590 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetSym()`, `PetscSectionSymCreate()` 3591 @*/ 3592 PetscErrorCode PetscSectionSetSym(PetscSection section, PetscSectionSym sym) 3593 { 3594 PetscFunctionBegin; 3595 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3596 PetscCall(PetscSectionSymDestroy(§ion->sym)); 3597 if (sym) { 3598 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 2); 3599 PetscCheckSameComm(section, 1, sym, 2); 3600 PetscCall(PetscObjectReference((PetscObject)sym)); 3601 } 3602 section->sym = sym; 3603 PetscFunctionReturn(PETSC_SUCCESS); 3604 } 3605 3606 /*@ 3607 PetscSectionGetSym - Get the symmetries for the data referred to by the section 3608 3609 Not Collective 3610 3611 Input Parameter: 3612 . section - the section describing data layout 3613 3614 Output Parameter: 3615 . sym - the symmetry describing the affect of orientation on the access of the data, provided previously by `PetscSectionSetSym()` 3616 3617 Level: developer 3618 3619 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSetSym()`, `PetscSectionSymCreate()` 3620 @*/ 3621 PetscErrorCode PetscSectionGetSym(PetscSection section, PetscSectionSym *sym) 3622 { 3623 PetscFunctionBegin; 3624 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3625 *sym = section->sym; 3626 PetscFunctionReturn(PETSC_SUCCESS); 3627 } 3628 3629 /*@ 3630 PetscSectionSetFieldSym - Set the symmetries for the data referred to by a field of the section 3631 3632 Collective 3633 3634 Input Parameters: 3635 + section - the section describing data layout 3636 . field - the field number 3637 - sym - the symmetry describing the affect of orientation on the access of the data 3638 3639 Level: developer 3640 3641 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetFieldSym()`, `PetscSectionSymCreate()` 3642 @*/ 3643 PetscErrorCode PetscSectionSetFieldSym(PetscSection section, PetscInt field, PetscSectionSym sym) 3644 { 3645 PetscFunctionBegin; 3646 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3647 PetscSectionCheckValidField(field, section->numFields); 3648 PetscCall(PetscSectionSetSym(section->field[field], sym)); 3649 PetscFunctionReturn(PETSC_SUCCESS); 3650 } 3651 3652 /*@ 3653 PetscSectionGetFieldSym - Get the symmetries for the data referred to by a field of the section 3654 3655 Collective 3656 3657 Input Parameters: 3658 + section - the section describing data layout 3659 - field - the field number 3660 3661 Output Parameter: 3662 . sym - the symmetry describing the affect of orientation on the access of the data 3663 3664 Level: developer 3665 3666 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSetFieldSym()`, `PetscSectionSymCreate()` 3667 @*/ 3668 PetscErrorCode PetscSectionGetFieldSym(PetscSection section, PetscInt field, PetscSectionSym *sym) 3669 { 3670 PetscFunctionBegin; 3671 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3672 PetscSectionCheckValidField(field, section->numFields); 3673 *sym = section->field[field]->sym; 3674 PetscFunctionReturn(PETSC_SUCCESS); 3675 } 3676 3677 /*@C 3678 PetscSectionGetPointSyms - Get the symmetries for a set of points in a `PetscSection` under specific orientations. 3679 3680 Not Collective 3681 3682 Input Parameters: 3683 + section - the section 3684 . numPoints - the number of points 3685 - points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an 3686 arbitrary integer: its interpretation is up to sym. Orientations are used by `DM`: for their interpretation in that 3687 context, see `DMPlexGetConeOrientation()`). 3688 3689 Output Parameters: 3690 + perms - The permutations for the given orientations (or `NULL` if there is no symmetry or the permutation is the identity). 3691 - rots - The field rotations symmetries for the given orientations (or `NULL` if there is no symmetry or the rotations are all 3692 identity). 3693 3694 Example of usage, gathering dofs into a local array (lArray) from a section array (sArray): 3695 .vb 3696 const PetscInt **perms; 3697 const PetscScalar **rots; 3698 PetscInt lOffset; 3699 3700 PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots); 3701 for (i = 0, lOffset = 0; i < numPoints; i++) { 3702 PetscInt point = points[2*i], dof, sOffset; 3703 const PetscInt *perm = perms ? perms[i] : NULL; 3704 const PetscScalar *rot = rots ? rots[i] : NULL; 3705 3706 PetscSectionGetDof(section,point,&dof); 3707 PetscSectionGetOffset(section,point,&sOffset); 3708 3709 if (perm) { for (j = 0; j < dof; j++) lArray[lOffset + perm[j]] = sArray[sOffset + j]; } 3710 else { for (j = 0; j < dof; j++) lArray[lOffset + j ] = sArray[sOffset + j]; } 3711 if (rot) { for (j = 0; j < dof; j++) lArray[lOffset + j ] *= rot[j]; } 3712 lOffset += dof; 3713 } 3714 PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots); 3715 .ve 3716 3717 Example of usage, adding dofs into a section array (sArray) from a local array (lArray): 3718 .vb 3719 const PetscInt **perms; 3720 const PetscScalar **rots; 3721 PetscInt lOffset; 3722 3723 PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots); 3724 for (i = 0, lOffset = 0; i < numPoints; i++) { 3725 PetscInt point = points[2*i], dof, sOffset; 3726 const PetscInt *perm = perms ? perms[i] : NULL; 3727 const PetscScalar *rot = rots ? rots[i] : NULL; 3728 3729 PetscSectionGetDof(section,point,&dof); 3730 PetscSectionGetOffset(section,point,&sOff); 3731 3732 if (perm) { for (j = 0; j < dof; j++) sArray[sOffset + j] += lArray[lOffset + perm[j]] * (rot ? PetscConj(rot[perm[j]]) : 1.); } 3733 else { for (j = 0; j < dof; j++) sArray[sOffset + j] += lArray[lOffset + j ] * (rot ? PetscConj(rot[ j ]) : 1.); } 3734 offset += dof; 3735 } 3736 PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots); 3737 .ve 3738 3739 Level: developer 3740 3741 Notes: 3742 `PetscSectionSetSym()` must have been previously called to provide the symmetries to the `PetscSection` 3743 3744 Use `PetscSectionRestorePointSyms()` when finished with the data 3745 3746 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionRestorePointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()` 3747 @*/ 3748 PetscErrorCode PetscSectionGetPointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots) 3749 { 3750 PetscSectionSym sym; 3751 3752 PetscFunctionBegin; 3753 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3754 if (numPoints) PetscAssertPointer(points, 3); 3755 if (perms) *perms = NULL; 3756 if (rots) *rots = NULL; 3757 sym = section->sym; 3758 if (sym && (perms || rots)) { 3759 SymWorkLink link; 3760 3761 if (sym->workin) { 3762 link = sym->workin; 3763 sym->workin = sym->workin->next; 3764 } else { 3765 PetscCall(PetscNew(&link)); 3766 } 3767 if (numPoints > link->numPoints) { 3768 PetscInt **perms = (PetscInt **)link->perms; 3769 PetscScalar **rots = (PetscScalar **)link->rots; 3770 PetscCall(PetscFree2(perms, rots)); 3771 PetscCall(PetscMalloc2(numPoints, (PetscInt ***)&link->perms, numPoints, (PetscScalar ***)&link->rots)); 3772 link->numPoints = numPoints; 3773 } 3774 link->next = sym->workout; 3775 sym->workout = link; 3776 PetscCall(PetscArrayzero((PetscInt **)link->perms, numPoints)); 3777 PetscCall(PetscArrayzero((PetscInt **)link->rots, numPoints)); 3778 PetscUseTypeMethod(sym, getpoints, section, numPoints, points, link->perms, link->rots); 3779 if (perms) *perms = link->perms; 3780 if (rots) *rots = link->rots; 3781 } 3782 PetscFunctionReturn(PETSC_SUCCESS); 3783 } 3784 3785 /*@C 3786 PetscSectionRestorePointSyms - Restore the symmetries returned by `PetscSectionGetPointSyms()` 3787 3788 Not Collective 3789 3790 Input Parameters: 3791 + section - the section 3792 . numPoints - the number of points 3793 . points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an 3794 arbitrary integer: its interpretation is up to sym. Orientations are used by `DM`: for their interpretation in that 3795 context, see `DMPlexGetConeOrientation()`). 3796 . perms - The permutations for the given orientations: set to `NULL` at conclusion 3797 - rots - The field rotations symmetries for the given orientations: set to `NULL` at conclusion 3798 3799 Level: developer 3800 3801 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetPointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()` 3802 @*/ 3803 PetscErrorCode PetscSectionRestorePointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots) 3804 { 3805 PetscSectionSym sym; 3806 3807 PetscFunctionBegin; 3808 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3809 sym = section->sym; 3810 if (sym && (perms || rots)) { 3811 SymWorkLink *p, link; 3812 3813 for (p = &sym->workout; (link = *p); p = &link->next) { 3814 if ((perms && link->perms == *perms) || (rots && link->rots == *rots)) { 3815 *p = link->next; 3816 link->next = sym->workin; 3817 sym->workin = link; 3818 if (perms) *perms = NULL; 3819 if (rots) *rots = NULL; 3820 PetscFunctionReturn(PETSC_SUCCESS); 3821 } 3822 } 3823 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Array was not checked out"); 3824 } 3825 PetscFunctionReturn(PETSC_SUCCESS); 3826 } 3827 3828 /*@C 3829 PetscSectionGetFieldPointSyms - Get the symmetries for a set of points in a field of a `PetscSection` under specific orientations. 3830 3831 Not Collective 3832 3833 Input Parameters: 3834 + section - the section 3835 . field - the field of the section 3836 . numPoints - the number of points 3837 - points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an 3838 arbitrary integer: its interpretation is up to sym. Orientations are used by `DM`: for their interpretation in that 3839 context, see `DMPlexGetConeOrientation()`). 3840 3841 Output Parameters: 3842 + perms - The permutations for the given orientations (or `NULL` if there is no symmetry or the permutation is the identity). 3843 - rots - The field rotations symmetries for the given orientations (or `NULL` if there is no symmetry or the rotations are all 3844 identity). 3845 3846 Level: developer 3847 3848 Notes: 3849 `PetscSectionSetFieldSym()` must have been previously called to provide the symmetries to the `PetscSection` 3850 3851 Use `PetscSectionRestoreFieldPointSyms()` when finished with the data 3852 3853 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetPointSyms()`, `PetscSectionRestoreFieldPointSyms()` 3854 @*/ 3855 PetscErrorCode PetscSectionGetFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots) 3856 { 3857 PetscFunctionBegin; 3858 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3859 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); 3860 PetscCall(PetscSectionGetPointSyms(section->field[field], numPoints, points, perms, rots)); 3861 PetscFunctionReturn(PETSC_SUCCESS); 3862 } 3863 3864 /*@C 3865 PetscSectionRestoreFieldPointSyms - Restore the symmetries returned by `PetscSectionGetFieldPointSyms()` 3866 3867 Not Collective 3868 3869 Input Parameters: 3870 + section - the section 3871 . field - the field number 3872 . numPoints - the number of points 3873 . points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an 3874 arbitrary integer: its interpretation is up to sym. Orientations are used by `DM`: for their interpretation in that 3875 context, see `DMPlexGetConeOrientation()`). 3876 . perms - The permutations for the given orientations: set to NULL at conclusion 3877 - rots - The field rotations symmetries for the given orientations: set to NULL at conclusion 3878 3879 Level: developer 3880 3881 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionRestorePointSyms()`, `petscSectionGetFieldPointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()` 3882 @*/ 3883 PetscErrorCode PetscSectionRestoreFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots) 3884 { 3885 PetscFunctionBegin; 3886 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3887 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); 3888 PetscCall(PetscSectionRestorePointSyms(section->field[field], numPoints, points, perms, rots)); 3889 PetscFunctionReturn(PETSC_SUCCESS); 3890 } 3891 3892 /*@ 3893 PetscSectionSymCopy - Copy the symmetries, assuming that the point structure is compatible 3894 3895 Not Collective 3896 3897 Input Parameter: 3898 . sym - the `PetscSectionSym` 3899 3900 Output Parameter: 3901 . nsym - the equivalent symmetries 3902 3903 Level: developer 3904 3905 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()` 3906 @*/ 3907 PetscErrorCode PetscSectionSymCopy(PetscSectionSym sym, PetscSectionSym nsym) 3908 { 3909 PetscFunctionBegin; 3910 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3911 PetscValidHeaderSpecific(nsym, PETSC_SECTION_SYM_CLASSID, 2); 3912 PetscTryTypeMethod(sym, copy, nsym); 3913 PetscFunctionReturn(PETSC_SUCCESS); 3914 } 3915 3916 /*@ 3917 PetscSectionSymDistribute - Distribute the symmetries in accordance with the input `PetscSF` 3918 3919 Collective 3920 3921 Input Parameters: 3922 + sym - the `PetscSectionSym` 3923 - migrationSF - the distribution map from roots to leaves 3924 3925 Output Parameter: 3926 . dsym - the redistributed symmetries 3927 3928 Level: developer 3929 3930 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()` 3931 @*/ 3932 PetscErrorCode PetscSectionSymDistribute(PetscSectionSym sym, PetscSF migrationSF, PetscSectionSym *dsym) 3933 { 3934 PetscFunctionBegin; 3935 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3936 PetscValidHeaderSpecific(migrationSF, PETSCSF_CLASSID, 2); 3937 PetscAssertPointer(dsym, 3); 3938 PetscTryTypeMethod(sym, distribute, migrationSF, dsym); 3939 PetscFunctionReturn(PETSC_SUCCESS); 3940 } 3941 3942 /*@ 3943 PetscSectionGetUseFieldOffsets - Get the flag indicating if field offsets are used directly in a global section, rather than just the point offset 3944 3945 Not Collective 3946 3947 Input Parameter: 3948 . s - the global `PetscSection` 3949 3950 Output Parameter: 3951 . flg - the flag 3952 3953 Level: developer 3954 3955 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionSetChart()`, `PetscSectionCreate()` 3956 @*/ 3957 PetscErrorCode PetscSectionGetUseFieldOffsets(PetscSection s, PetscBool *flg) 3958 { 3959 PetscFunctionBegin; 3960 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 3961 *flg = s->useFieldOff; 3962 PetscFunctionReturn(PETSC_SUCCESS); 3963 } 3964 3965 /*@ 3966 PetscSectionSetUseFieldOffsets - Set the flag to use field offsets directly in a global section, rather than just the point offset 3967 3968 Not Collective 3969 3970 Input Parameters: 3971 + s - the global `PetscSection` 3972 - flg - the flag 3973 3974 Level: developer 3975 3976 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetUseFieldOffsets()`, `PetscSectionSetChart()`, `PetscSectionCreate()` 3977 @*/ 3978 PetscErrorCode PetscSectionSetUseFieldOffsets(PetscSection s, PetscBool flg) 3979 { 3980 PetscFunctionBegin; 3981 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 3982 s->useFieldOff = flg; 3983 PetscFunctionReturn(PETSC_SUCCESS); 3984 } 3985 3986 #define PetscSectionExpandPoints_Loop(TYPE) \ 3987 do { \ 3988 PetscInt i, n, o0, o1, size; \ 3989 TYPE *a0 = (TYPE *)origArray, *a1; \ 3990 PetscCall(PetscSectionGetStorageSize(s, &size)); \ 3991 PetscCall(PetscMalloc1(size, &a1)); \ 3992 for (i = 0; i < npoints; i++) { \ 3993 PetscCall(PetscSectionGetOffset(origSection, points_[i], &o0)); \ 3994 PetscCall(PetscSectionGetOffset(s, i, &o1)); \ 3995 PetscCall(PetscSectionGetDof(s, i, &n)); \ 3996 PetscCall(PetscMemcpy(&a1[o1], &a0[o0], n * unitsize)); \ 3997 } \ 3998 *newArray = (void *)a1; \ 3999 } while (0) 4000 4001 /*@ 4002 PetscSectionExtractDofsFromArray - Extracts elements of an array corresponding to DOFs of specified points. 4003 4004 Not Collective 4005 4006 Input Parameters: 4007 + origSection - the `PetscSection` describing the layout of the array 4008 . dataType - `MPI_Datatype` describing the data type of the array (currently only `MPIU_INT`, `MPIU_SCALAR`, `MPIU_REAL`) 4009 . origArray - the array; its size must be equal to the storage size of `origSection` 4010 - points - `IS` with points to extract; its indices must lie in the chart of `origSection` 4011 4012 Output Parameters: 4013 + newSection - the new `PetscSection` describing the layout of the new array (with points renumbered 0,1,... but preserving numbers of DOFs) 4014 - newArray - the array of the extracted DOFs; its size is the storage size of `newSection` 4015 4016 Level: developer 4017 4018 .seealso: [PetscSection](ch_petscsection), `PetscSectionSym`, `PetscSectionGetChart()`, `PetscSectionGetDof()`, `PetscSectionGetStorageSize()`, `PetscSectionCreate()` 4019 @*/ 4020 PetscErrorCode PetscSectionExtractDofsFromArray(PetscSection origSection, MPI_Datatype dataType, const void *origArray, IS points, PetscSection *newSection, void *newArray[]) 4021 { 4022 PetscSection s; 4023 const PetscInt *points_; 4024 PetscInt i, n, npoints, pStart, pEnd; 4025 PetscMPIInt unitsize; 4026 4027 PetscFunctionBegin; 4028 PetscValidHeaderSpecific(origSection, PETSC_SECTION_CLASSID, 1); 4029 PetscAssertPointer(origArray, 3); 4030 PetscValidHeaderSpecific(points, IS_CLASSID, 4); 4031 if (newSection) PetscAssertPointer(newSection, 5); 4032 if (newArray) PetscAssertPointer(newArray, 6); 4033 PetscCallMPI(MPI_Type_size(dataType, &unitsize)); 4034 PetscCall(ISGetLocalSize(points, &npoints)); 4035 PetscCall(ISGetIndices(points, &points_)); 4036 PetscCall(PetscSectionGetChart(origSection, &pStart, &pEnd)); 4037 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 4038 PetscCall(PetscSectionSetChart(s, 0, npoints)); 4039 for (i = 0; i < npoints; i++) { 4040 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); 4041 PetscCall(PetscSectionGetDof(origSection, points_[i], &n)); 4042 PetscCall(PetscSectionSetDof(s, i, n)); 4043 } 4044 PetscCall(PetscSectionSetUp(s)); 4045 if (newArray) { 4046 if (dataType == MPIU_INT) { 4047 PetscSectionExpandPoints_Loop(PetscInt); 4048 } else if (dataType == MPIU_SCALAR) { 4049 PetscSectionExpandPoints_Loop(PetscScalar); 4050 } else if (dataType == MPIU_REAL) { 4051 PetscSectionExpandPoints_Loop(PetscReal); 4052 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "not implemented for this MPI_Datatype"); 4053 } 4054 if (newSection) { 4055 *newSection = s; 4056 } else { 4057 PetscCall(PetscSectionDestroy(&s)); 4058 } 4059 PetscCall(ISRestoreIndices(points, &points_)); 4060 PetscFunctionReturn(PETSC_SUCCESS); 4061 } 4062