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