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