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