1 /* 2 This file contains routines for basic section object implementation. 3 */ 4 5 #include <petsc/private/sectionimpl.h> /*I "petscsection.h" I*/ 6 #include <petscsf.h> 7 8 PetscClassId PETSC_SECTION_CLASSID; 9 10 /*@ 11 PetscSectionCreate - Allocates a `PetscSection` and sets the map contents to the default. 12 13 Collective 14 15 Input Parameters: 16 + comm - the MPI communicator 17 - s - pointer to the section 18 19 Level: beginner 20 21 Notes: 22 Typical calling sequence 23 .vb 24 PetscSectionCreate(MPI_Comm,PetscSection *);! 25 PetscSectionSetNumFields(PetscSection, numFields); 26 PetscSectionSetChart(PetscSection,low,high); 27 PetscSectionSetDof(PetscSection,point,numdof); 28 PetscSectionSetUp(PetscSection); 29 PetscSectionGetOffset(PetscSection,point,PetscInt *); 30 PetscSectionDestroy(PetscSection); 31 .ve 32 33 The `PetscSection` object and methods are intended to be used in the PETSc `Vec` and `Mat` implementations. The indices returned by the `PetscSection` are appropriate for the kind of `Vec` it is associated with. For example, if the vector being indexed is a local vector, we call the section a local section. If the section indexes a global vector, we call it a global section. For parallel vectors, like global vectors, we use negative indices to indicate dofs owned by other processes. 34 35 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSetChart()`, `PetscSectionDestroy()`, `PetscSectionCreateGlobalSection()` 36 @*/ 37 PetscErrorCode PetscSectionCreate(MPI_Comm comm, PetscSection *s) 38 { 39 PetscFunctionBegin; 40 PetscAssertPointer(s, 2); 41 PetscCall(ISInitializePackage()); 42 43 PetscCall(PetscHeaderCreate(*s, PETSC_SECTION_CLASSID, "PetscSection", "Section", "IS", comm, PetscSectionDestroy, PetscSectionView)); 44 (*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](sec_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](sec_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](sec_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](sec_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 PetscCall(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](sec_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](sec_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, (char **)&s->fieldNames[f])); 399 PetscCall(PetscSNPrintf(name, 64, "Component_0")); 400 PetscCall(PetscMalloc1(s->numFieldComponents[f], &s->compNames[f])); 401 PetscCall(PetscStrallocpy(name, (char **)&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](sec_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](sec_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, (char **)&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](sec_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](sec_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, (char **)&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](sec_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](sec_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, (char ***)&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, (char **)&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](sec_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](sec_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](sec_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](sec_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](sec_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](sec_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](sec_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](sec_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](sec_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](sec_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](sec_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](sec_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](sec_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](sec_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](sec_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](sec_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](sec_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](sec_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](sec_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 PetscCall(PetscMalloc1((last >= 0 ? s->bc->atlasOff[last] + s->bc->atlasDof[last] : 0), &s->bcIndices)); 1269 } 1270 PetscFunctionReturn(PETSC_SUCCESS); 1271 } 1272 1273 /*@ 1274 PetscSectionSetUp - Calculate offsets based upon the number of degrees of freedom for each point in preparation for use of the `PetscSection` 1275 1276 Not Collective 1277 1278 Input Parameter: 1279 . s - the `PetscSection` 1280 1281 Level: intermediate 1282 1283 Notes: 1284 If used, `PetscSectionSetPermutation()` must be called before this routine. 1285 1286 `PetscSectionSetPointMajor()`, cannot be called after this routine. 1287 1288 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionSetPermutation()` 1289 @*/ 1290 PetscErrorCode PetscSectionSetUp(PetscSection s) 1291 { 1292 const PetscInt *pind = NULL; 1293 PetscInt offset = 0, foff, p, f; 1294 1295 PetscFunctionBegin; 1296 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1297 if (s->setup) PetscFunctionReturn(PETSC_SUCCESS); 1298 s->setup = PETSC_TRUE; 1299 /* Set offsets and field offsets for all points */ 1300 /* Assume that all fields have the same chart */ 1301 PetscCheck(s->includesConstraints, PETSC_COMM_SELF, PETSC_ERR_SUP, "PetscSectionSetUp is currently unsupported for includesConstraints = PETSC_TRUE"); 1302 if (s->perm) PetscCall(ISGetIndices(s->perm, &pind)); 1303 if (s->pointMajor) { 1304 for (p = 0; p < s->pEnd - s->pStart; ++p) { 1305 const PetscInt q = pind ? pind[p] : p; 1306 1307 /* Set point offset */ 1308 s->atlasOff[q] = offset; 1309 offset += s->atlasDof[q]; 1310 /* Set field offset */ 1311 for (f = 0, foff = s->atlasOff[q]; f < s->numFields; ++f) { 1312 PetscSection sf = s->field[f]; 1313 1314 sf->atlasOff[q] = foff; 1315 foff += sf->atlasDof[q]; 1316 } 1317 } 1318 } else { 1319 /* Set field offsets for all points */ 1320 for (f = 0; f < s->numFields; ++f) { 1321 PetscSection sf = s->field[f]; 1322 1323 for (p = 0; p < s->pEnd - s->pStart; ++p) { 1324 const PetscInt q = pind ? pind[p] : p; 1325 1326 sf->atlasOff[q] = offset; 1327 offset += sf->atlasDof[q]; 1328 } 1329 } 1330 /* Disable point offsets since these are unused */ 1331 for (p = 0; p < s->pEnd - s->pStart; ++p) s->atlasOff[p] = -1; 1332 } 1333 if (s->perm) PetscCall(ISRestoreIndices(s->perm, &pind)); 1334 /* Setup BC sections */ 1335 PetscCall(PetscSectionSetUpBC(s)); 1336 for (f = 0; f < s->numFields; ++f) PetscCall(PetscSectionSetUpBC(s->field[f])); 1337 PetscFunctionReturn(PETSC_SUCCESS); 1338 } 1339 1340 /*@ 1341 PetscSectionGetMaxDof - Return the maximum number of degrees of freedom on any point in the `PetscSection` 1342 1343 Not Collective 1344 1345 Input Parameter: 1346 . s - the `PetscSection` 1347 1348 Output Parameter: 1349 . maxDof - the maximum dof 1350 1351 Level: intermediate 1352 1353 Notes: 1354 The returned number is up-to-date without need for `PetscSectionSetUp()`. 1355 1356 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 1357 the maximum over all points of the value returned by `PetscSectionGetDof()` on this MPI process 1358 1359 Developer Notes: 1360 The returned number is calculated lazily and stashed. 1361 1362 A call to `PetscSectionInvalidateMaxDof_Internal()` invalidates the stashed value. 1363 1364 `PetscSectionInvalidateMaxDof_Internal()` is called in `PetscSectionSetDof()`, `PetscSectionAddDof()` and `PetscSectionReset()` 1365 1366 It should also be called every time `atlasDof` is modified directly. 1367 1368 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetDof()`, `PetscSectionSetDof()`, `PetscSectionAddDof()`, `PetscSectionCreate()` 1369 @*/ 1370 PetscErrorCode PetscSectionGetMaxDof(PetscSection s, PetscInt *maxDof) 1371 { 1372 PetscInt p; 1373 1374 PetscFunctionBegin; 1375 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1376 PetscAssertPointer(maxDof, 2); 1377 if (s->maxDof == PETSC_MIN_INT) { 1378 s->maxDof = 0; 1379 for (p = 0; p < s->pEnd - s->pStart; ++p) s->maxDof = PetscMax(s->maxDof, s->atlasDof[p]); 1380 } 1381 *maxDof = s->maxDof; 1382 PetscFunctionReturn(PETSC_SUCCESS); 1383 } 1384 1385 /*@ 1386 PetscSectionGetStorageSize - Return the size of an array or local `Vec` capable of holding all the degrees of freedom defined in a `PetscSection` 1387 1388 Not Collective 1389 1390 Input Parameter: 1391 . s - the `PetscSection` 1392 1393 Output Parameter: 1394 . size - the size of an array which can hold all the dofs 1395 1396 Level: intermediate 1397 1398 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionGetConstrainedStorageSize()`, `PetscSectionCreate()` 1399 @*/ 1400 PetscErrorCode PetscSectionGetStorageSize(PetscSection s, PetscInt *size) 1401 { 1402 PetscInt p, n = 0; 1403 1404 PetscFunctionBegin; 1405 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1406 PetscAssertPointer(size, 2); 1407 for (p = 0; p < s->pEnd - s->pStart; ++p) n += s->atlasDof[p] > 0 ? s->atlasDof[p] : 0; 1408 *size = n; 1409 PetscFunctionReturn(PETSC_SUCCESS); 1410 } 1411 1412 /*@ 1413 PetscSectionGetConstrainedStorageSize - Return the size of an array or local `Vec` capable of holding all unconstrained degrees of freedom in a `PetscSection` 1414 1415 Not Collective 1416 1417 Input Parameter: 1418 . s - the `PetscSection` 1419 1420 Output Parameter: 1421 . size - the size of an array which can hold all unconstrained dofs 1422 1423 Level: intermediate 1424 1425 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetStorageSize()`, `PetscSectionGetOffset()`, `PetscSectionCreate()` 1426 @*/ 1427 PetscErrorCode PetscSectionGetConstrainedStorageSize(PetscSection s, PetscInt *size) 1428 { 1429 PetscInt p, n = 0; 1430 1431 PetscFunctionBegin; 1432 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1433 PetscAssertPointer(size, 2); 1434 for (p = 0; p < s->pEnd - s->pStart; ++p) { 1435 const PetscInt cdof = s->bc ? s->bc->atlasDof[p] : 0; 1436 n += s->atlasDof[p] > 0 ? s->atlasDof[p] - cdof : 0; 1437 } 1438 *size = n; 1439 PetscFunctionReturn(PETSC_SUCCESS); 1440 } 1441 1442 /*@ 1443 PetscSectionCreateGlobalSection - Create a parallel section describing the global layout using 1444 a local (sequential) `PetscSection` on each MPI process and a `PetscSF` describing the section point overlap. 1445 1446 Input Parameters: 1447 + s - The `PetscSection` for the local field layout 1448 . sf - The `PetscSF` describing parallel layout of the section points (leaves are unowned local points) 1449 . usePermutation - By default this is `PETSC_TRUE`, meaning any permutation of the local section is transferred to the global section 1450 . includeConstraints - By default this is `PETSC_FALSE`, meaning that the global field vector will not possess constrained dofs 1451 - localOffsets - If `PETSC_TRUE`, use local rather than global offsets for the points 1452 1453 Output Parameter: 1454 . gsection - The `PetscSection` for the global field layout 1455 1456 Level: intermediate 1457 1458 Notes: 1459 On each MPI process `gsection` inherits the chart of the `s` on that process. 1460 1461 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`. 1462 In those locations the value of size is -(size+1) and the value of the offset on the remote process is -(off+1). 1463 1464 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionCreateGlobalSectionCensored()` 1465 @*/ 1466 PetscErrorCode PetscSectionCreateGlobalSection(PetscSection s, PetscSF sf, PetscBool usePermutation, PetscBool includeConstraints, PetscBool localOffsets, PetscSection *gsection) 1467 { 1468 PetscSection gs; 1469 const PetscInt *pind = NULL; 1470 PetscInt *recv = NULL, *neg = NULL; 1471 PetscInt pStart, pEnd, p, dof, cdof, off, foff, globalOff = 0, nroots, nlocal, maxleaf; 1472 PetscInt numFields, f, numComponents; 1473 1474 PetscFunctionBegin; 1475 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1476 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2); 1477 PetscValidLogicalCollectiveBool(s, usePermutation, 3); 1478 PetscValidLogicalCollectiveBool(s, includeConstraints, 4); 1479 PetscValidLogicalCollectiveBool(s, localOffsets, 5); 1480 PetscAssertPointer(gsection, 6); 1481 PetscCheck(s->pointMajor, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for field major ordering"); 1482 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), &gs)); 1483 PetscCall(PetscSectionGetNumFields(s, &numFields)); 1484 if (numFields > 0) PetscCall(PetscSectionSetNumFields(gs, numFields)); 1485 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 1486 PetscCall(PetscSectionSetChart(gs, pStart, pEnd)); 1487 gs->includesConstraints = includeConstraints; 1488 PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL)); 1489 nlocal = nroots; /* The local/leaf space matches global/root space */ 1490 /* Must allocate for all points visible to SF, which may be more than this section */ 1491 if (nroots >= 0) { /* nroots < 0 means that the graph has not been set, only happens in serial */ 1492 PetscCall(PetscSFGetLeafRange(sf, NULL, &maxleaf)); 1493 PetscCheck(nroots >= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "SF roots %" PetscInt_FMT " < pEnd %" PetscInt_FMT, nroots, pEnd); 1494 PetscCheck(maxleaf < nroots, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Max local leaf %" PetscInt_FMT " >= nroots %" PetscInt_FMT, maxleaf, nroots); 1495 PetscCall(PetscMalloc2(nroots, &neg, nlocal, &recv)); 1496 PetscCall(PetscArrayzero(neg, nroots)); 1497 } 1498 /* Mark all local points with negative dof */ 1499 for (p = pStart; p < pEnd; ++p) { 1500 PetscCall(PetscSectionGetDof(s, p, &dof)); 1501 PetscCall(PetscSectionSetDof(gs, p, dof)); 1502 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 1503 if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetConstraintDof(gs, p, cdof)); 1504 if (neg) neg[p] = -(dof + 1); 1505 } 1506 PetscCall(PetscSectionSetUpBC(gs)); 1507 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])); 1508 if (nroots >= 0) { 1509 PetscCall(PetscArrayzero(recv, nlocal)); 1510 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, recv, MPI_REPLACE)); 1511 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, recv, MPI_REPLACE)); 1512 for (p = pStart; p < pEnd; ++p) { 1513 if (recv[p] < 0) { 1514 gs->atlasDof[p - pStart] = recv[p]; 1515 PetscCall(PetscSectionGetDof(s, p, &dof)); 1516 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); 1517 } 1518 } 1519 } 1520 /* Calculate new sizes, get process offset, and calculate point offsets */ 1521 if (usePermutation && s->perm) PetscCall(ISGetIndices(s->perm, &pind)); 1522 for (p = 0, off = 0; p < pEnd - pStart; ++p) { 1523 const PetscInt q = pind ? pind[p] : p; 1524 1525 cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[q] : 0; 1526 gs->atlasOff[q] = off; 1527 off += gs->atlasDof[q] > 0 ? gs->atlasDof[q] - cdof : 0; 1528 } 1529 if (!localOffsets) { 1530 PetscCallMPI(MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)s))); 1531 globalOff -= off; 1532 } 1533 for (p = pStart, off = 0; p < pEnd; ++p) { 1534 gs->atlasOff[p - pStart] += globalOff; 1535 if (neg) neg[p] = -(gs->atlasOff[p - pStart] + 1); 1536 } 1537 if (usePermutation && s->perm) PetscCall(ISRestoreIndices(s->perm, &pind)); 1538 /* Put in negative offsets for ghost points */ 1539 if (nroots >= 0) { 1540 PetscCall(PetscArrayzero(recv, nlocal)); 1541 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, recv, MPI_REPLACE)); 1542 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, recv, MPI_REPLACE)); 1543 for (p = pStart; p < pEnd; ++p) { 1544 if (recv[p] < 0) gs->atlasOff[p - pStart] = recv[p]; 1545 } 1546 } 1547 PetscCall(PetscFree2(neg, recv)); 1548 /* Set field dofs/offsets/constraints */ 1549 for (f = 0; f < numFields; ++f) { 1550 const char *name; 1551 1552 gs->field[f]->includesConstraints = includeConstraints; 1553 PetscCall(PetscSectionGetFieldComponents(s, f, &numComponents)); 1554 PetscCall(PetscSectionSetFieldComponents(gs, f, numComponents)); 1555 PetscCall(PetscSectionGetFieldName(s, f, &name)); 1556 PetscCall(PetscSectionSetFieldName(gs, f, name)); 1557 } 1558 for (p = pStart; p < pEnd; ++p) { 1559 PetscCall(PetscSectionGetOffset(gs, p, &off)); 1560 for (f = 0, foff = off; f < numFields; ++f) { 1561 PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof)); 1562 if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetFieldConstraintDof(gs, p, f, cdof)); 1563 PetscCall(PetscSectionGetFieldDof(s, p, f, &dof)); 1564 PetscCall(PetscSectionSetFieldDof(gs, p, f, off < 0 ? -(dof + 1) : dof)); 1565 PetscCall(PetscSectionSetFieldOffset(gs, p, f, foff)); 1566 PetscCall(PetscSectionGetFieldConstraintDof(gs, p, f, &cdof)); 1567 foff = off < 0 ? foff - (dof - cdof) : foff + (dof - cdof); 1568 } 1569 } 1570 for (f = 0; f < numFields; ++f) { 1571 PetscSection gfs = gs->field[f]; 1572 1573 PetscCall(PetscSectionSetUpBC(gfs)); 1574 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])); 1575 } 1576 gs->setup = PETSC_TRUE; 1577 PetscCall(PetscSectionViewFromOptions(gs, NULL, "-global_section_view")); 1578 *gsection = gs; 1579 PetscFunctionReturn(PETSC_SUCCESS); 1580 } 1581 1582 /*@ 1583 PetscSectionCreateGlobalSectionCensored - Create a `PetscSection` describing the globallayout using 1584 a local (sequential) `PetscSection` on each MPI process and an `PetscSF` describing the section point overlap. 1585 1586 Input Parameters: 1587 + s - The `PetscSection` for the local field layout 1588 . sf - The `PetscSF` describing parallel layout of the section points 1589 . includeConstraints - By default this is `PETSC_FALSE`, meaning that the global vector will not possess constrained dofs 1590 . numExcludes - The number of exclusion ranges, this must have the same value on all MPI processes 1591 - 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 1592 1593 Output Parameter: 1594 . gsection - The `PetscSection` for the global field layout 1595 1596 Level: advanced 1597 1598 Notes: 1599 On each MPI process `gsection` inherits the chart of the `s` on that process. 1600 1601 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`. 1602 In those locations the value of size is -(size+1) and the value of the offset on the remote process is -(off+1). 1603 1604 This routine augments `PetscSectionCreateGlobalSection()` by allowing one to exclude certain ranges in the chart of the `PetscSection` 1605 1606 Developer Notes: 1607 This is a terrible function name 1608 1609 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()` 1610 @*/ 1611 PetscErrorCode PetscSectionCreateGlobalSectionCensored(PetscSection s, PetscSF sf, PetscBool includeConstraints, PetscInt numExcludes, const PetscInt excludes[], PetscSection *gsection) 1612 { 1613 const PetscInt *pind = NULL; 1614 PetscInt *neg = NULL, *tmpOff = NULL; 1615 PetscInt pStart, pEnd, p, e, dof, cdof, off, globalOff = 0, nroots; 1616 1617 PetscFunctionBegin; 1618 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1619 PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2); 1620 PetscAssertPointer(gsection, 6); 1621 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), gsection)); 1622 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 1623 PetscCall(PetscSectionSetChart(*gsection, pStart, pEnd)); 1624 PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL)); 1625 if (nroots >= 0) { 1626 PetscCheck(nroots >= pEnd - pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PetscSF nroots %" PetscInt_FMT " < %" PetscInt_FMT " section size", nroots, pEnd - pStart); 1627 PetscCall(PetscCalloc1(nroots, &neg)); 1628 if (nroots > pEnd - pStart) { 1629 PetscCall(PetscCalloc1(nroots, &tmpOff)); 1630 } else { 1631 tmpOff = &(*gsection)->atlasDof[-pStart]; 1632 } 1633 } 1634 /* Mark ghost points with negative dof */ 1635 for (p = pStart; p < pEnd; ++p) { 1636 for (e = 0; e < numExcludes; ++e) { 1637 if ((p >= excludes[e * 2 + 0]) && (p < excludes[e * 2 + 1])) { 1638 PetscCall(PetscSectionSetDof(*gsection, p, 0)); 1639 break; 1640 } 1641 } 1642 if (e < numExcludes) continue; 1643 PetscCall(PetscSectionGetDof(s, p, &dof)); 1644 PetscCall(PetscSectionSetDof(*gsection, p, dof)); 1645 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 1646 if (!includeConstraints && cdof > 0) PetscCall(PetscSectionSetConstraintDof(*gsection, p, cdof)); 1647 if (neg) neg[p] = -(dof + 1); 1648 } 1649 PetscCall(PetscSectionSetUpBC(*gsection)); 1650 if (nroots >= 0) { 1651 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE)); 1652 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE)); 1653 if (nroots > pEnd - pStart) { 1654 for (p = pStart; p < pEnd; ++p) { 1655 if (tmpOff[p] < 0) (*gsection)->atlasDof[p - pStart] = tmpOff[p]; 1656 } 1657 } 1658 } 1659 /* Calculate new sizes, get process offset, and calculate point offsets */ 1660 if (s->perm) PetscCall(ISGetIndices(s->perm, &pind)); 1661 for (p = 0, off = 0; p < pEnd - pStart; ++p) { 1662 const PetscInt q = pind ? pind[p] : p; 1663 1664 cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[q] : 0; 1665 (*gsection)->atlasOff[q] = off; 1666 off += (*gsection)->atlasDof[q] > 0 ? (*gsection)->atlasDof[q] - cdof : 0; 1667 } 1668 PetscCallMPI(MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)s))); 1669 globalOff -= off; 1670 for (p = 0, off = 0; p < pEnd - pStart; ++p) { 1671 (*gsection)->atlasOff[p] += globalOff; 1672 if (neg) neg[p + pStart] = -((*gsection)->atlasOff[p] + 1); 1673 } 1674 if (s->perm) PetscCall(ISRestoreIndices(s->perm, &pind)); 1675 /* Put in negative offsets for ghost points */ 1676 if (nroots >= 0) { 1677 if (nroots == pEnd - pStart) tmpOff = &(*gsection)->atlasOff[-pStart]; 1678 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE)); 1679 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, neg, tmpOff, MPI_REPLACE)); 1680 if (nroots > pEnd - pStart) { 1681 for (p = pStart; p < pEnd; ++p) { 1682 if (tmpOff[p] < 0) (*gsection)->atlasOff[p - pStart] = tmpOff[p]; 1683 } 1684 } 1685 } 1686 if (nroots >= 0 && nroots > pEnd - pStart) PetscCall(PetscFree(tmpOff)); 1687 PetscCall(PetscFree(neg)); 1688 PetscFunctionReturn(PETSC_SUCCESS); 1689 } 1690 1691 /*@ 1692 PetscSectionGetPointLayout - Get a `PetscLayout` for the points with nonzero dof counts of the unnamed default field within this `PetscSection`s local chart 1693 1694 Collective 1695 1696 Input Parameters: 1697 + comm - The `MPI_Comm` 1698 - s - The `PetscSection` 1699 1700 Output Parameter: 1701 . layout - The point layout for the data that defines the section 1702 1703 Level: advanced 1704 1705 Notes: 1706 `PetscSectionGetValueLayout()` provides similar information but counting the total number of degrees of freedom on the MPI process (excluding constrained 1707 degrees of freedom). 1708 1709 This count includes constrained degrees of freedom 1710 1711 This is usually called on the default global section. 1712 1713 Example: 1714 .vb 1715 The chart is [2,5), point 2 has 2 dof, point 3 has 0 dof, point 4 has 1 dof 1716 The local size of the `PetscLayout` is 2 since 2 points have a non-zero number of dof 1717 .ve 1718 1719 Developer Notes: 1720 I find the names of these two functions extremely non-informative 1721 1722 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetValueLayout()`, `PetscSectionCreate()` 1723 @*/ 1724 PetscErrorCode PetscSectionGetPointLayout(MPI_Comm comm, PetscSection s, PetscLayout *layout) 1725 { 1726 PetscInt pStart, pEnd, p, localSize = 0; 1727 1728 PetscFunctionBegin; 1729 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 1730 for (p = pStart; p < pEnd; ++p) { 1731 PetscInt dof; 1732 1733 PetscCall(PetscSectionGetDof(s, p, &dof)); 1734 if (dof >= 0) ++localSize; 1735 } 1736 PetscCall(PetscLayoutCreate(comm, layout)); 1737 PetscCall(PetscLayoutSetLocalSize(*layout, localSize)); 1738 PetscCall(PetscLayoutSetBlockSize(*layout, 1)); 1739 PetscCall(PetscLayoutSetUp(*layout)); 1740 PetscFunctionReturn(PETSC_SUCCESS); 1741 } 1742 1743 /*@ 1744 PetscSectionGetValueLayout - Get the `PetscLayout` associated with the section dofs of a `PetscSection` 1745 1746 Collective 1747 1748 Input Parameters: 1749 + comm - The `MPI_Comm` 1750 - s - The `PetscSection` 1751 1752 Output Parameter: 1753 . layout - The dof layout for the section 1754 1755 Level: advanced 1756 1757 Notes: 1758 `PetscSectionGetPointLayout()` provides similar information but only counting the number of points with nonzero degrees of freedom and 1759 including the constrained degrees of freedom 1760 1761 This is usually called for the default global section. 1762 1763 Example: 1764 .vb 1765 The chart is [2,5), point 2 has 4 dof (2 constrained), point 3 has 0 dof, point 4 has 1 dof (not constrained) 1766 The local size of the `PetscLayout` is 3 since there are 3 unconstrained degrees of freedom on this MPI process 1767 .ve 1768 1769 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetPointLayout()`, `PetscSectionCreate()` 1770 @*/ 1771 PetscErrorCode PetscSectionGetValueLayout(MPI_Comm comm, PetscSection s, PetscLayout *layout) 1772 { 1773 PetscInt pStart, pEnd, p, localSize = 0; 1774 1775 PetscFunctionBegin; 1776 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2); 1777 PetscAssertPointer(layout, 3); 1778 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 1779 for (p = pStart; p < pEnd; ++p) { 1780 PetscInt dof, cdof; 1781 1782 PetscCall(PetscSectionGetDof(s, p, &dof)); 1783 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 1784 if (dof - cdof > 0) localSize += dof - cdof; 1785 } 1786 PetscCall(PetscLayoutCreate(comm, layout)); 1787 PetscCall(PetscLayoutSetLocalSize(*layout, localSize)); 1788 PetscCall(PetscLayoutSetBlockSize(*layout, 1)); 1789 PetscCall(PetscLayoutSetUp(*layout)); 1790 PetscFunctionReturn(PETSC_SUCCESS); 1791 } 1792 1793 /*@ 1794 PetscSectionGetOffset - Return the offset into an array or `Vec` for the dof associated with the given point. 1795 1796 Not Collective 1797 1798 Input Parameters: 1799 + s - the `PetscSection` 1800 - point - the point 1801 1802 Output Parameter: 1803 . offset - the offset 1804 1805 Level: intermediate 1806 1807 Notes: 1808 In a global section, `offset` will be negative for points not owned by this process. 1809 1810 This is for the unnamed default field in the `PetscSection` not the named fields 1811 1812 The `offset` values are different depending on a value set with `PetscSectionSetPointMajor()` 1813 1814 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionCreate()`, `PetscSectionSetPointMajor()` 1815 @*/ 1816 PetscErrorCode PetscSectionGetOffset(PetscSection s, PetscInt point, PetscInt *offset) 1817 { 1818 PetscFunctionBegin; 1819 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1820 PetscAssertPointer(offset, 3); 1821 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); 1822 *offset = s->atlasOff[point - s->pStart]; 1823 PetscFunctionReturn(PETSC_SUCCESS); 1824 } 1825 1826 /*@ 1827 PetscSectionSetOffset - Set the offset into an array or `Vec` for the dof associated with the given point. 1828 1829 Not Collective 1830 1831 Input Parameters: 1832 + s - the `PetscSection` 1833 . point - the point 1834 - offset - the offset, these values may be negative indicating the values are off process 1835 1836 Level: developer 1837 1838 Note: 1839 The user usually does not call this function, but uses `PetscSectionSetUp()` 1840 1841 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionCreate()`, `PetscSectionSetUp()` 1842 @*/ 1843 PetscErrorCode PetscSectionSetOffset(PetscSection s, PetscInt point, PetscInt offset) 1844 { 1845 PetscFunctionBegin; 1846 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1847 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); 1848 s->atlasOff[point - s->pStart] = offset; 1849 PetscFunctionReturn(PETSC_SUCCESS); 1850 } 1851 1852 /*@ 1853 PetscSectionGetFieldOffset - Return the offset into an array or `Vec` for the field dof associated with the given point. 1854 1855 Not Collective 1856 1857 Input Parameters: 1858 + s - the `PetscSection` 1859 . point - the point 1860 - field - the field 1861 1862 Output Parameter: 1863 . offset - the offset 1864 1865 Level: intermediate 1866 1867 Notes: 1868 In a global section, `offset` will be negative for points not owned by this process. 1869 1870 The `offset` values are different depending on a value set with `PetscSectionSetPointMajor()` 1871 1872 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()`, `PetscSectionGetFieldPointOffset()` 1873 @*/ 1874 PetscErrorCode PetscSectionGetFieldOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt *offset) 1875 { 1876 PetscFunctionBegin; 1877 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1878 PetscAssertPointer(offset, 4); 1879 PetscSectionCheckValidField(field, s->numFields); 1880 PetscCall(PetscSectionGetOffset(s->field[field], point, offset)); 1881 PetscFunctionReturn(PETSC_SUCCESS); 1882 } 1883 1884 /*@ 1885 PetscSectionSetFieldOffset - Set the offset into an array or `Vec` for the dof associated with the given field at a point. 1886 1887 Not Collective 1888 1889 Input Parameters: 1890 + s - the `PetscSection` 1891 . point - the point 1892 . field - the field 1893 - offset - the offset, these values may be negative indicating the values are off process 1894 1895 Level: developer 1896 1897 Note: 1898 The user usually does not call this function, but uses `PetscSectionSetUp()` 1899 1900 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetFieldOffset()`, `PetscSectionSetOffset()`, `PetscSectionCreate()`, `PetscSectionSetUp()` 1901 @*/ 1902 PetscErrorCode PetscSectionSetFieldOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt offset) 1903 { 1904 PetscFunctionBegin; 1905 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1906 PetscSectionCheckValidField(field, s->numFields); 1907 PetscCall(PetscSectionSetOffset(s->field[field], point, offset)); 1908 PetscFunctionReturn(PETSC_SUCCESS); 1909 } 1910 1911 /*@ 1912 PetscSectionGetFieldPointOffset - Return the offset for the first field dof associated with the given point relative to the offset for that point for the 1913 unnamed default field's first dof 1914 1915 Not Collective 1916 1917 Input Parameters: 1918 + s - the `PetscSection` 1919 . point - the point 1920 - field - the field 1921 1922 Output Parameter: 1923 . offset - the offset 1924 1925 Level: advanced 1926 1927 Note: 1928 This ignores constraints 1929 1930 Example: 1931 .vb 1932 if PetscSectionSetPointMajor(s,PETSC_TRUE) 1933 The unnamed default field has 3 dof at `point` 1934 Field 0 has 2 dof at `point` 1935 Then PetscSectionGetFieldPointOffset(s,point,1,&offset) returns and offset of 5 1936 .ve 1937 1938 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()`, `PetscSectionGetFieldOffset()` 1939 @*/ 1940 PetscErrorCode PetscSectionGetFieldPointOffset(PetscSection s, PetscInt point, PetscInt field, PetscInt *offset) 1941 { 1942 PetscInt off, foff; 1943 1944 PetscFunctionBegin; 1945 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1946 PetscAssertPointer(offset, 4); 1947 PetscSectionCheckValidField(field, s->numFields); 1948 PetscCall(PetscSectionGetOffset(s, point, &off)); 1949 PetscCall(PetscSectionGetOffset(s->field[field], point, &foff)); 1950 *offset = foff - off; 1951 PetscFunctionReturn(PETSC_SUCCESS); 1952 } 1953 1954 /*@ 1955 PetscSectionGetOffsetRange - Return the full range of offsets [`start`, `end`) for a `PetscSection` 1956 1957 Not Collective 1958 1959 Input Parameter: 1960 . s - the `PetscSection` 1961 1962 Output Parameters: 1963 + start - the minimum offset 1964 - end - one more than the maximum offset 1965 1966 Level: intermediate 1967 1968 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetOffset()`, `PetscSectionCreate()` 1969 @*/ 1970 PetscErrorCode PetscSectionGetOffsetRange(PetscSection s, PetscInt *start, PetscInt *end) 1971 { 1972 PetscInt os = 0, oe = 0, pStart, pEnd, p; 1973 1974 PetscFunctionBegin; 1975 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 1976 if (s->atlasOff) { 1977 os = s->atlasOff[0]; 1978 oe = s->atlasOff[0]; 1979 } 1980 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 1981 for (p = 0; p < pEnd - pStart; ++p) { 1982 PetscInt dof = s->atlasDof[p], off = s->atlasOff[p]; 1983 1984 if (off >= 0) { 1985 os = PetscMin(os, off); 1986 oe = PetscMax(oe, off + dof); 1987 } 1988 } 1989 if (start) *start = os; 1990 if (end) *end = oe; 1991 PetscFunctionReturn(PETSC_SUCCESS); 1992 } 1993 1994 /*@ 1995 PetscSectionCreateSubsection - Create a new, smaller `PetscSection` composed of only selected fields 1996 1997 Collective 1998 1999 Input Parameters: 2000 + s - the `PetscSection` 2001 . len - the number of subfields 2002 - fields - the subfield numbers 2003 2004 Output Parameter: 2005 . subs - the subsection 2006 2007 Level: advanced 2008 2009 Notes: 2010 The chart of `subs` is the same as the chart of `s` 2011 2012 This will error if a fieldnumber is out of range 2013 2014 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreateSupersection()`, `PetscSectionCreate()` 2015 @*/ 2016 PetscErrorCode PetscSectionCreateSubsection(PetscSection s, PetscInt len, const PetscInt fields[], PetscSection *subs) 2017 { 2018 PetscInt nF, f, c, pStart, pEnd, p, maxCdof = 0; 2019 2020 PetscFunctionBegin; 2021 if (!len) PetscFunctionReturn(PETSC_SUCCESS); 2022 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2023 PetscAssertPointer(fields, 3); 2024 PetscAssertPointer(subs, 4); 2025 PetscCall(PetscSectionGetNumFields(s, &nF)); 2026 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); 2027 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), subs)); 2028 PetscCall(PetscSectionSetNumFields(*subs, len)); 2029 for (f = 0; f < len; ++f) { 2030 const char *name = NULL; 2031 PetscInt numComp = 0; 2032 PetscSectionSym sym; 2033 2034 PetscCall(PetscSectionGetFieldName(s, fields[f], &name)); 2035 PetscCall(PetscSectionSetFieldName(*subs, f, name)); 2036 PetscCall(PetscSectionGetFieldComponents(s, fields[f], &numComp)); 2037 PetscCall(PetscSectionSetFieldComponents(*subs, f, numComp)); 2038 for (c = 0; c < s->numFieldComponents[fields[f]]; ++c) { 2039 PetscCall(PetscSectionGetComponentName(s, fields[f], c, &name)); 2040 PetscCall(PetscSectionSetComponentName(*subs, f, c, name)); 2041 } 2042 PetscCall(PetscSectionGetFieldSym(s, fields[f], &sym)); 2043 PetscCall(PetscSectionSetFieldSym(*subs, f, sym)); 2044 } 2045 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 2046 PetscCall(PetscSectionSetChart(*subs, pStart, pEnd)); 2047 for (p = pStart; p < pEnd; ++p) { 2048 PetscInt dof = 0, cdof = 0, fdof = 0, cfdof = 0; 2049 2050 for (f = 0; f < len; ++f) { 2051 PetscCall(PetscSectionGetFieldDof(s, p, fields[f], &fdof)); 2052 PetscCall(PetscSectionSetFieldDof(*subs, p, f, fdof)); 2053 PetscCall(PetscSectionGetFieldConstraintDof(s, p, fields[f], &cfdof)); 2054 if (cfdof) PetscCall(PetscSectionSetFieldConstraintDof(*subs, p, f, cfdof)); 2055 dof += fdof; 2056 cdof += cfdof; 2057 } 2058 PetscCall(PetscSectionSetDof(*subs, p, dof)); 2059 if (cdof) PetscCall(PetscSectionSetConstraintDof(*subs, p, cdof)); 2060 maxCdof = PetscMax(cdof, maxCdof); 2061 } 2062 PetscCall(PetscSectionSetUp(*subs)); 2063 if (maxCdof) { 2064 PetscInt *indices; 2065 2066 PetscCall(PetscMalloc1(maxCdof, &indices)); 2067 for (p = pStart; p < pEnd; ++p) { 2068 PetscInt cdof; 2069 2070 PetscCall(PetscSectionGetConstraintDof(*subs, p, &cdof)); 2071 if (cdof) { 2072 const PetscInt *oldIndices = NULL; 2073 PetscInt fdof = 0, cfdof = 0, fc, numConst = 0, fOff = 0; 2074 2075 for (f = 0; f < len; ++f) { 2076 PetscCall(PetscSectionGetFieldDof(s, p, fields[f], &fdof)); 2077 PetscCall(PetscSectionGetFieldConstraintDof(s, p, fields[f], &cfdof)); 2078 PetscCall(PetscSectionGetFieldConstraintIndices(s, p, fields[f], &oldIndices)); 2079 PetscCall(PetscSectionSetFieldConstraintIndices(*subs, p, f, oldIndices)); 2080 for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] = oldIndices[fc] + fOff; 2081 numConst += cfdof; 2082 fOff += fdof; 2083 } 2084 PetscCall(PetscSectionSetConstraintIndices(*subs, p, indices)); 2085 } 2086 } 2087 PetscCall(PetscFree(indices)); 2088 } 2089 PetscFunctionReturn(PETSC_SUCCESS); 2090 } 2091 2092 /*@ 2093 PetscSectionCreateComponentSubsection - Create a new, smaller `PetscSection` composed of only selected components 2094 2095 Collective 2096 2097 Input Parameters: 2098 + s - the `PetscSection` 2099 . len - the number of components 2100 - comps - the component numbers 2101 2102 Output Parameter: 2103 . subs - the subsection 2104 2105 Level: advanced 2106 2107 Notes: 2108 The chart of `subs` is the same as the chart of `s` 2109 2110 This will error if the section has more than one field, or if a component number is out of range 2111 2112 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreateSupersection()`, `PetscSectionCreate()` 2113 @*/ 2114 PetscErrorCode PetscSectionCreateComponentSubsection(PetscSection s, PetscInt len, const PetscInt comps[], PetscSection *subs) 2115 { 2116 PetscSectionSym sym; 2117 const char *name = NULL; 2118 PetscInt Nf, pStart, pEnd; 2119 2120 PetscFunctionBegin; 2121 if (!len) PetscFunctionReturn(PETSC_SUCCESS); 2122 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2123 PetscAssertPointer(comps, 3); 2124 PetscAssertPointer(subs, 4); 2125 PetscCall(PetscSectionGetNumFields(s, &Nf)); 2126 PetscCheck(Nf == 1, PetscObjectComm((PetscObject)s), PETSC_ERR_ARG_WRONG, "This method can only handle one field, not %" PetscInt_FMT, Nf); 2127 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), subs)); 2128 PetscCall(PetscSectionSetNumFields(*subs, 1)); 2129 PetscCall(PetscSectionGetFieldName(s, 0, &name)); 2130 PetscCall(PetscSectionSetFieldName(*subs, 0, name)); 2131 PetscCall(PetscSectionSetFieldComponents(*subs, 0, len)); 2132 PetscCall(PetscSectionGetFieldSym(s, 0, &sym)); 2133 PetscCall(PetscSectionSetFieldSym(*subs, 0, sym)); 2134 for (PetscInt c = 0; c < len; ++c) { 2135 PetscCall(PetscSectionGetComponentName(s, 0, comps[c], &name)); 2136 PetscCall(PetscSectionSetComponentName(*subs, 0, c, name)); 2137 } 2138 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 2139 PetscCall(PetscSectionSetChart(*subs, pStart, pEnd)); 2140 for (PetscInt p = pStart; p < pEnd; ++p) { 2141 PetscInt dof, cdof, cfdof; 2142 2143 PetscCall(PetscSectionGetDof(s, p, &dof)); 2144 if (!dof) continue; 2145 PetscCall(PetscSectionGetFieldConstraintDof(s, p, 0, &cfdof)); 2146 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 2147 PetscCheck(!cdof && !cfdof, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Component selection does not work with constraints"); 2148 PetscCall(PetscSectionSetFieldDof(*subs, p, 0, len)); 2149 PetscCall(PetscSectionSetDof(*subs, p, len)); 2150 } 2151 PetscCall(PetscSectionSetUp(*subs)); 2152 PetscFunctionReturn(PETSC_SUCCESS); 2153 } 2154 2155 /*@ 2156 PetscSectionCreateSupersection - Create a new, larger section composed of multiple `PetscSection`s 2157 2158 Collective 2159 2160 Input Parameters: 2161 + s - the input sections 2162 - len - the number of input sections 2163 2164 Output Parameter: 2165 . supers - the supersection 2166 2167 Level: advanced 2168 2169 Notes: 2170 The section offsets now refer to a new, larger vector. 2171 2172 Developer Notes: 2173 Needs to explain how the sections are composed 2174 2175 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreateSubsection()`, `PetscSectionCreate()` 2176 @*/ 2177 PetscErrorCode PetscSectionCreateSupersection(PetscSection s[], PetscInt len, PetscSection *supers) 2178 { 2179 PetscInt Nf = 0, f, pStart = PETSC_MAX_INT, pEnd = 0, p, maxCdof = 0, i; 2180 2181 PetscFunctionBegin; 2182 if (!len) PetscFunctionReturn(PETSC_SUCCESS); 2183 for (i = 0; i < len; ++i) { 2184 PetscInt nf, pStarti, pEndi; 2185 2186 PetscCall(PetscSectionGetNumFields(s[i], &nf)); 2187 PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi)); 2188 pStart = PetscMin(pStart, pStarti); 2189 pEnd = PetscMax(pEnd, pEndi); 2190 Nf += nf; 2191 } 2192 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s[0]), supers)); 2193 PetscCall(PetscSectionSetNumFields(*supers, Nf)); 2194 for (i = 0, f = 0; i < len; ++i) { 2195 PetscInt nf, fi, ci; 2196 2197 PetscCall(PetscSectionGetNumFields(s[i], &nf)); 2198 for (fi = 0; fi < nf; ++fi, ++f) { 2199 const char *name = NULL; 2200 PetscInt numComp = 0; 2201 2202 PetscCall(PetscSectionGetFieldName(s[i], fi, &name)); 2203 PetscCall(PetscSectionSetFieldName(*supers, f, name)); 2204 PetscCall(PetscSectionGetFieldComponents(s[i], fi, &numComp)); 2205 PetscCall(PetscSectionSetFieldComponents(*supers, f, numComp)); 2206 for (ci = 0; ci < s[i]->numFieldComponents[fi]; ++ci) { 2207 PetscCall(PetscSectionGetComponentName(s[i], fi, ci, &name)); 2208 PetscCall(PetscSectionSetComponentName(*supers, f, ci, name)); 2209 } 2210 } 2211 } 2212 PetscCall(PetscSectionSetChart(*supers, pStart, pEnd)); 2213 for (p = pStart; p < pEnd; ++p) { 2214 PetscInt dof = 0, cdof = 0; 2215 2216 for (i = 0, f = 0; i < len; ++i) { 2217 PetscInt nf, fi, pStarti, pEndi; 2218 PetscInt fdof = 0, cfdof = 0; 2219 2220 PetscCall(PetscSectionGetNumFields(s[i], &nf)); 2221 PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi)); 2222 if ((p < pStarti) || (p >= pEndi)) continue; 2223 for (fi = 0; fi < nf; ++fi, ++f) { 2224 PetscCall(PetscSectionGetFieldDof(s[i], p, fi, &fdof)); 2225 PetscCall(PetscSectionAddFieldDof(*supers, p, f, fdof)); 2226 PetscCall(PetscSectionGetFieldConstraintDof(s[i], p, fi, &cfdof)); 2227 if (cfdof) PetscCall(PetscSectionAddFieldConstraintDof(*supers, p, f, cfdof)); 2228 dof += fdof; 2229 cdof += cfdof; 2230 } 2231 } 2232 PetscCall(PetscSectionSetDof(*supers, p, dof)); 2233 if (cdof) PetscCall(PetscSectionSetConstraintDof(*supers, p, cdof)); 2234 maxCdof = PetscMax(cdof, maxCdof); 2235 } 2236 PetscCall(PetscSectionSetUp(*supers)); 2237 if (maxCdof) { 2238 PetscInt *indices; 2239 2240 PetscCall(PetscMalloc1(maxCdof, &indices)); 2241 for (p = pStart; p < pEnd; ++p) { 2242 PetscInt cdof; 2243 2244 PetscCall(PetscSectionGetConstraintDof(*supers, p, &cdof)); 2245 if (cdof) { 2246 PetscInt dof, numConst = 0, fOff = 0; 2247 2248 for (i = 0, f = 0; i < len; ++i) { 2249 const PetscInt *oldIndices = NULL; 2250 PetscInt nf, fi, pStarti, pEndi, fdof, cfdof, fc; 2251 2252 PetscCall(PetscSectionGetNumFields(s[i], &nf)); 2253 PetscCall(PetscSectionGetChart(s[i], &pStarti, &pEndi)); 2254 if ((p < pStarti) || (p >= pEndi)) continue; 2255 for (fi = 0; fi < nf; ++fi, ++f) { 2256 PetscCall(PetscSectionGetFieldDof(s[i], p, fi, &fdof)); 2257 PetscCall(PetscSectionGetFieldConstraintDof(s[i], p, fi, &cfdof)); 2258 PetscCall(PetscSectionGetFieldConstraintIndices(s[i], p, fi, &oldIndices)); 2259 for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] = oldIndices[fc]; 2260 PetscCall(PetscSectionSetFieldConstraintIndices(*supers, p, f, &indices[numConst])); 2261 for (fc = 0; fc < cfdof; ++fc) indices[numConst + fc] += fOff; 2262 numConst += cfdof; 2263 } 2264 PetscCall(PetscSectionGetDof(s[i], p, &dof)); 2265 fOff += dof; 2266 } 2267 PetscCall(PetscSectionSetConstraintIndices(*supers, p, indices)); 2268 } 2269 } 2270 PetscCall(PetscFree(indices)); 2271 } 2272 PetscFunctionReturn(PETSC_SUCCESS); 2273 } 2274 2275 static PetscErrorCode PetscSectionCreateSubplexSection_Private(PetscSection s, IS subpointMap, PetscBool renumberPoints, PetscSection *subs) 2276 { 2277 const PetscInt *points = NULL, *indices = NULL; 2278 PetscInt numFields, f, c, numSubpoints = 0, pStart, pEnd, p, spStart, spEnd, subp; 2279 2280 PetscFunctionBegin; 2281 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2282 PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2); 2283 PetscAssertPointer(subs, 4); 2284 PetscCall(PetscSectionGetNumFields(s, &numFields)); 2285 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), subs)); 2286 if (numFields) PetscCall(PetscSectionSetNumFields(*subs, numFields)); 2287 for (f = 0; f < numFields; ++f) { 2288 const char *name = NULL; 2289 PetscInt numComp = 0; 2290 2291 PetscCall(PetscSectionGetFieldName(s, f, &name)); 2292 PetscCall(PetscSectionSetFieldName(*subs, f, name)); 2293 PetscCall(PetscSectionGetFieldComponents(s, f, &numComp)); 2294 PetscCall(PetscSectionSetFieldComponents(*subs, f, numComp)); 2295 for (c = 0; c < s->numFieldComponents[f]; ++c) { 2296 PetscCall(PetscSectionGetComponentName(s, f, c, &name)); 2297 PetscCall(PetscSectionSetComponentName(*subs, f, c, name)); 2298 } 2299 } 2300 /* For right now, we do not try to squeeze the subchart */ 2301 if (subpointMap) { 2302 PetscCall(ISGetSize(subpointMap, &numSubpoints)); 2303 PetscCall(ISGetIndices(subpointMap, &points)); 2304 } 2305 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 2306 if (renumberPoints) { 2307 spStart = 0; 2308 spEnd = numSubpoints; 2309 } else { 2310 PetscCall(ISGetMinMax(subpointMap, &spStart, &spEnd)); 2311 ++spEnd; 2312 } 2313 PetscCall(PetscSectionSetChart(*subs, spStart, spEnd)); 2314 for (p = pStart; p < pEnd; ++p) { 2315 PetscInt dof, cdof, fdof = 0, cfdof = 0; 2316 2317 PetscCall(PetscFindInt(p, numSubpoints, points, &subp)); 2318 if (subp < 0) continue; 2319 if (!renumberPoints) subp = p; 2320 for (f = 0; f < numFields; ++f) { 2321 PetscCall(PetscSectionGetFieldDof(s, p, f, &fdof)); 2322 PetscCall(PetscSectionSetFieldDof(*subs, subp, f, fdof)); 2323 PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cfdof)); 2324 if (cfdof) PetscCall(PetscSectionSetFieldConstraintDof(*subs, subp, f, cfdof)); 2325 } 2326 PetscCall(PetscSectionGetDof(s, p, &dof)); 2327 PetscCall(PetscSectionSetDof(*subs, subp, dof)); 2328 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 2329 if (cdof) PetscCall(PetscSectionSetConstraintDof(*subs, subp, cdof)); 2330 } 2331 PetscCall(PetscSectionSetUp(*subs)); 2332 /* Change offsets to original offsets */ 2333 for (p = pStart; p < pEnd; ++p) { 2334 PetscInt off, foff = 0; 2335 2336 PetscCall(PetscFindInt(p, numSubpoints, points, &subp)); 2337 if (subp < 0) continue; 2338 if (!renumberPoints) subp = p; 2339 for (f = 0; f < numFields; ++f) { 2340 PetscCall(PetscSectionGetFieldOffset(s, p, f, &foff)); 2341 PetscCall(PetscSectionSetFieldOffset(*subs, subp, f, foff)); 2342 } 2343 PetscCall(PetscSectionGetOffset(s, p, &off)); 2344 PetscCall(PetscSectionSetOffset(*subs, subp, off)); 2345 } 2346 /* Copy constraint indices */ 2347 for (subp = spStart; subp < spEnd; ++subp) { 2348 PetscInt cdof; 2349 2350 PetscCall(PetscSectionGetConstraintDof(*subs, subp, &cdof)); 2351 if (cdof) { 2352 for (f = 0; f < numFields; ++f) { 2353 PetscCall(PetscSectionGetFieldConstraintIndices(s, points[subp - spStart], f, &indices)); 2354 PetscCall(PetscSectionSetFieldConstraintIndices(*subs, subp, f, indices)); 2355 } 2356 PetscCall(PetscSectionGetConstraintIndices(s, points[subp - spStart], &indices)); 2357 PetscCall(PetscSectionSetConstraintIndices(*subs, subp, indices)); 2358 } 2359 } 2360 if (subpointMap) PetscCall(ISRestoreIndices(subpointMap, &points)); 2361 PetscFunctionReturn(PETSC_SUCCESS); 2362 } 2363 2364 /*@ 2365 PetscSectionCreateSubmeshSection - Create a new, smaller section with support on the submesh 2366 2367 Collective 2368 2369 Input Parameters: 2370 + s - the `PetscSection` 2371 - subpointMap - a sorted list of points in the original mesh which are in the submesh 2372 2373 Output Parameter: 2374 . subs - the subsection 2375 2376 Level: advanced 2377 2378 Notes: 2379 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))` 2380 2381 Compare this with `PetscSectionCreateSubdomainSection()` that does not map the points numbers to start at zero but leaves them as before 2382 2383 Developer Notes: 2384 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` 2385 2386 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreateSubdomainSection()`, `PetscSectionCreateSubsection()`, `DMPlexGetSubpointMap()`, `PetscSectionCreate()` 2387 @*/ 2388 PetscErrorCode PetscSectionCreateSubmeshSection(PetscSection s, IS subpointMap, PetscSection *subs) 2389 { 2390 PetscFunctionBegin; 2391 PetscCall(PetscSectionCreateSubplexSection_Private(s, subpointMap, PETSC_TRUE, subs)); 2392 PetscFunctionReturn(PETSC_SUCCESS); 2393 } 2394 2395 /*@ 2396 PetscSectionCreateSubdomainSection - Create a new, smaller section with support on a subdomain of the mesh 2397 2398 Collective 2399 2400 Input Parameters: 2401 + s - the `PetscSection` 2402 - subpointMap - a sorted list of points in the original mesh which are in the subdomain 2403 2404 Output Parameter: 2405 . subs - the subsection 2406 2407 Level: advanced 2408 2409 Notes: 2410 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` 2411 is `[min(subpointMap),max(subpointMap)+1)` 2412 2413 Compare this with `PetscSectionCreateSubmeshSection()` that maps the point numbers to start at zero 2414 2415 Developer Notes: 2416 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` 2417 2418 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreateSubmeshSection()`, `PetscSectionCreateSubsection()`, `DMPlexGetSubpointMap()`, `PetscSectionCreate()` 2419 @*/ 2420 PetscErrorCode PetscSectionCreateSubdomainSection(PetscSection s, IS subpointMap, PetscSection *subs) 2421 { 2422 PetscFunctionBegin; 2423 PetscCall(PetscSectionCreateSubplexSection_Private(s, subpointMap, PETSC_FALSE, subs)); 2424 PetscFunctionReturn(PETSC_SUCCESS); 2425 } 2426 2427 static PetscErrorCode PetscSectionView_ASCII(PetscSection s, PetscViewer viewer) 2428 { 2429 PetscInt p; 2430 PetscMPIInt rank; 2431 2432 PetscFunctionBegin; 2433 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 2434 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 2435 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "Process %d:\n", rank)); 2436 for (p = 0; p < s->pEnd - s->pStart; ++p) { 2437 if (s->bc && s->bc->atlasDof[p] > 0) { 2438 PetscInt b; 2439 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT " constrained", p + s->pStart, s->atlasDof[p], s->atlasOff[p])); 2440 if (s->bcIndices) { 2441 for (b = 0; b < s->bc->atlasDof[p]; ++b) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " %" PetscInt_FMT, s->bcIndices[s->bc->atlasOff[p] + b])); 2442 } 2443 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "\n")); 2444 } else { 2445 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, " (%4" PetscInt_FMT ") dim %2" PetscInt_FMT " offset %3" PetscInt_FMT "\n", p + s->pStart, s->atlasDof[p], s->atlasOff[p])); 2446 } 2447 } 2448 PetscCall(PetscViewerFlush(viewer)); 2449 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 2450 if (s->sym) { 2451 PetscCall(PetscViewerASCIIPushTab(viewer)); 2452 PetscCall(PetscSectionSymView(s->sym, viewer)); 2453 PetscCall(PetscViewerASCIIPopTab(viewer)); 2454 } 2455 PetscFunctionReturn(PETSC_SUCCESS); 2456 } 2457 2458 /*@ 2459 PetscSectionViewFromOptions - View the `PetscSection` based on values in the options database 2460 2461 Collective 2462 2463 Input Parameters: 2464 + A - the `PetscSection` object to view 2465 . obj - Optional object that provides the options prefix used for the options 2466 - name - command line option 2467 2468 Level: intermediate 2469 2470 Note: 2471 See `PetscObjectViewFromOptions()` for available values of `PetscViewer` and `PetscViewerFormat` 2472 2473 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionView`, `PetscObjectViewFromOptions()`, `PetscSectionCreate()`, `PetscSectionView()` 2474 @*/ 2475 PetscErrorCode PetscSectionViewFromOptions(PetscSection A, PetscObject obj, const char name[]) 2476 { 2477 PetscFunctionBegin; 2478 PetscValidHeaderSpecific(A, PETSC_SECTION_CLASSID, 1); 2479 PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name)); 2480 PetscFunctionReturn(PETSC_SUCCESS); 2481 } 2482 2483 /*@ 2484 PetscSectionView - Views a `PetscSection` 2485 2486 Collective 2487 2488 Input Parameters: 2489 + s - the `PetscSection` object to view 2490 - viewer - the viewer 2491 2492 Level: beginner 2493 2494 Note: 2495 `PetscSectionView()`, when viewer is of type `PETSCVIEWERHDF5`, only saves 2496 distribution independent data, such as dofs, offsets, constraint dofs, 2497 and constraint indices. Points that have negative dofs, for instance, 2498 are not saved as they represent points owned by other processes. 2499 Point numbering and rank assignment is currently not stored. 2500 The saved section can be loaded with `PetscSectionLoad()`. 2501 2502 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`, `PetscSectionLoad()`, `PetscViewer` 2503 @*/ 2504 PetscErrorCode PetscSectionView(PetscSection s, PetscViewer viewer) 2505 { 2506 PetscBool isascii, ishdf5; 2507 PetscInt f; 2508 2509 PetscFunctionBegin; 2510 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2511 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)s), &viewer)); 2512 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2513 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 2514 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2515 if (isascii) { 2516 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)s, viewer)); 2517 if (s->numFields) { 2518 PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " fields\n", s->numFields)); 2519 for (f = 0; f < s->numFields; ++f) { 2520 PetscCall(PetscViewerASCIIPrintf(viewer, " field %" PetscInt_FMT " \"%s\" with %" PetscInt_FMT " components\n", f, s->fieldNames[f], s->numFieldComponents[f])); 2521 PetscCall(PetscSectionView_ASCII(s->field[f], viewer)); 2522 } 2523 } else { 2524 PetscCall(PetscSectionView_ASCII(s, viewer)); 2525 } 2526 } else if (ishdf5) { 2527 #if PetscDefined(HAVE_HDF5) 2528 PetscCall(PetscSectionView_HDF5_Internal(s, viewer)); 2529 #else 2530 SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2531 #endif 2532 } 2533 PetscFunctionReturn(PETSC_SUCCESS); 2534 } 2535 2536 /*@ 2537 PetscSectionLoad - Loads a `PetscSection` 2538 2539 Collective 2540 2541 Input Parameters: 2542 + s - the `PetscSection` object to load 2543 - viewer - the viewer 2544 2545 Level: beginner 2546 2547 Note: 2548 `PetscSectionLoad()`, when viewer is of type `PETSCVIEWERHDF5`, loads 2549 a section saved with `PetscSectionView()`. The number of processes 2550 used here (N) does not need to be the same as that used when saving. 2551 After calling this function, the chart of s on rank i will be set 2552 to [0, E_i), where \sum_{i=0}^{N-1}E_i equals to the total number of 2553 saved section points. 2554 2555 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionDestroy()`, `PetscSectionView()` 2556 @*/ 2557 PetscErrorCode PetscSectionLoad(PetscSection s, PetscViewer viewer) 2558 { 2559 PetscBool ishdf5; 2560 2561 PetscFunctionBegin; 2562 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2563 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 2564 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 2565 if (ishdf5) { 2566 #if PetscDefined(HAVE_HDF5) 2567 PetscCall(PetscSectionLoad_HDF5_Internal(s, viewer)); 2568 PetscFunctionReturn(PETSC_SUCCESS); 2569 #else 2570 SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 2571 #endif 2572 } else SETERRQ(PetscObjectComm((PetscObject)s), PETSC_ERR_SUP, "Viewer type %s not yet supported for PetscSection loading", ((PetscObject)viewer)->type_name); 2573 } 2574 2575 /*@ 2576 PetscSectionResetClosurePermutation - Remove any existing closure permutation 2577 2578 Input Parameter: 2579 . section - The `PetscSection` 2580 2581 Level: intermediate 2582 2583 .seealso: `PetscSectionSetClosurePermutation()`, `PetscSectionSetClosureIndex()`, `PetscSectionReset()` 2584 @*/ 2585 PetscErrorCode PetscSectionResetClosurePermutation(PetscSection section) 2586 { 2587 PetscSectionClosurePermVal clVal; 2588 2589 PetscFunctionBegin; 2590 if (!section->clHash) PetscFunctionReturn(PETSC_SUCCESS); 2591 kh_foreach_value(section->clHash, clVal, { 2592 PetscCall(PetscFree(clVal.perm)); 2593 PetscCall(PetscFree(clVal.invPerm)); 2594 }); 2595 kh_destroy(ClPerm, section->clHash); 2596 section->clHash = NULL; 2597 PetscFunctionReturn(PETSC_SUCCESS); 2598 } 2599 2600 /*@ 2601 PetscSectionReset - Frees all section data, the section is then as if `PetscSectionCreate()` had just been called. 2602 2603 Not Collective 2604 2605 Input Parameter: 2606 . s - the `PetscSection` 2607 2608 Level: beginner 2609 2610 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()` 2611 @*/ 2612 PetscErrorCode PetscSectionReset(PetscSection s) 2613 { 2614 PetscInt f, c; 2615 2616 PetscFunctionBegin; 2617 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2618 for (f = 0; f < s->numFields; ++f) { 2619 PetscCall(PetscSectionDestroy(&s->field[f])); 2620 PetscCall(PetscFree(s->fieldNames[f])); 2621 for (c = 0; c < s->numFieldComponents[f]; ++c) PetscCall(PetscFree(s->compNames[f][c])); 2622 PetscCall(PetscFree(s->compNames[f])); 2623 } 2624 PetscCall(PetscFree(s->numFieldComponents)); 2625 PetscCall(PetscFree(s->fieldNames)); 2626 PetscCall(PetscFree(s->compNames)); 2627 PetscCall(PetscFree(s->field)); 2628 PetscCall(PetscSectionDestroy(&s->bc)); 2629 PetscCall(PetscFree(s->bcIndices)); 2630 PetscCall(PetscFree2(s->atlasDof, s->atlasOff)); 2631 PetscCall(PetscSectionDestroy(&s->clSection)); 2632 PetscCall(ISDestroy(&s->clPoints)); 2633 PetscCall(ISDestroy(&s->perm)); 2634 PetscCall(PetscBTDestroy(&s->blockStarts)); 2635 PetscCall(PetscSectionResetClosurePermutation(s)); 2636 PetscCall(PetscSectionSymDestroy(&s->sym)); 2637 PetscCall(PetscSectionDestroy(&s->clSection)); 2638 PetscCall(ISDestroy(&s->clPoints)); 2639 PetscCall(PetscSectionInvalidateMaxDof_Internal(s)); 2640 s->pStart = -1; 2641 s->pEnd = -1; 2642 s->maxDof = 0; 2643 s->setup = PETSC_FALSE; 2644 s->numFields = 0; 2645 s->clObj = NULL; 2646 PetscFunctionReturn(PETSC_SUCCESS); 2647 } 2648 2649 /*@ 2650 PetscSectionDestroy - Frees a `PetscSection` 2651 2652 Not Collective 2653 2654 Input Parameter: 2655 . s - the `PetscSection` 2656 2657 Level: beginner 2658 2659 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionCreate()`, `PetscSectionReset()` 2660 @*/ 2661 PetscErrorCode PetscSectionDestroy(PetscSection *s) 2662 { 2663 PetscFunctionBegin; 2664 if (!*s) PetscFunctionReturn(PETSC_SUCCESS); 2665 PetscValidHeaderSpecific(*s, PETSC_SECTION_CLASSID, 1); 2666 if (--((PetscObject)*s)->refct > 0) { 2667 *s = NULL; 2668 PetscFunctionReturn(PETSC_SUCCESS); 2669 } 2670 PetscCall(PetscSectionReset(*s)); 2671 PetscCall(PetscHeaderDestroy(s)); 2672 PetscFunctionReturn(PETSC_SUCCESS); 2673 } 2674 2675 static PetscErrorCode VecIntGetValuesSection_Private(const PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt **values) 2676 { 2677 const PetscInt p = point - s->pStart; 2678 2679 PetscFunctionBegin; 2680 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2); 2681 *values = &baseArray[s->atlasOff[p]]; 2682 PetscFunctionReturn(PETSC_SUCCESS); 2683 } 2684 2685 static PetscErrorCode VecIntSetValuesSection_Private(PetscInt *baseArray, PetscSection s, PetscInt point, const PetscInt values[], InsertMode mode) 2686 { 2687 PetscInt *array; 2688 const PetscInt p = point - s->pStart; 2689 const PetscInt orientation = 0; /* Needs to be included for use in closure operations */ 2690 PetscInt cDim = 0; 2691 2692 PetscFunctionBegin; 2693 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 2); 2694 PetscCall(PetscSectionGetConstraintDof(s, p, &cDim)); 2695 array = &baseArray[s->atlasOff[p]]; 2696 if (!cDim) { 2697 if (orientation >= 0) { 2698 const PetscInt dim = s->atlasDof[p]; 2699 PetscInt i; 2700 2701 if (mode == INSERT_VALUES) { 2702 for (i = 0; i < dim; ++i) array[i] = values ? values[i] : i; 2703 } else { 2704 for (i = 0; i < dim; ++i) array[i] += values[i]; 2705 } 2706 } else { 2707 PetscInt offset = 0; 2708 PetscInt j = -1, field, i; 2709 2710 for (field = 0; field < s->numFields; ++field) { 2711 const PetscInt dim = s->field[field]->atlasDof[p]; 2712 2713 for (i = dim - 1; i >= 0; --i) array[++j] = values ? values[i + offset] : i + offset; 2714 offset += dim; 2715 } 2716 } 2717 } else { 2718 if (orientation >= 0) { 2719 const PetscInt dim = s->atlasDof[p]; 2720 PetscInt cInd = 0, i; 2721 const PetscInt *cDof; 2722 2723 PetscCall(PetscSectionGetConstraintIndices(s, point, &cDof)); 2724 if (mode == INSERT_VALUES) { 2725 for (i = 0; i < dim; ++i) { 2726 if ((cInd < cDim) && (i == cDof[cInd])) { 2727 ++cInd; 2728 continue; 2729 } 2730 array[i] = values ? values[i] : i; 2731 } 2732 } else { 2733 for (i = 0; i < dim; ++i) { 2734 if ((cInd < cDim) && (i == cDof[cInd])) { 2735 ++cInd; 2736 continue; 2737 } 2738 array[i] += values[i]; 2739 } 2740 } 2741 } else { 2742 const PetscInt *cDof; 2743 PetscInt offset = 0; 2744 PetscInt cOffset = 0; 2745 PetscInt j = 0, field; 2746 2747 PetscCall(PetscSectionGetConstraintIndices(s, point, &cDof)); 2748 for (field = 0; field < s->numFields; ++field) { 2749 const PetscInt dim = s->field[field]->atlasDof[p]; /* PetscSectionGetFieldDof() */ 2750 const PetscInt tDim = s->field[field]->bc->atlasDof[p]; /* PetscSectionGetFieldConstraintDof() */ 2751 const PetscInt sDim = dim - tDim; 2752 PetscInt cInd = 0, i, k; 2753 2754 for (i = 0, k = dim + offset - 1; i < dim; ++i, ++j, --k) { 2755 if ((cInd < sDim) && (j == cDof[cInd + cOffset])) { 2756 ++cInd; 2757 continue; 2758 } 2759 array[j] = values ? values[k] : k; 2760 } 2761 offset += dim; 2762 cOffset += dim - tDim; 2763 } 2764 } 2765 } 2766 PetscFunctionReturn(PETSC_SUCCESS); 2767 } 2768 2769 /*@ 2770 PetscSectionHasConstraints - Determine whether a `PetscSection` has constrained dofs 2771 2772 Not Collective 2773 2774 Input Parameter: 2775 . s - The `PetscSection` 2776 2777 Output Parameter: 2778 . hasConstraints - flag indicating that the section has constrained dofs 2779 2780 Level: intermediate 2781 2782 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2783 @*/ 2784 PetscErrorCode PetscSectionHasConstraints(PetscSection s, PetscBool *hasConstraints) 2785 { 2786 PetscFunctionBegin; 2787 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2788 PetscAssertPointer(hasConstraints, 2); 2789 *hasConstraints = s->bc ? PETSC_TRUE : PETSC_FALSE; 2790 PetscFunctionReturn(PETSC_SUCCESS); 2791 } 2792 2793 /*@C 2794 PetscSectionGetConstraintIndices - Get the point dof numbers, in [0, dof), which are constrained for a given point 2795 2796 Not Collective 2797 2798 Input Parameters: 2799 + s - The `PetscSection` 2800 - point - The point 2801 2802 Output Parameter: 2803 . indices - The constrained dofs 2804 2805 Level: intermediate 2806 2807 Fortran Notes: 2808 Use `PetscSectionGetConstraintIndicesF90()` and `PetscSectionRestoreConstraintIndicesF90()` 2809 2810 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2811 @*/ 2812 PetscErrorCode PetscSectionGetConstraintIndices(PetscSection s, PetscInt point, const PetscInt *indices[]) 2813 { 2814 PetscFunctionBegin; 2815 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2816 if (s->bc) { 2817 PetscCall(VecIntGetValuesSection_Private(s->bcIndices, s->bc, point, indices)); 2818 } else *indices = NULL; 2819 PetscFunctionReturn(PETSC_SUCCESS); 2820 } 2821 2822 /*@ 2823 PetscSectionSetConstraintIndices - Set the point dof numbers, in [0, dof), which are constrained 2824 2825 Not Collective 2826 2827 Input Parameters: 2828 + s - The `PetscSection` 2829 . point - The point 2830 - indices - The constrained dofs 2831 2832 Level: intermediate 2833 2834 Fortran Notes: 2835 Use `PetscSectionSetConstraintIndicesF90()` 2836 2837 .seealso: [PetscSection](sec_petscsection), `PetscSectionGetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2838 @*/ 2839 PetscErrorCode PetscSectionSetConstraintIndices(PetscSection s, PetscInt point, const PetscInt indices[]) 2840 { 2841 PetscFunctionBegin; 2842 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2843 if (s->bc) { 2844 const PetscInt dof = s->atlasDof[point]; 2845 const PetscInt cdof = s->bc->atlasDof[point]; 2846 PetscInt d; 2847 2848 if (indices) 2849 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]); 2850 PetscCall(VecIntSetValuesSection_Private(s->bcIndices, s->bc, point, indices, INSERT_VALUES)); 2851 } 2852 PetscFunctionReturn(PETSC_SUCCESS); 2853 } 2854 2855 /*@C 2856 PetscSectionGetFieldConstraintIndices - Get the field dof numbers, in [0, fdof), which are constrained 2857 2858 Not Collective 2859 2860 Input Parameters: 2861 + s - The `PetscSection` 2862 . field - The field number 2863 - point - The point 2864 2865 Output Parameter: 2866 . indices - The constrained dofs sorted in ascending order 2867 2868 Level: intermediate 2869 2870 Note: 2871 The indices array, which is provided by the caller, must have capacity to hold the number of constrained dofs, e.g., as returned by `PetscSectionGetConstraintDof()`. 2872 2873 Fortran Notes: 2874 Use `PetscSectionGetFieldConstraintIndicesF90()` and `PetscSectionRestoreFieldConstraintIndicesF90()` 2875 2876 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetFieldConstraintIndices()`, `PetscSectionGetConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2877 @*/ 2878 PetscErrorCode PetscSectionGetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt **indices) 2879 { 2880 PetscFunctionBegin; 2881 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2882 PetscAssertPointer(indices, 4); 2883 PetscSectionCheckValidField(field, s->numFields); 2884 PetscCall(PetscSectionGetConstraintIndices(s->field[field], point, indices)); 2885 PetscFunctionReturn(PETSC_SUCCESS); 2886 } 2887 2888 /*@C 2889 PetscSectionSetFieldConstraintIndices - Set the field dof numbers, in [0, fdof), which are constrained 2890 2891 Not Collective 2892 2893 Input Parameters: 2894 + s - The `PetscSection` 2895 . point - The point 2896 . field - The field number 2897 - indices - The constrained dofs 2898 2899 Level: intermediate 2900 2901 Fortran Notes: 2902 Use `PetscSectionSetFieldConstraintIndicesF90()` 2903 2904 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetConstraintIndices()`, `PetscSectionGetFieldConstraintIndices()`, `PetscSectionGetConstraintDof()`, `PetscSection` 2905 @*/ 2906 PetscErrorCode PetscSectionSetFieldConstraintIndices(PetscSection s, PetscInt point, PetscInt field, const PetscInt indices[]) 2907 { 2908 PetscFunctionBegin; 2909 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 2910 PetscSectionCheckValidField(field, s->numFields); 2911 PetscCall(PetscSectionSetConstraintIndices(s->field[field], point, indices)); 2912 PetscFunctionReturn(PETSC_SUCCESS); 2913 } 2914 2915 /*@ 2916 PetscSectionPermute - Reorder the section according to the input point permutation 2917 2918 Collective 2919 2920 Input Parameters: 2921 + section - The `PetscSection` object 2922 - permutation - The point permutation, old point p becomes new point perm[p] 2923 2924 Output Parameter: 2925 . sectionNew - The permuted `PetscSection` 2926 2927 Level: intermediate 2928 2929 Note: 2930 The data and the access to the data via `PetscSectionGetFieldOffset()` and `PetscSectionGetOffset()` are both changed in `sectionNew` 2931 2932 Compare to `PetscSectionSetPermutation()` 2933 2934 .seealso: [PetscSection](sec_petscsection), `IS`, `PetscSection`, `MatPermute()`, `PetscSectionSetPermutation()` 2935 @*/ 2936 PetscErrorCode PetscSectionPermute(PetscSection section, IS permutation, PetscSection *sectionNew) 2937 { 2938 PetscSection s = section, sNew; 2939 const PetscInt *perm; 2940 PetscInt numFields, f, c, numPoints, pStart, pEnd, p; 2941 2942 PetscFunctionBegin; 2943 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 2944 PetscValidHeaderSpecific(permutation, IS_CLASSID, 2); 2945 PetscAssertPointer(sectionNew, 3); 2946 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)s), &sNew)); 2947 PetscCall(PetscSectionGetNumFields(s, &numFields)); 2948 if (numFields) PetscCall(PetscSectionSetNumFields(sNew, numFields)); 2949 for (f = 0; f < numFields; ++f) { 2950 const char *name; 2951 PetscInt numComp; 2952 2953 PetscCall(PetscSectionGetFieldName(s, f, &name)); 2954 PetscCall(PetscSectionSetFieldName(sNew, f, name)); 2955 PetscCall(PetscSectionGetFieldComponents(s, f, &numComp)); 2956 PetscCall(PetscSectionSetFieldComponents(sNew, f, numComp)); 2957 for (c = 0; c < s->numFieldComponents[f]; ++c) { 2958 PetscCall(PetscSectionGetComponentName(s, f, c, &name)); 2959 PetscCall(PetscSectionSetComponentName(sNew, f, c, name)); 2960 } 2961 } 2962 PetscCall(ISGetLocalSize(permutation, &numPoints)); 2963 PetscCall(ISGetIndices(permutation, &perm)); 2964 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 2965 PetscCall(PetscSectionSetChart(sNew, pStart, pEnd)); 2966 PetscCheck(numPoints >= pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Permutation size %" PetscInt_FMT " is less than largest Section point %" PetscInt_FMT, numPoints, pEnd); 2967 for (p = pStart; p < pEnd; ++p) { 2968 PetscInt dof, cdof; 2969 2970 PetscCall(PetscSectionGetDof(s, p, &dof)); 2971 PetscCall(PetscSectionSetDof(sNew, perm[p], dof)); 2972 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 2973 if (cdof) PetscCall(PetscSectionSetConstraintDof(sNew, perm[p], cdof)); 2974 for (f = 0; f < numFields; ++f) { 2975 PetscCall(PetscSectionGetFieldDof(s, p, f, &dof)); 2976 PetscCall(PetscSectionSetFieldDof(sNew, perm[p], f, dof)); 2977 PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof)); 2978 if (cdof) PetscCall(PetscSectionSetFieldConstraintDof(sNew, perm[p], f, cdof)); 2979 } 2980 } 2981 PetscCall(PetscSectionSetUp(sNew)); 2982 for (p = pStart; p < pEnd; ++p) { 2983 const PetscInt *cind; 2984 PetscInt cdof; 2985 2986 PetscCall(PetscSectionGetConstraintDof(s, p, &cdof)); 2987 if (cdof) { 2988 PetscCall(PetscSectionGetConstraintIndices(s, p, &cind)); 2989 PetscCall(PetscSectionSetConstraintIndices(sNew, perm[p], cind)); 2990 } 2991 for (f = 0; f < numFields; ++f) { 2992 PetscCall(PetscSectionGetFieldConstraintDof(s, p, f, &cdof)); 2993 if (cdof) { 2994 PetscCall(PetscSectionGetFieldConstraintIndices(s, p, f, &cind)); 2995 PetscCall(PetscSectionSetFieldConstraintIndices(sNew, perm[p], f, cind)); 2996 } 2997 } 2998 } 2999 PetscCall(ISRestoreIndices(permutation, &perm)); 3000 *sectionNew = sNew; 3001 PetscFunctionReturn(PETSC_SUCCESS); 3002 } 3003 3004 /*@ 3005 PetscSectionSetClosureIndex - Create an internal data structure to speed up closure queries. 3006 3007 Collective 3008 3009 Input Parameters: 3010 + section - The `PetscSection` 3011 . obj - A `PetscObject` which serves as the key for this index 3012 . clSection - `PetscSection` giving the size of the closure of each point 3013 - clPoints - `IS` giving the points in each closure 3014 3015 Level: advanced 3016 3017 Note: 3018 This function creates an internal map from each point to its closure. We compress out closure points with no dofs in this section. 3019 3020 Developer Notes: 3021 The information provided here is completely opaque 3022 3023 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionGetClosureIndex()`, `DMPlexCreateClosureIndex()` 3024 @*/ 3025 PetscErrorCode PetscSectionSetClosureIndex(PetscSection section, PetscObject obj, PetscSection clSection, IS clPoints) 3026 { 3027 PetscFunctionBegin; 3028 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3029 PetscValidHeaderSpecific(clSection, PETSC_SECTION_CLASSID, 3); 3030 PetscValidHeaderSpecific(clPoints, IS_CLASSID, 4); 3031 if (section->clObj != obj) PetscCall(PetscSectionResetClosurePermutation(section)); 3032 section->clObj = obj; 3033 PetscCall(PetscObjectReference((PetscObject)clSection)); 3034 PetscCall(PetscObjectReference((PetscObject)clPoints)); 3035 PetscCall(PetscSectionDestroy(§ion->clSection)); 3036 PetscCall(ISDestroy(§ion->clPoints)); 3037 section->clSection = clSection; 3038 section->clPoints = clPoints; 3039 PetscFunctionReturn(PETSC_SUCCESS); 3040 } 3041 3042 /*@ 3043 PetscSectionGetClosureIndex - Get the cache of points in the closure of each point in the section set with `PetscSectionSetClosureIndex()` 3044 3045 Collective 3046 3047 Input Parameters: 3048 + section - The `PetscSection` 3049 - obj - A `PetscObject` which serves as the key for this index 3050 3051 Output Parameters: 3052 + clSection - `PetscSection` giving the size of the closure of each point 3053 - clPoints - `IS` giving the points in each closure 3054 3055 Level: advanced 3056 3057 .seealso: [PetscSection](sec_petscsection), `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()` 3058 @*/ 3059 PetscErrorCode PetscSectionGetClosureIndex(PetscSection section, PetscObject obj, PetscSection *clSection, IS *clPoints) 3060 { 3061 PetscFunctionBegin; 3062 if (section->clObj == obj) { 3063 if (clSection) *clSection = section->clSection; 3064 if (clPoints) *clPoints = section->clPoints; 3065 } else { 3066 if (clSection) *clSection = NULL; 3067 if (clPoints) *clPoints = NULL; 3068 } 3069 PetscFunctionReturn(PETSC_SUCCESS); 3070 } 3071 3072 PetscErrorCode PetscSectionSetClosurePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, PetscCopyMode mode, PetscInt *clPerm) 3073 { 3074 PetscInt i; 3075 khiter_t iter; 3076 int new_entry; 3077 PetscSectionClosurePermKey key = {depth, clSize}; 3078 PetscSectionClosurePermVal *val; 3079 3080 PetscFunctionBegin; 3081 if (section->clObj != obj) { 3082 PetscCall(PetscSectionDestroy(§ion->clSection)); 3083 PetscCall(ISDestroy(§ion->clPoints)); 3084 } 3085 section->clObj = obj; 3086 if (!section->clHash) PetscCall(PetscClPermCreate(§ion->clHash)); 3087 iter = kh_put(ClPerm, section->clHash, key, &new_entry); 3088 val = &kh_val(section->clHash, iter); 3089 if (!new_entry) { 3090 PetscCall(PetscFree(val->perm)); 3091 PetscCall(PetscFree(val->invPerm)); 3092 } 3093 if (mode == PETSC_COPY_VALUES) { 3094 PetscCall(PetscMalloc1(clSize, &val->perm)); 3095 PetscCall(PetscArraycpy(val->perm, clPerm, clSize)); 3096 } else if (mode == PETSC_OWN_POINTER) { 3097 val->perm = clPerm; 3098 } else SETERRQ(PetscObjectComm(obj), PETSC_ERR_SUP, "Do not support borrowed arrays"); 3099 PetscCall(PetscMalloc1(clSize, &val->invPerm)); 3100 for (i = 0; i < clSize; ++i) val->invPerm[clPerm[i]] = i; 3101 PetscFunctionReturn(PETSC_SUCCESS); 3102 } 3103 3104 /*@ 3105 PetscSectionSetClosurePermutation - Set the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex. 3106 3107 Not Collective 3108 3109 Input Parameters: 3110 + section - The `PetscSection` 3111 . obj - A `PetscObject` which serves as the key for this index (usually a `DM`) 3112 . depth - Depth of points on which to apply the given permutation 3113 - perm - Permutation of the cell dof closure 3114 3115 Level: intermediate 3116 3117 Notes: 3118 The specified permutation will only be applied to points at depth whose closure size matches the length of perm. In a 3119 mixed-topology or variable-degree finite element space, this function can be called multiple times at each depth for 3120 each topology and degree. 3121 3122 This approach assumes that (depth, len(perm)) uniquely identifies the desired permutation; this might not be true for 3123 exotic/enriched spaces on mixed topology meshes. 3124 3125 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionGetClosurePermutation()`, `PetscSectionGetClosureIndex()`, `DMPlexCreateClosureIndex()`, `PetscCopyMode` 3126 @*/ 3127 PetscErrorCode PetscSectionSetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, IS perm) 3128 { 3129 const PetscInt *clPerm = NULL; 3130 PetscInt clSize = 0; 3131 3132 PetscFunctionBegin; 3133 if (perm) { 3134 PetscCall(ISGetLocalSize(perm, &clSize)); 3135 PetscCall(ISGetIndices(perm, &clPerm)); 3136 } 3137 PetscCall(PetscSectionSetClosurePermutation_Internal(section, obj, depth, clSize, PETSC_COPY_VALUES, (PetscInt *)clPerm)); 3138 if (perm) PetscCall(ISRestoreIndices(perm, &clPerm)); 3139 PetscFunctionReturn(PETSC_SUCCESS); 3140 } 3141 3142 static PetscErrorCode PetscSectionGetClosurePermutation_Private(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[]) 3143 { 3144 PetscFunctionBegin; 3145 if (section->clObj == obj) { 3146 PetscSectionClosurePermKey k = {depth, size}; 3147 PetscSectionClosurePermVal v; 3148 3149 PetscCall(PetscClPermGet(section->clHash, k, &v)); 3150 if (perm) *perm = v.perm; 3151 } else { 3152 if (perm) *perm = NULL; 3153 } 3154 PetscFunctionReturn(PETSC_SUCCESS); 3155 } 3156 3157 /*@ 3158 PetscSectionGetClosurePermutation - Get the dof permutation for the closure of each cell in the section, meaning clPerm[newIndex] = oldIndex. 3159 3160 Not Collective 3161 3162 Input Parameters: 3163 + section - The `PetscSection` 3164 . obj - A `PetscObject` which serves as the key for this index (usually a DM) 3165 . depth - Depth stratum on which to obtain closure permutation 3166 - clSize - Closure size to be permuted (e.g., may vary with element topology and degree) 3167 3168 Output Parameter: 3169 . perm - The dof closure permutation 3170 3171 Level: intermediate 3172 3173 Note: 3174 The user must destroy the `IS` that is returned. 3175 3176 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionSetClosurePermutation()`, `PetscSectionGetClosureInversePermutation()`, `PetscSectionGetClosureIndex()`, `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()` 3177 @*/ 3178 PetscErrorCode PetscSectionGetClosurePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm) 3179 { 3180 const PetscInt *clPerm = NULL; 3181 3182 PetscFunctionBegin; 3183 PetscCall(PetscSectionGetClosurePermutation_Private(section, obj, depth, clSize, &clPerm)); 3184 PetscCheck(clPerm, PetscObjectComm((PetscObject)obj), PETSC_ERR_ARG_WRONG, "There is no closure permutation associated with this object for depth %" PetscInt_FMT " of size %" PetscInt_FMT, depth, clSize); 3185 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm)); 3186 PetscFunctionReturn(PETSC_SUCCESS); 3187 } 3188 3189 PetscErrorCode PetscSectionGetClosureInversePermutation_Internal(PetscSection section, PetscObject obj, PetscInt depth, PetscInt size, const PetscInt *perm[]) 3190 { 3191 PetscFunctionBegin; 3192 if (section->clObj == obj && section->clHash) { 3193 PetscSectionClosurePermKey k = {depth, size}; 3194 PetscSectionClosurePermVal v; 3195 PetscCall(PetscClPermGet(section->clHash, k, &v)); 3196 if (perm) *perm = v.invPerm; 3197 } else { 3198 if (perm) *perm = NULL; 3199 } 3200 PetscFunctionReturn(PETSC_SUCCESS); 3201 } 3202 3203 /*@ 3204 PetscSectionGetClosureInversePermutation - Get the inverse dof permutation for the closure of each cell in the section, meaning clPerm[oldIndex] = newIndex. 3205 3206 Not Collective 3207 3208 Input Parameters: 3209 + section - The `PetscSection` 3210 . obj - A `PetscObject` which serves as the key for this index (usually a `DM`) 3211 . depth - Depth stratum on which to obtain closure permutation 3212 - clSize - Closure size to be permuted (e.g., may vary with element topology and degree) 3213 3214 Output Parameter: 3215 . perm - The dof closure permutation 3216 3217 Level: intermediate 3218 3219 Note: 3220 The user must destroy the `IS` that is returned. 3221 3222 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionSetClosurePermutation()`, `PetscSectionGetClosureIndex()`, `PetscSectionSetClosureIndex()`, `DMPlexCreateClosureIndex()` 3223 @*/ 3224 PetscErrorCode PetscSectionGetClosureInversePermutation(PetscSection section, PetscObject obj, PetscInt depth, PetscInt clSize, IS *perm) 3225 { 3226 const PetscInt *clPerm = NULL; 3227 3228 PetscFunctionBegin; 3229 PetscCall(PetscSectionGetClosureInversePermutation_Internal(section, obj, depth, clSize, &clPerm)); 3230 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, clSize, clPerm, PETSC_USE_POINTER, perm)); 3231 PetscFunctionReturn(PETSC_SUCCESS); 3232 } 3233 3234 /*@ 3235 PetscSectionGetField - Get the `PetscSection` associated with a single field 3236 3237 Input Parameters: 3238 + s - The `PetscSection` 3239 - field - The field number 3240 3241 Output Parameter: 3242 . subs - The `PetscSection` for the given field, note the chart of `subs` is not set 3243 3244 Level: intermediate 3245 3246 Note: 3247 Does not increase the reference count of the selected sub-section. There is no matching `PetscSectionRestoreField()` 3248 3249 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `IS`, `PetscSectionSetNumFields()` 3250 @*/ 3251 PetscErrorCode PetscSectionGetField(PetscSection s, PetscInt field, PetscSection *subs) 3252 { 3253 PetscFunctionBegin; 3254 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 3255 PetscAssertPointer(subs, 3); 3256 PetscSectionCheckValidField(field, s->numFields); 3257 *subs = s->field[field]; 3258 PetscFunctionReturn(PETSC_SUCCESS); 3259 } 3260 3261 PetscClassId PETSC_SECTION_SYM_CLASSID; 3262 PetscFunctionList PetscSectionSymList = NULL; 3263 3264 /*@ 3265 PetscSectionSymCreate - Creates an empty `PetscSectionSym` object. 3266 3267 Collective 3268 3269 Input Parameter: 3270 . comm - the MPI communicator 3271 3272 Output Parameter: 3273 . sym - pointer to the new set of symmetries 3274 3275 Level: developer 3276 3277 .seealso: [PetscSection](sec_petscsection), `PetscSection`, `PetscSectionSym`, `PetscSectionSymDestroy()` 3278 @*/ 3279 PetscErrorCode PetscSectionSymCreate(MPI_Comm comm, PetscSectionSym *sym) 3280 { 3281 PetscFunctionBegin; 3282 PetscAssertPointer(sym, 2); 3283 PetscCall(ISInitializePackage()); 3284 3285 PetscCall(PetscHeaderCreate(*sym, PETSC_SECTION_SYM_CLASSID, "PetscSectionSym", "Section Symmetry", "IS", comm, PetscSectionSymDestroy, PetscSectionSymView)); 3286 PetscFunctionReturn(PETSC_SUCCESS); 3287 } 3288 3289 /*@ 3290 PetscSectionSymSetType - Builds a `PetscSectionSym`, for a particular implementation. 3291 3292 Collective 3293 3294 Input Parameters: 3295 + sym - The section symmetry object 3296 - method - The name of the section symmetry type 3297 3298 Level: developer 3299 3300 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymGetType()`, `PetscSectionSymCreate()` 3301 @*/ 3302 PetscErrorCode PetscSectionSymSetType(PetscSectionSym sym, PetscSectionSymType method) 3303 { 3304 PetscErrorCode (*r)(PetscSectionSym); 3305 PetscBool match; 3306 3307 PetscFunctionBegin; 3308 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3309 PetscCall(PetscObjectTypeCompare((PetscObject)sym, method, &match)); 3310 if (match) PetscFunctionReturn(PETSC_SUCCESS); 3311 3312 PetscCall(PetscFunctionListFind(PetscSectionSymList, method, &r)); 3313 PetscCheck(r, PetscObjectComm((PetscObject)sym), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscSectionSym type: %s", method); 3314 PetscTryTypeMethod(sym, destroy); 3315 sym->ops->destroy = NULL; 3316 3317 PetscCall((*r)(sym)); 3318 PetscCall(PetscObjectChangeTypeName((PetscObject)sym, method)); 3319 PetscFunctionReturn(PETSC_SUCCESS); 3320 } 3321 3322 /*@ 3323 PetscSectionSymGetType - Gets the section symmetry type name (as a string) from the `PetscSectionSym`. 3324 3325 Not Collective 3326 3327 Input Parameter: 3328 . sym - The section symmetry 3329 3330 Output Parameter: 3331 . type - The index set type name 3332 3333 Level: developer 3334 3335 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymSetType()`, `PetscSectionSymCreate()` 3336 @*/ 3337 PetscErrorCode PetscSectionSymGetType(PetscSectionSym sym, PetscSectionSymType *type) 3338 { 3339 PetscFunctionBegin; 3340 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3341 PetscAssertPointer(type, 2); 3342 *type = ((PetscObject)sym)->type_name; 3343 PetscFunctionReturn(PETSC_SUCCESS); 3344 } 3345 3346 /*@C 3347 PetscSectionSymRegister - Registers a new section symmetry implementation 3348 3349 Not Collective, No Fortran Support 3350 3351 Input Parameters: 3352 + sname - The name of a new user-defined creation routine 3353 - function - The creation routine itself 3354 3355 Level: developer 3356 3357 Notes: 3358 `PetscSectionSymRegister()` may be called multiple times to add several user-defined vectors 3359 3360 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymType`, `PetscSectionSymCreate()`, `PetscSectionSymSetType()` 3361 @*/ 3362 PetscErrorCode PetscSectionSymRegister(const char sname[], PetscErrorCode (*function)(PetscSectionSym)) 3363 { 3364 PetscFunctionBegin; 3365 PetscCall(ISInitializePackage()); 3366 PetscCall(PetscFunctionListAdd(&PetscSectionSymList, sname, function)); 3367 PetscFunctionReturn(PETSC_SUCCESS); 3368 } 3369 3370 /*@ 3371 PetscSectionSymDestroy - Destroys a section symmetry. 3372 3373 Collective 3374 3375 Input Parameter: 3376 . sym - the section symmetry 3377 3378 Level: developer 3379 3380 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()` 3381 @*/ 3382 PetscErrorCode PetscSectionSymDestroy(PetscSectionSym *sym) 3383 { 3384 SymWorkLink link, next; 3385 3386 PetscFunctionBegin; 3387 if (!*sym) PetscFunctionReturn(PETSC_SUCCESS); 3388 PetscValidHeaderSpecific(*sym, PETSC_SECTION_SYM_CLASSID, 1); 3389 if (--((PetscObject)*sym)->refct > 0) { 3390 *sym = NULL; 3391 PetscFunctionReturn(PETSC_SUCCESS); 3392 } 3393 PetscTryTypeMethod(*sym, destroy); 3394 PetscCheck(!(*sym)->workout, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Work array still checked out"); 3395 for (link = (*sym)->workin; link; link = next) { 3396 PetscInt **perms = (PetscInt **)link->perms; 3397 PetscScalar **rots = (PetscScalar **)link->rots; 3398 PetscCall(PetscFree2(perms, rots)); 3399 next = link->next; 3400 PetscCall(PetscFree(link)); 3401 } 3402 (*sym)->workin = NULL; 3403 PetscCall(PetscHeaderDestroy(sym)); 3404 PetscFunctionReturn(PETSC_SUCCESS); 3405 } 3406 3407 /*@ 3408 PetscSectionSymView - Displays a section symmetry 3409 3410 Collective 3411 3412 Input Parameters: 3413 + sym - the index set 3414 - viewer - viewer used to display the set, for example `PETSC_VIEWER_STDOUT_SELF`. 3415 3416 Level: developer 3417 3418 .seealso: `PetscSectionSym`, `PetscViewer`, `PetscViewerASCIIOpen()` 3419 @*/ 3420 PetscErrorCode PetscSectionSymView(PetscSectionSym sym, PetscViewer viewer) 3421 { 3422 PetscFunctionBegin; 3423 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3424 if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)sym), &viewer)); 3425 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 3426 PetscCheckSameComm(sym, 1, viewer, 2); 3427 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)sym, viewer)); 3428 PetscTryTypeMethod(sym, view, viewer); 3429 PetscFunctionReturn(PETSC_SUCCESS); 3430 } 3431 3432 /*@ 3433 PetscSectionSetSym - Set the symmetries for the data referred to by the section 3434 3435 Collective 3436 3437 Input Parameters: 3438 + section - the section describing data layout 3439 - sym - the symmetry describing the affect of orientation on the access of the data 3440 3441 Level: developer 3442 3443 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetSym()`, `PetscSectionSymCreate()` 3444 @*/ 3445 PetscErrorCode PetscSectionSetSym(PetscSection section, PetscSectionSym sym) 3446 { 3447 PetscFunctionBegin; 3448 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3449 PetscCall(PetscSectionSymDestroy(§ion->sym)); 3450 if (sym) { 3451 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 2); 3452 PetscCheckSameComm(section, 1, sym, 2); 3453 PetscCall(PetscObjectReference((PetscObject)sym)); 3454 } 3455 section->sym = sym; 3456 PetscFunctionReturn(PETSC_SUCCESS); 3457 } 3458 3459 /*@ 3460 PetscSectionGetSym - Get the symmetries for the data referred to by the section 3461 3462 Not Collective 3463 3464 Input Parameter: 3465 . section - the section describing data layout 3466 3467 Output Parameter: 3468 . sym - the symmetry describing the affect of orientation on the access of the data, provided previously by `PetscSectionSetSym()` 3469 3470 Level: developer 3471 3472 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSetSym()`, `PetscSectionSymCreate()` 3473 @*/ 3474 PetscErrorCode PetscSectionGetSym(PetscSection section, PetscSectionSym *sym) 3475 { 3476 PetscFunctionBegin; 3477 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3478 *sym = section->sym; 3479 PetscFunctionReturn(PETSC_SUCCESS); 3480 } 3481 3482 /*@ 3483 PetscSectionSetFieldSym - Set the symmetries for the data referred to by a field of the section 3484 3485 Collective 3486 3487 Input Parameters: 3488 + section - the section describing data layout 3489 . field - the field number 3490 - sym - the symmetry describing the affect of orientation on the access of the data 3491 3492 Level: developer 3493 3494 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetFieldSym()`, `PetscSectionSymCreate()` 3495 @*/ 3496 PetscErrorCode PetscSectionSetFieldSym(PetscSection section, PetscInt field, PetscSectionSym sym) 3497 { 3498 PetscFunctionBegin; 3499 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3500 PetscSectionCheckValidField(field, section->numFields); 3501 PetscCall(PetscSectionSetSym(section->field[field], sym)); 3502 PetscFunctionReturn(PETSC_SUCCESS); 3503 } 3504 3505 /*@ 3506 PetscSectionGetFieldSym - Get the symmetries for the data referred to by a field of the section 3507 3508 Collective 3509 3510 Input Parameters: 3511 + section - the section describing data layout 3512 - field - the field number 3513 3514 Output Parameter: 3515 . sym - the symmetry describing the affect of orientation on the access of the data 3516 3517 Level: developer 3518 3519 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSetFieldSym()`, `PetscSectionSymCreate()` 3520 @*/ 3521 PetscErrorCode PetscSectionGetFieldSym(PetscSection section, PetscInt field, PetscSectionSym *sym) 3522 { 3523 PetscFunctionBegin; 3524 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3525 PetscSectionCheckValidField(field, section->numFields); 3526 *sym = section->field[field]->sym; 3527 PetscFunctionReturn(PETSC_SUCCESS); 3528 } 3529 3530 /*@C 3531 PetscSectionGetPointSyms - Get the symmetries for a set of points in a `PetscSection` under specific orientations. 3532 3533 Not Collective 3534 3535 Input Parameters: 3536 + section - the section 3537 . numPoints - the number of points 3538 - points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an 3539 arbitrary integer: its interpretation is up to sym. Orientations are used by `DM`: for their interpretation in that 3540 context, see `DMPlexGetConeOrientation()`). 3541 3542 Output Parameters: 3543 + perms - The permutations for the given orientations (or `NULL` if there is no symmetry or the permutation is the identity). 3544 - rots - The field rotations symmetries for the given orientations (or `NULL` if there is no symmetry or the rotations are all 3545 identity). 3546 3547 Example of usage, gathering dofs into a local array (lArray) from a section array (sArray): 3548 .vb 3549 const PetscInt **perms; 3550 const PetscScalar **rots; 3551 PetscInt lOffset; 3552 3553 PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots); 3554 for (i = 0, lOffset = 0; i < numPoints; i++) { 3555 PetscInt point = points[2*i], dof, sOffset; 3556 const PetscInt *perm = perms ? perms[i] : NULL; 3557 const PetscScalar *rot = rots ? rots[i] : NULL; 3558 3559 PetscSectionGetDof(section,point,&dof); 3560 PetscSectionGetOffset(section,point,&sOffset); 3561 3562 if (perm) {for (j = 0; j < dof; j++) {lArray[lOffset + perm[j]] = sArray[sOffset + j];}} 3563 else {for (j = 0; j < dof; j++) {lArray[lOffset + j ] = sArray[sOffset + j];}} 3564 if (rot) {for (j = 0; j < dof; j++) {lArray[lOffset + j ] *= rot[j]; }} 3565 lOffset += dof; 3566 } 3567 PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots); 3568 .ve 3569 3570 Example of usage, adding dofs into a section array (sArray) from a local array (lArray): 3571 .vb 3572 const PetscInt **perms; 3573 const PetscScalar **rots; 3574 PetscInt lOffset; 3575 3576 PetscSectionGetPointSyms(section,numPoints,points,&perms,&rots); 3577 for (i = 0, lOffset = 0; i < numPoints; i++) { 3578 PetscInt point = points[2*i], dof, sOffset; 3579 const PetscInt *perm = perms ? perms[i] : NULL; 3580 const PetscScalar *rot = rots ? rots[i] : NULL; 3581 3582 PetscSectionGetDof(section,point,&dof); 3583 PetscSectionGetOffset(section,point,&sOff); 3584 3585 if (perm) {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset + perm[j]] * (rot ? PetscConj(rot[perm[j]]) : 1.);}} 3586 else {for (j = 0; j < dof; j++) {sArray[sOffset + j] += lArray[lOffset + j ] * (rot ? PetscConj(rot[ j ]) : 1.);}} 3587 offset += dof; 3588 } 3589 PetscSectionRestorePointSyms(section,numPoints,points,&perms,&rots); 3590 .ve 3591 3592 Level: developer 3593 3594 Notes: 3595 `PetscSectionSetSym()` must have been previously called to provide the symmetries to the `PetscSection` 3596 3597 Use `PetscSectionRestorePointSyms()` when finished with the data 3598 3599 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionRestorePointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()` 3600 @*/ 3601 PetscErrorCode PetscSectionGetPointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots) 3602 { 3603 PetscSectionSym sym; 3604 3605 PetscFunctionBegin; 3606 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3607 if (numPoints) PetscAssertPointer(points, 3); 3608 if (perms) *perms = NULL; 3609 if (rots) *rots = NULL; 3610 sym = section->sym; 3611 if (sym && (perms || rots)) { 3612 SymWorkLink link; 3613 3614 if (sym->workin) { 3615 link = sym->workin; 3616 sym->workin = sym->workin->next; 3617 } else { 3618 PetscCall(PetscNew(&link)); 3619 } 3620 if (numPoints > link->numPoints) { 3621 PetscInt **perms = (PetscInt **)link->perms; 3622 PetscScalar **rots = (PetscScalar **)link->rots; 3623 PetscCall(PetscFree2(perms, rots)); 3624 PetscCall(PetscMalloc2(numPoints, (PetscInt ***)&link->perms, numPoints, (PetscScalar ***)&link->rots)); 3625 link->numPoints = numPoints; 3626 } 3627 link->next = sym->workout; 3628 sym->workout = link; 3629 PetscCall(PetscArrayzero((PetscInt **)link->perms, numPoints)); 3630 PetscCall(PetscArrayzero((PetscInt **)link->rots, numPoints)); 3631 PetscUseTypeMethod(sym, getpoints, section, numPoints, points, link->perms, link->rots); 3632 if (perms) *perms = link->perms; 3633 if (rots) *rots = link->rots; 3634 } 3635 PetscFunctionReturn(PETSC_SUCCESS); 3636 } 3637 3638 /*@C 3639 PetscSectionRestorePointSyms - Restore the symmetries returned by `PetscSectionGetPointSyms()` 3640 3641 Not Collective 3642 3643 Input Parameters: 3644 + section - the section 3645 . numPoints - the number of points 3646 . points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an 3647 arbitrary integer: its interpretation is up to sym. Orientations are used by `DM`: for their interpretation in that 3648 context, see `DMPlexGetConeOrientation()`). 3649 . perms - The permutations for the given orientations: set to `NULL` at conclusion 3650 - rots - The field rotations symmetries for the given orientations: set to `NULL` at conclusion 3651 3652 Level: developer 3653 3654 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetPointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()` 3655 @*/ 3656 PetscErrorCode PetscSectionRestorePointSyms(PetscSection section, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots) 3657 { 3658 PetscSectionSym sym; 3659 3660 PetscFunctionBegin; 3661 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3662 sym = section->sym; 3663 if (sym && (perms || rots)) { 3664 SymWorkLink *p, link; 3665 3666 for (p = &sym->workout; (link = *p); p = &link->next) { 3667 if ((perms && link->perms == *perms) || (rots && link->rots == *rots)) { 3668 *p = link->next; 3669 link->next = sym->workin; 3670 sym->workin = link; 3671 if (perms) *perms = NULL; 3672 if (rots) *rots = NULL; 3673 PetscFunctionReturn(PETSC_SUCCESS); 3674 } 3675 } 3676 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Array was not checked out"); 3677 } 3678 PetscFunctionReturn(PETSC_SUCCESS); 3679 } 3680 3681 /*@C 3682 PetscSectionGetFieldPointSyms - Get the symmetries for a set of points in a field of a `PetscSection` under specific orientations. 3683 3684 Not Collective 3685 3686 Input Parameters: 3687 + section - the section 3688 . field - the field of the section 3689 . numPoints - the number of points 3690 - points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an 3691 arbitrary integer: its interpretation is up to sym. Orientations are used by `DM`: for their interpretation in that 3692 context, see `DMPlexGetConeOrientation()`). 3693 3694 Output Parameters: 3695 + perms - The permutations for the given orientations (or `NULL` if there is no symmetry or the permutation is the identity). 3696 - rots - The field rotations symmetries for the given orientations (or `NULL` if there is no symmetry or the rotations are all 3697 identity). 3698 3699 Level: developer 3700 3701 Notes: 3702 `PetscSectionSetFieldSym()` must have been previously called to provide the symmetries to the `PetscSection` 3703 3704 Use `PetscSectionRestoreFieldPointSyms()` when finished with the data 3705 3706 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetPointSyms()`, `PetscSectionRestoreFieldPointSyms()` 3707 @*/ 3708 PetscErrorCode PetscSectionGetFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots) 3709 { 3710 PetscFunctionBegin; 3711 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3712 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); 3713 PetscCall(PetscSectionGetPointSyms(section->field[field], numPoints, points, perms, rots)); 3714 PetscFunctionReturn(PETSC_SUCCESS); 3715 } 3716 3717 /*@C 3718 PetscSectionRestoreFieldPointSyms - Restore the symmetries returned by `PetscSectionGetFieldPointSyms()` 3719 3720 Not Collective 3721 3722 Input Parameters: 3723 + section - the section 3724 . field - the field number 3725 . numPoints - the number of points 3726 . points - an array of size 2 * `numPoints`, containing a list of (point, orientation) pairs. (An orientation is an 3727 arbitrary integer: its interpretation is up to sym. Orientations are used by `DM`: for their interpretation in that 3728 context, see `DMPlexGetConeOrientation()`). 3729 . perms - The permutations for the given orientations: set to NULL at conclusion 3730 - rots - The field rotations symmetries for the given orientations: set to NULL at conclusion 3731 3732 Level: developer 3733 3734 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionRestorePointSyms()`, `petscSectionGetFieldPointSyms()`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()` 3735 @*/ 3736 PetscErrorCode PetscSectionRestoreFieldPointSyms(PetscSection section, PetscInt field, PetscInt numPoints, const PetscInt *points, const PetscInt ***perms, const PetscScalar ***rots) 3737 { 3738 PetscFunctionBegin; 3739 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 1); 3740 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); 3741 PetscCall(PetscSectionRestorePointSyms(section->field[field], numPoints, points, perms, rots)); 3742 PetscFunctionReturn(PETSC_SUCCESS); 3743 } 3744 3745 /*@ 3746 PetscSectionSymCopy - Copy the symmetries, assuming that the point structure is compatible 3747 3748 Not Collective 3749 3750 Input Parameter: 3751 . sym - the `PetscSectionSym` 3752 3753 Output Parameter: 3754 . nsym - the equivalent symmetries 3755 3756 Level: developer 3757 3758 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()` 3759 @*/ 3760 PetscErrorCode PetscSectionSymCopy(PetscSectionSym sym, PetscSectionSym nsym) 3761 { 3762 PetscFunctionBegin; 3763 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3764 PetscValidHeaderSpecific(nsym, PETSC_SECTION_SYM_CLASSID, 2); 3765 PetscTryTypeMethod(sym, copy, nsym); 3766 PetscFunctionReturn(PETSC_SUCCESS); 3767 } 3768 3769 /*@ 3770 PetscSectionSymDistribute - Distribute the symmetries in accordance with the input `PetscSF` 3771 3772 Collective 3773 3774 Input Parameters: 3775 + sym - the `PetscSectionSym` 3776 - migrationSF - the distribution map from roots to leaves 3777 3778 Output Parameter: 3779 . dsym - the redistributed symmetries 3780 3781 Level: developer 3782 3783 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSymCreate()`, `PetscSectionSetSym()`, `PetscSectionGetSym()`, `PetscSectionSymLabelSetStratum()`, `PetscSectionGetPointSyms()` 3784 @*/ 3785 PetscErrorCode PetscSectionSymDistribute(PetscSectionSym sym, PetscSF migrationSF, PetscSectionSym *dsym) 3786 { 3787 PetscFunctionBegin; 3788 PetscValidHeaderSpecific(sym, PETSC_SECTION_SYM_CLASSID, 1); 3789 PetscValidHeaderSpecific(migrationSF, PETSCSF_CLASSID, 2); 3790 PetscAssertPointer(dsym, 3); 3791 PetscTryTypeMethod(sym, distribute, migrationSF, dsym); 3792 PetscFunctionReturn(PETSC_SUCCESS); 3793 } 3794 3795 /*@ 3796 PetscSectionGetUseFieldOffsets - Get the flag indicating if field offsets are used directly in a global section, rather than just the point offset 3797 3798 Not Collective 3799 3800 Input Parameter: 3801 . s - the global `PetscSection` 3802 3803 Output Parameter: 3804 . flg - the flag 3805 3806 Level: developer 3807 3808 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionSetChart()`, `PetscSectionCreate()` 3809 @*/ 3810 PetscErrorCode PetscSectionGetUseFieldOffsets(PetscSection s, PetscBool *flg) 3811 { 3812 PetscFunctionBegin; 3813 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 3814 *flg = s->useFieldOff; 3815 PetscFunctionReturn(PETSC_SUCCESS); 3816 } 3817 3818 /*@ 3819 PetscSectionSetUseFieldOffsets - Set the flag to use field offsets directly in a global section, rather than just the point offset 3820 3821 Not Collective 3822 3823 Input Parameters: 3824 + s - the global `PetscSection` 3825 - flg - the flag 3826 3827 Level: developer 3828 3829 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetUseFieldOffsets()`, `PetscSectionSetChart()`, `PetscSectionCreate()` 3830 @*/ 3831 PetscErrorCode PetscSectionSetUseFieldOffsets(PetscSection s, PetscBool flg) 3832 { 3833 PetscFunctionBegin; 3834 PetscValidHeaderSpecific(s, PETSC_SECTION_CLASSID, 1); 3835 s->useFieldOff = flg; 3836 PetscFunctionReturn(PETSC_SUCCESS); 3837 } 3838 3839 #define PetscSectionExpandPoints_Loop(TYPE) \ 3840 do { \ 3841 PetscInt i, n, o0, o1, size; \ 3842 TYPE *a0 = (TYPE *)origArray, *a1; \ 3843 PetscCall(PetscSectionGetStorageSize(s, &size)); \ 3844 PetscCall(PetscMalloc1(size, &a1)); \ 3845 for (i = 0; i < npoints; i++) { \ 3846 PetscCall(PetscSectionGetOffset(origSection, points_[i], &o0)); \ 3847 PetscCall(PetscSectionGetOffset(s, i, &o1)); \ 3848 PetscCall(PetscSectionGetDof(s, i, &n)); \ 3849 PetscCall(PetscMemcpy(&a1[o1], &a0[o0], n *unitsize)); \ 3850 } \ 3851 *newArray = (void *)a1; \ 3852 } while (0) 3853 3854 /*@ 3855 PetscSectionExtractDofsFromArray - Extracts elements of an array corresponding to DOFs of specified points. 3856 3857 Not Collective 3858 3859 Input Parameters: 3860 + origSection - the `PetscSection` describing the layout of the array 3861 . dataType - `MPI_Datatype` describing the data type of the array (currently only `MPIU_INT`, `MPIU_SCALAR`, `MPIU_REAL`) 3862 . origArray - the array; its size must be equal to the storage size of `origSection` 3863 - points - `IS` with points to extract; its indices must lie in the chart of `origSection` 3864 3865 Output Parameters: 3866 + newSection - the new `PetscSection` describing the layout of the new array (with points renumbered 0,1,... but preserving numbers of DOFs) 3867 - newArray - the array of the extracted DOFs; its size is the storage size of `newSection` 3868 3869 Level: developer 3870 3871 .seealso: [PetscSection](sec_petscsection), `PetscSectionSym`, `PetscSectionGetChart()`, `PetscSectionGetDof()`, `PetscSectionGetStorageSize()`, `PetscSectionCreate()` 3872 @*/ 3873 PetscErrorCode PetscSectionExtractDofsFromArray(PetscSection origSection, MPI_Datatype dataType, const void *origArray, IS points, PetscSection *newSection, void *newArray[]) 3874 { 3875 PetscSection s; 3876 const PetscInt *points_; 3877 PetscInt i, n, npoints, pStart, pEnd; 3878 PetscMPIInt unitsize; 3879 3880 PetscFunctionBegin; 3881 PetscValidHeaderSpecific(origSection, PETSC_SECTION_CLASSID, 1); 3882 PetscAssertPointer(origArray, 3); 3883 PetscValidHeaderSpecific(points, IS_CLASSID, 4); 3884 if (newSection) PetscAssertPointer(newSection, 5); 3885 if (newArray) PetscAssertPointer(newArray, 6); 3886 PetscCallMPI(MPI_Type_size(dataType, &unitsize)); 3887 PetscCall(ISGetLocalSize(points, &npoints)); 3888 PetscCall(ISGetIndices(points, &points_)); 3889 PetscCall(PetscSectionGetChart(origSection, &pStart, &pEnd)); 3890 PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &s)); 3891 PetscCall(PetscSectionSetChart(s, 0, npoints)); 3892 for (i = 0; i < npoints; i++) { 3893 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); 3894 PetscCall(PetscSectionGetDof(origSection, points_[i], &n)); 3895 PetscCall(PetscSectionSetDof(s, i, n)); 3896 } 3897 PetscCall(PetscSectionSetUp(s)); 3898 if (newArray) { 3899 if (dataType == MPIU_INT) { 3900 PetscSectionExpandPoints_Loop(PetscInt); 3901 } else if (dataType == MPIU_SCALAR) { 3902 PetscSectionExpandPoints_Loop(PetscScalar); 3903 } else if (dataType == MPIU_REAL) { 3904 PetscSectionExpandPoints_Loop(PetscReal); 3905 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "not implemented for this MPI_Datatype"); 3906 } 3907 if (newSection) { 3908 *newSection = s; 3909 } else { 3910 PetscCall(PetscSectionDestroy(&s)); 3911 } 3912 PetscCall(ISRestoreIndices(points, &points_)); 3913 PetscFunctionReturn(PETSC_SUCCESS); 3914 } 3915