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