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