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