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