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