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