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