1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/isimpl.h> 3 #include <petsc/private/vecimpl.h> 4 #include <petscsf.h> 5 #include <petscds.h> 6 #include <petscdraw.h> 7 8 /* Logging support */ 9 PetscLogEvent DMPLEX_Interpolate, PETSCPARTITIONER_Partition, DMPLEX_Distribute, DMPLEX_DistributeCones, DMPLEX_DistributeLabels, DMPLEX_DistributeSF, DMPLEX_DistributeOverlap, DMPLEX_DistributeField, DMPLEX_DistributeData, DMPLEX_Migrate, DMPLEX_GlobalToNaturalBegin, DMPLEX_GlobalToNaturalEnd, DMPLEX_NaturalToGlobalBegin, DMPLEX_NaturalToGlobalEnd, DMPLEX_Stratify, DMPLEX_Preallocate, DMPLEX_ResidualFEM, DMPLEX_JacobianFEM, DMPLEX_InterpolatorFEM, DMPLEX_InjectorFEM, DMPLEX_IntegralFEM, DMPLEX_CreateGmsh; 10 11 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 12 PETSC_EXTERN PetscErrorCode VecLoad_Default(Vec, PetscViewer); 13 14 #undef __FUNCT__ 15 #define __FUNCT__ "DMPlexGetFieldType_Internal" 16 PetscErrorCode DMPlexGetFieldType_Internal(DM dm, PetscSection section, PetscInt field, PetscInt *sStart, PetscInt *sEnd, PetscViewerVTKFieldType *ft) 17 { 18 PetscInt dim, pStart, pEnd, vStart, vEnd, cStart, cEnd, cEndInterior, vdof = 0, cdof = 0; 19 PetscErrorCode ierr; 20 21 PetscFunctionBegin; 22 *ft = PETSC_VTK_POINT_FIELD; 23 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 24 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 25 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 26 ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr); 27 cEnd = cEndInterior < 0 ? cEnd : cEndInterior; 28 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 29 if (field >= 0) { 30 if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, vStart, field, &vdof);CHKERRQ(ierr);} 31 if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetFieldDof(section, cStart, field, &cdof);CHKERRQ(ierr);} 32 } else { 33 if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);} 34 if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);} 35 } 36 if (vdof) { 37 *sStart = vStart; 38 *sEnd = vEnd; 39 if (vdof == dim) *ft = PETSC_VTK_POINT_VECTOR_FIELD; 40 else *ft = PETSC_VTK_POINT_FIELD; 41 } else if (cdof) { 42 *sStart = cStart; 43 *sEnd = cEnd; 44 if (cdof == dim) *ft = PETSC_VTK_CELL_VECTOR_FIELD; 45 else *ft = PETSC_VTK_CELL_FIELD; 46 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK"); 47 PetscFunctionReturn(0); 48 } 49 50 #undef __FUNCT__ 51 #define __FUNCT__ "VecView_Plex_Local" 52 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer) 53 { 54 DM dm; 55 PetscBool isvtk, ishdf5, isseq; 56 PetscErrorCode ierr; 57 58 PetscFunctionBegin; 59 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 60 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 61 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 62 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 63 ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr); 64 if (isvtk || ishdf5) { 65 PetscInt numFields; 66 PetscBool fem = PETSC_FALSE; 67 68 ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr); 69 if (numFields) { 70 PetscObject fe; 71 72 ierr = DMGetField(dm, 0, &fe);CHKERRQ(ierr); 73 if (fe->classid == PETSCFE_CLASSID) fem = PETSC_TRUE; 74 } 75 if (fem) {ierr = DMPlexInsertBoundaryValues(dm, PETSC_TRUE, v, 0.0, NULL, NULL, NULL);CHKERRQ(ierr);} 76 } 77 if (isvtk) { 78 PetscSection section; 79 PetscViewerVTKFieldType ft; 80 PetscInt pStart, pEnd; 81 82 ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr); 83 ierr = DMPlexGetFieldType_Internal(dm, section, PETSC_DETERMINE, &pStart, &pEnd, &ft);CHKERRQ(ierr); 84 ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */ 85 ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr); /* viewer drops reference */ 86 ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr); 87 } else if (ishdf5) { 88 #if defined(PETSC_HAVE_HDF5) 89 ierr = VecView_Plex_Local_HDF5(v, viewer);CHKERRQ(ierr); 90 #else 91 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 92 #endif 93 } else { 94 if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);} 95 else {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);} 96 } 97 PetscFunctionReturn(0); 98 } 99 100 #undef __FUNCT__ 101 #define __FUNCT__ "VecView_Plex_Draw" 102 PetscErrorCode VecView_Plex_Draw(Vec v, PetscViewer viewer) 103 { 104 DM dm; 105 PetscDraw draw, popup; 106 DM cdm; 107 PetscSection coordSection; 108 Vec coordinates; 109 const PetscScalar *coords, *array; 110 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 111 PetscReal min, max; 112 PetscBool isnull; 113 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N, level; 114 const char *name; 115 PetscErrorCode ierr; 116 117 PetscFunctionBegin; 118 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 119 ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr); 120 if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim); 121 ierr = DMGetCoarsenLevel(dm, &level);CHKERRQ(ierr); 122 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 123 ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr); 124 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 125 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 126 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 127 128 ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr); 129 ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr); 130 if (isnull) PetscFunctionReturn(0); 131 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 132 ierr = PetscDrawSetTitle(draw, name);CHKERRQ(ierr); 133 134 ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr); 135 ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr); 136 for (c = 0; c < N; c += dim) { 137 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 138 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 139 } 140 ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr); 141 ierr = PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);CHKERRQ(ierr); 142 ierr = PetscDrawClear(draw);CHKERRQ(ierr); 143 144 ierr = VecMin(v, NULL, &min);CHKERRQ(ierr); 145 ierr = VecMax(v, NULL, &max);CHKERRQ(ierr); 146 ierr = PetscDrawGetPopup(draw, &popup);CHKERRQ(ierr); 147 ierr = PetscDrawScalePopup(popup, min, max);CHKERRQ(ierr); 148 149 ierr = VecGetArrayRead(v, &array);CHKERRQ(ierr); 150 for (c = cStart; c < cEnd; ++c) { 151 PetscScalar *coords = NULL, *a = NULL; 152 PetscInt numCoords, color; 153 154 ierr = DMPlexPointGlobalRead(dm, c, array, &a);CHKERRQ(ierr); 155 color = PetscDrawRealToColor(PetscRealPart(a[0]), min, max); 156 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 157 switch (numCoords) { 158 case 6: 159 ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color, color, color);CHKERRQ(ierr); 160 break; 161 case 8: 162 ierr = PetscDrawTriangle(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), color, color, color);CHKERRQ(ierr); 163 ierr = PetscDrawTriangle(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), color, color, color);CHKERRQ(ierr); 164 break; 165 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords); 166 } 167 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 168 } 169 ierr = VecRestoreArrayRead(v, &array);CHKERRQ(ierr); 170 ierr = PetscDrawFlush(draw);CHKERRQ(ierr); 171 ierr = PetscDrawPause(draw);CHKERRQ(ierr); 172 ierr = PetscDrawSave(draw);CHKERRQ(ierr); 173 PetscFunctionReturn(0); 174 } 175 176 #undef __FUNCT__ 177 #define __FUNCT__ "VecView_Plex" 178 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer) 179 { 180 DM dm; 181 PetscBool isvtk, ishdf5, isdraw, isseq; 182 PetscErrorCode ierr; 183 184 PetscFunctionBegin; 185 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 186 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 187 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 188 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 189 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);CHKERRQ(ierr); 190 ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr); 191 if (isvtk) { 192 Vec locv; 193 const char *name; 194 195 ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr); 196 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 197 ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr); 198 ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr); 199 ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr); 200 ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr); 201 ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr); 202 } else if (ishdf5) { 203 #if defined(PETSC_HAVE_HDF5) 204 ierr = VecView_Plex_HDF5(v, viewer);CHKERRQ(ierr); 205 #else 206 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 207 #endif 208 } else if (isdraw) { 209 ierr = VecView_Plex_Draw(v, viewer);CHKERRQ(ierr); 210 } else { 211 if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);} 212 else {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);} 213 } 214 PetscFunctionReturn(0); 215 } 216 217 #undef __FUNCT__ 218 #define __FUNCT__ "VecView_Plex_Native" 219 PetscErrorCode VecView_Plex_Native(Vec originalv, PetscViewer viewer) 220 { 221 DM dm; 222 MPI_Comm comm; 223 PetscViewerFormat format; 224 Vec v; 225 PetscBool isvtk, ishdf5; 226 PetscErrorCode ierr; 227 228 PetscFunctionBegin; 229 ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr); 230 ierr = PetscObjectGetComm((PetscObject) originalv, &comm);CHKERRQ(ierr); 231 if (!dm) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 232 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 233 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 234 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 235 if (format == PETSC_VIEWER_NATIVE) { 236 const char *vecname; 237 PetscInt n, nroots; 238 239 if (dm->sfNatural) { 240 ierr = VecGetLocalSize(originalv, &n);CHKERRQ(ierr); 241 ierr = PetscSFGetGraph(dm->sfNatural, &nroots, NULL, NULL, NULL);CHKERRQ(ierr); 242 if (n == nroots) { 243 ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr); 244 ierr = DMPlexGlobalToNaturalBegin(dm, originalv, v);CHKERRQ(ierr); 245 ierr = DMPlexGlobalToNaturalEnd(dm, originalv, v);CHKERRQ(ierr); 246 ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr); 247 ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr); 248 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "DM global to natural SF only handles global vectors"); 249 } else SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created"); 250 } else { 251 /* we are viewing a natural DMPlex vec. */ 252 v = originalv; 253 } 254 if (ishdf5) { 255 #if defined(PETSC_HAVE_HDF5) 256 ierr = VecView_Plex_HDF5_Native(v, viewer);CHKERRQ(ierr); 257 #else 258 SETERRQ(comm, PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 259 #endif 260 } else if (isvtk) { 261 SETERRQ(comm, PETSC_ERR_SUP, "VTK format does not support viewing in natural order. Please switch to HDF5."); 262 } else { 263 PetscBool isseq; 264 265 ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr); 266 if (isseq) {ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);} 267 else {ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);} 268 } 269 if (format == PETSC_VIEWER_NATIVE) {ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr);} 270 PetscFunctionReturn(0); 271 } 272 273 #undef __FUNCT__ 274 #define __FUNCT__ "VecLoad_Plex_Local" 275 PetscErrorCode VecLoad_Plex_Local(Vec v, PetscViewer viewer) 276 { 277 DM dm; 278 PetscBool ishdf5; 279 PetscErrorCode ierr; 280 281 PetscFunctionBegin; 282 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 283 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 284 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 285 if (ishdf5) { 286 DM dmBC; 287 Vec gv; 288 const char *name; 289 290 ierr = DMGetOutputDM(dm, &dmBC);CHKERRQ(ierr); 291 ierr = DMGetGlobalVector(dmBC, &gv);CHKERRQ(ierr); 292 ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr); 293 ierr = PetscObjectSetName((PetscObject) gv, name);CHKERRQ(ierr); 294 ierr = VecLoad_Default(gv, viewer);CHKERRQ(ierr); 295 ierr = DMGlobalToLocalBegin(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr); 296 ierr = DMGlobalToLocalEnd(dmBC, gv, INSERT_VALUES, v);CHKERRQ(ierr); 297 ierr = DMRestoreGlobalVector(dmBC, &gv);CHKERRQ(ierr); 298 } else { 299 ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr); 300 } 301 PetscFunctionReturn(0); 302 } 303 304 #undef __FUNCT__ 305 #define __FUNCT__ "VecLoad_Plex" 306 PetscErrorCode VecLoad_Plex(Vec v, PetscViewer viewer) 307 { 308 DM dm; 309 PetscBool ishdf5; 310 PetscErrorCode ierr; 311 312 PetscFunctionBegin; 313 ierr = VecGetDM(v, &dm);CHKERRQ(ierr); 314 if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 315 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 316 if (ishdf5) { 317 #if defined(PETSC_HAVE_HDF5) 318 ierr = VecLoad_Plex_HDF5(v, viewer);CHKERRQ(ierr); 319 #else 320 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 321 #endif 322 } else { 323 ierr = VecLoad_Default(v, viewer);CHKERRQ(ierr); 324 } 325 PetscFunctionReturn(0); 326 } 327 328 #undef __FUNCT__ 329 #define __FUNCT__ "VecLoad_Plex_Native" 330 PetscErrorCode VecLoad_Plex_Native(Vec originalv, PetscViewer viewer) 331 { 332 DM dm; 333 PetscViewerFormat format; 334 PetscBool ishdf5; 335 PetscErrorCode ierr; 336 337 PetscFunctionBegin; 338 ierr = VecGetDM(originalv, &dm);CHKERRQ(ierr); 339 if (!dm) SETERRQ(PetscObjectComm((PetscObject) originalv), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 340 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 341 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 342 if (format == PETSC_VIEWER_NATIVE) { 343 if (dm->sfNatural) { 344 if (ishdf5) { 345 #if defined(PETSC_HAVE_HDF5) 346 Vec v; 347 const char *vecname; 348 349 ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr); 350 ierr = PetscObjectGetName((PetscObject) originalv, &vecname);CHKERRQ(ierr); 351 ierr = PetscObjectSetName((PetscObject) v, vecname);CHKERRQ(ierr); 352 ierr = VecLoad_Plex_HDF5_Native(v, viewer);CHKERRQ(ierr); 353 ierr = DMPlexNaturalToGlobalBegin(dm, v, originalv);CHKERRQ(ierr); 354 ierr = DMPlexNaturalToGlobalEnd(dm, v, originalv);CHKERRQ(ierr); 355 ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr); 356 #else 357 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 358 #endif 359 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Reading in natural order is not supported for anything but HDF5."); 360 } 361 } 362 PetscFunctionReturn(0); 363 } 364 365 #undef __FUNCT__ 366 #define __FUNCT__ "DMPlexView_Ascii_Geometry" 367 PetscErrorCode DMPlexView_Ascii_Geometry(DM dm, PetscViewer viewer) 368 { 369 PetscSection coordSection; 370 Vec coordinates; 371 DMLabel depthLabel; 372 const char *name[4]; 373 const PetscScalar *a; 374 PetscInt dim, pStart, pEnd, cStart, cEnd, c; 375 PetscErrorCode ierr; 376 377 PetscFunctionBegin; 378 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 379 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 380 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 381 ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr); 382 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 383 ierr = PetscSectionGetChart(coordSection, &pStart, &pEnd);CHKERRQ(ierr); 384 ierr = VecGetArrayRead(coordinates, &a);CHKERRQ(ierr); 385 name[0] = "vertex"; 386 name[1] = "edge"; 387 name[dim-1] = "face"; 388 name[dim] = "cell"; 389 for (c = cStart; c < cEnd; ++c) { 390 PetscInt *closure = NULL; 391 PetscInt closureSize, cl; 392 393 ierr = PetscViewerASCIIPrintf(viewer, "Geometry for cell %D:\n", c);CHKERRQ(ierr); 394 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 395 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 396 for (cl = 0; cl < closureSize*2; cl += 2) { 397 PetscInt point = closure[cl], depth, dof, off, d, p; 398 399 if ((point < pStart) || (point >= pEnd)) continue; 400 ierr = PetscSectionGetDof(coordSection, point, &dof);CHKERRQ(ierr); 401 if (!dof) continue; 402 ierr = DMLabelGetValue(depthLabel, point, &depth);CHKERRQ(ierr); 403 ierr = PetscSectionGetOffset(coordSection, point, &off);CHKERRQ(ierr); 404 ierr = PetscViewerASCIIPrintf(viewer, "%s %D coords:", name[depth], point);CHKERRQ(ierr); 405 for (p = 0; p < dof/dim; ++p) { 406 ierr = PetscViewerASCIIPrintf(viewer, " (");CHKERRQ(ierr); 407 for (d = 0; d < dim; ++d) { 408 if (d > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);} 409 ierr = PetscViewerASCIIPrintf(viewer, "%g", PetscRealPart(a[off+p*dim+d]));CHKERRQ(ierr); 410 } 411 ierr = PetscViewerASCIIPrintf(viewer, ")");CHKERRQ(ierr); 412 } 413 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 414 } 415 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 416 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 417 } 418 ierr = VecRestoreArrayRead(coordinates, &a);CHKERRQ(ierr); 419 PetscFunctionReturn(0); 420 } 421 422 #undef __FUNCT__ 423 #define __FUNCT__ "DMPlexView_Ascii" 424 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer) 425 { 426 DM_Plex *mesh = (DM_Plex*) dm->data; 427 DM cdm; 428 DMLabel markers; 429 PetscSection coordSection; 430 Vec coordinates; 431 PetscViewerFormat format; 432 PetscErrorCode ierr; 433 434 PetscFunctionBegin; 435 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 436 ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr); 437 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 438 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 439 if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { 440 const char *name; 441 PetscInt maxConeSize, maxSupportSize; 442 PetscInt pStart, pEnd, p; 443 PetscMPIInt rank, size; 444 445 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr); 446 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr); 447 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 448 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 449 ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr); 450 ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr); 451 ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr); 452 ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr); 453 ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr); 454 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d] Max sizes cone: %D support: %D\n", rank,maxConeSize, maxSupportSize);CHKERRQ(ierr); 455 for (p = pStart; p < pEnd; ++p) { 456 PetscInt dof, off, s; 457 458 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 459 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 460 for (s = off; s < off+dof; ++s) { 461 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr); 462 } 463 } 464 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 465 ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr); 466 for (p = pStart; p < pEnd; ++p) { 467 PetscInt dof, off, c; 468 469 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 470 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 471 for (c = off; c < off+dof; ++c) { 472 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr); 473 } 474 } 475 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 476 ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr); 477 ierr = PetscSectionGetChart(coordSection, &pStart, NULL);CHKERRQ(ierr); 478 if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);} 479 ierr = DMGetLabel(dm, "marker", &markers);CHKERRQ(ierr); 480 ierr = DMLabelView(markers,viewer);CHKERRQ(ierr); 481 if (size > 1) { 482 PetscSF sf; 483 484 ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr); 485 ierr = PetscSFView(sf, viewer);CHKERRQ(ierr); 486 } 487 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 488 } else if (format == PETSC_VIEWER_ASCII_LATEX) { 489 const char *name, *color; 490 const char *defcolors[3] = {"gray", "orange", "green"}; 491 const char *deflcolors[4] = {"blue", "cyan", "red", "magenta"}; 492 PetscReal scale = 2.0; 493 PetscBool useNumbers = PETSC_TRUE, useLabels, useColors; 494 double tcoords[3]; 495 PetscScalar *coords; 496 PetscInt numLabels, l, numColors, numLColors, dim, depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p; 497 PetscMPIInt rank, size; 498 char **names, **colors, **lcolors; 499 500 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 501 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 502 ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr); 503 numLabels = PetscMax(numLabels, 10); 504 numColors = 10; 505 numLColors = 10; 506 ierr = PetscCalloc3(numLabels, &names, numColors, &colors, numLColors, &lcolors);CHKERRQ(ierr); 507 ierr = PetscOptionsGetReal(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_scale", &scale, NULL);CHKERRQ(ierr); 508 ierr = PetscOptionsGetBool(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_numbers", &useNumbers, NULL);CHKERRQ(ierr); 509 ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_labels", names, &numLabels, &useLabels);CHKERRQ(ierr); 510 if (!useLabels) numLabels = 0; 511 ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_colors", colors, &numColors, &useColors);CHKERRQ(ierr); 512 if (!useColors) { 513 numColors = 3; 514 for (c = 0; c < numColors; ++c) {ierr = PetscStrallocpy(defcolors[c], &colors[c]);CHKERRQ(ierr);} 515 } 516 ierr = PetscOptionsGetStringArray(((PetscObject) viewer)->options,((PetscObject) viewer)->prefix, "-dm_plex_view_lcolors", lcolors, &numLColors, &useColors);CHKERRQ(ierr); 517 if (!useColors) { 518 numLColors = 4; 519 for (c = 0; c < numLColors; ++c) {ierr = PetscStrallocpy(deflcolors[c], &lcolors[c]);CHKERRQ(ierr);} 520 } 521 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr); 522 ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr); 523 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 524 ierr = PetscViewerASCIIPrintf(viewer, "\ 525 \\documentclass[tikz]{standalone}\n\n\ 526 \\usepackage{pgflibraryshapes}\n\ 527 \\usetikzlibrary{backgrounds}\n\ 528 \\usetikzlibrary{arrows}\n\ 529 \\begin{document}\n");CHKERRQ(ierr); 530 if (size > 1) { 531 ierr = PetscViewerASCIIPrintf(viewer, "%s for process ", name);CHKERRQ(ierr); 532 for (p = 0; p < size; ++p) { 533 if (p > 0 && p == size-1) { 534 ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr); 535 } else if (p > 0) { 536 ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr); 537 } 538 ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr); 539 } 540 ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n");CHKERRQ(ierr); 541 } 542 ierr = PetscViewerASCIIPrintf(viewer, "\\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", 1.0);CHKERRQ(ierr); 543 /* Plot vertices */ 544 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 545 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 546 ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr); 547 for (v = vStart; v < vEnd; ++v) { 548 PetscInt off, dof, d; 549 PetscBool isLabeled = PETSC_FALSE; 550 551 ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr); 552 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 553 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\path (");CHKERRQ(ierr); 554 if (PetscUnlikely(dof > 3)) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"coordSection vertex %D has dof %D > 3",v,dof); 555 for (d = 0; d < dof; ++d) { 556 tcoords[d] = (double) (scale*PetscRealPart(coords[off+d])); 557 tcoords[d] = PetscAbsReal(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 558 } 559 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 560 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 561 for (d = 0; d < dof; ++d) { 562 if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);} 563 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", tcoords[d]);CHKERRQ(ierr); 564 } 565 color = colors[rank%numColors]; 566 for (l = 0; l < numLabels; ++l) { 567 PetscInt val; 568 ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr); 569 if (val >= 0) {color = lcolors[l%numLColors]; isLabeled = PETSC_TRUE; break;} 570 } 571 if (useNumbers) { 572 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D};\n", v, rank, color, v);CHKERRQ(ierr); 573 } else { 574 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [fill,inner sep=%dpt,shape=circle,color=%s] {};\n", v, rank, !isLabeled ? 1 : 2, color);CHKERRQ(ierr); 575 } 576 } 577 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 578 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 579 /* Plot edges */ 580 if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);} 581 if (dim < 3 && useNumbers) { 582 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 583 ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr); 584 for (e = eStart; e < eEnd; ++e) { 585 const PetscInt *cone; 586 PetscInt coneSize, offA, offB, dof, d; 587 588 ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr); 589 if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize); 590 ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr); 591 ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr); 592 ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr); 593 ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr); 594 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr); 595 for (d = 0; d < dof; ++d) { 596 tcoords[d] = (double) (scale*PetscRealPart(coords[offA+d]+coords[offB+d])); 597 tcoords[d] = PetscAbsReal(tcoords[d]) < 1e-10 ? 0.0 : tcoords[d]; 598 } 599 /* Rotate coordinates since PGF makes z point out of the page instead of up */ 600 if (dim == 3) {PetscReal tmp = tcoords[1]; tcoords[1] = tcoords[2]; tcoords[2] = -tmp;} 601 for (d = 0; d < dof; ++d) { 602 if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);} 603 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%g", (double)tcoords[d]);CHKERRQ(ierr); 604 } 605 color = colors[rank%numColors]; 606 for (l = 0; l < numLabels; ++l) { 607 PetscInt val; 608 ierr = DMGetLabelValue(dm, names[l], v, &val);CHKERRQ(ierr); 609 if (val >= 0) {color = lcolors[l%numLColors]; break;} 610 } 611 ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%d) [draw,shape=circle,color=%s] {%D} --\n", e, rank, color, e);CHKERRQ(ierr); 612 } 613 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 614 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 615 ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr); 616 } 617 /* Plot cells */ 618 if (dim == 3 || !useNumbers) { 619 for (e = eStart; e < eEnd; ++e) { 620 const PetscInt *cone; 621 622 color = colors[rank%numColors]; 623 for (l = 0; l < numLabels; ++l) { 624 PetscInt val; 625 ierr = DMGetLabelValue(dm, names[l], e, &val);CHKERRQ(ierr); 626 if (val >= 0) {color = lcolors[l%numLColors]; break;} 627 } 628 ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr); 629 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] (%D_%d) -- (%D_%d);\n", color, cone[0], rank, cone[1], rank);CHKERRQ(ierr); 630 } 631 } else { 632 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 633 for (c = cStart; c < cEnd; ++c) { 634 PetscInt *closure = NULL; 635 PetscInt closureSize, firstPoint = -1; 636 637 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 638 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr); 639 for (p = 0; p < closureSize*2; p += 2) { 640 const PetscInt point = closure[p]; 641 642 if ((point < vStart) || (point >= vEnd)) continue; 643 if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);} 644 ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%d)", point, rank);CHKERRQ(ierr); 645 if (firstPoint < 0) firstPoint = point; 646 } 647 /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */ 648 ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%d);\n", firstPoint, rank);CHKERRQ(ierr); 649 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 650 } 651 } 652 ierr = PetscViewerFlush(viewer);CHKERRQ(ierr); 653 ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr); 654 ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n");CHKERRQ(ierr); 655 ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr); 656 for (l = 0; l < numLabels; ++l) {ierr = PetscFree(names[l]);CHKERRQ(ierr);} 657 for (c = 0; c < numColors; ++c) {ierr = PetscFree(colors[c]);CHKERRQ(ierr);} 658 for (c = 0; c < numLColors; ++c) {ierr = PetscFree(lcolors[c]);CHKERRQ(ierr);} 659 ierr = PetscFree3(names, colors, lcolors);CHKERRQ(ierr); 660 } else { 661 MPI_Comm comm; 662 PetscInt *sizes, *hybsizes; 663 PetscInt locDepth, depth, dim, d, pMax[4]; 664 PetscInt pStart, pEnd, p; 665 PetscInt numLabels, l; 666 const char *name; 667 PetscMPIInt size; 668 669 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 670 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 671 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 672 ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr); 673 if (name) {ierr = PetscViewerASCIIPrintf(viewer, "%s in %D dimensions:\n", name, dim);CHKERRQ(ierr);} 674 else {ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);} 675 ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr); 676 ierr = MPIU_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr); 677 ierr = DMPlexGetHybridBounds(dm, &pMax[depth], depth > 0 ? &pMax[depth-1] : NULL, &pMax[1], &pMax[0]);CHKERRQ(ierr); 678 ierr = PetscMalloc2(size,&sizes,size,&hybsizes);CHKERRQ(ierr); 679 if (depth == 1) { 680 ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr); 681 pEnd = pEnd - pStart; 682 ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 683 ierr = PetscViewerASCIIPrintf(viewer, " %d-cells:", 0);CHKERRQ(ierr); 684 for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);} 685 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 686 ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr); 687 pEnd = pEnd - pStart; 688 ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 689 ierr = PetscViewerASCIIPrintf(viewer, " %D-cells:", dim);CHKERRQ(ierr); 690 for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);} 691 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 692 } else { 693 for (d = 0; d <= dim; d++) { 694 ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr); 695 pEnd -= pStart; 696 pMax[d] -= pStart; 697 ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 698 ierr = MPI_Gather(&pMax[d], 1, MPIU_INT, hybsizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr); 699 ierr = PetscViewerASCIIPrintf(viewer, " %D-cells:", d);CHKERRQ(ierr); 700 for (p = 0; p < size; ++p) { 701 if (hybsizes[p] >= 0) {ierr = PetscViewerASCIIPrintf(viewer, " %D (%D)", sizes[p], sizes[p] - hybsizes[p]);CHKERRQ(ierr);} 702 else {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);} 703 } 704 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 705 } 706 } 707 ierr = PetscFree2(sizes,hybsizes);CHKERRQ(ierr); 708 ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr); 709 if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);} 710 for (l = 0; l < numLabels; ++l) { 711 DMLabel label; 712 const char *name; 713 IS valueIS; 714 const PetscInt *values; 715 PetscInt numValues, v; 716 717 ierr = DMGetLabelName(dm, l, &name);CHKERRQ(ierr); 718 ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr); 719 ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr); 720 ierr = PetscViewerASCIIPrintf(viewer, " %s: %D strata of sizes (", name, numValues);CHKERRQ(ierr); 721 ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr); 722 ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr); 723 ierr = PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);CHKERRQ(ierr); 724 for (v = 0; v < numValues; ++v) { 725 PetscInt size; 726 727 ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr); 728 if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);} 729 ierr = PetscViewerASCIIPrintf(viewer, "%D", size);CHKERRQ(ierr); 730 } 731 ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr); 732 ierr = PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);CHKERRQ(ierr); 733 ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr); 734 ierr = ISDestroy(&valueIS);CHKERRQ(ierr); 735 } 736 ierr = DMGetCoarseDM(dm, &cdm);CHKERRQ(ierr); 737 if (cdm) { 738 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 739 ierr = DMPlexView_Ascii(cdm, viewer);CHKERRQ(ierr); 740 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 741 } 742 } 743 PetscFunctionReturn(0); 744 } 745 746 #undef __FUNCT__ 747 #define __FUNCT__ "DMPlexView_Draw" 748 PetscErrorCode DMPlexView_Draw(DM dm, PetscViewer viewer) 749 { 750 PetscDraw draw; 751 DM cdm; 752 PetscSection coordSection; 753 Vec coordinates; 754 const PetscScalar *coords; 755 PetscReal bound[4] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 756 PetscBool isnull; 757 PetscInt dim, vStart, vEnd, cStart, cEnd, c, N; 758 PetscErrorCode ierr; 759 760 PetscFunctionBegin; 761 ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr); 762 if (dim != 2) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Cannot draw meshes of dimension %D", dim); 763 ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr); 764 ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr); 765 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 766 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 767 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 768 769 ierr = PetscViewerDrawGetDraw(viewer, 0, &draw);CHKERRQ(ierr); 770 ierr = PetscDrawIsNull(draw, &isnull);CHKERRQ(ierr); 771 if (isnull) PetscFunctionReturn(0); 772 ierr = PetscDrawSetTitle(draw, "Mesh");CHKERRQ(ierr); 773 774 ierr = VecGetLocalSize(coordinates, &N);CHKERRQ(ierr); 775 ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr); 776 for (c = 0; c < N; c += dim) { 777 bound[0] = PetscMin(bound[0], PetscRealPart(coords[c])); bound[2] = PetscMax(bound[2], PetscRealPart(coords[c])); 778 bound[1] = PetscMin(bound[1], PetscRealPart(coords[c+1])); bound[3] = PetscMax(bound[3], PetscRealPart(coords[c+1])); 779 } 780 ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr); 781 ierr = PetscDrawSetCoordinates(draw, bound[0], bound[1], bound[2], bound[3]);CHKERRQ(ierr); 782 ierr = PetscDrawClear(draw);CHKERRQ(ierr); 783 784 for (c = cStart; c < cEnd; ++c) { 785 PetscScalar *coords = NULL; 786 PetscInt numCoords; 787 788 ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 789 switch (numCoords) { 790 case 6: 791 ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 792 ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 793 ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 794 break; 795 case 8: 796 ierr = PetscDrawLine(draw, PetscRealPart(coords[0]), PetscRealPart(coords[1]), PetscRealPart(coords[2]), PetscRealPart(coords[3]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 797 ierr = PetscDrawLine(draw, PetscRealPart(coords[2]), PetscRealPart(coords[3]), PetscRealPart(coords[4]), PetscRealPart(coords[5]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 798 ierr = PetscDrawLine(draw, PetscRealPart(coords[4]), PetscRealPart(coords[5]), PetscRealPart(coords[6]), PetscRealPart(coords[7]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 799 ierr = PetscDrawLine(draw, PetscRealPart(coords[6]), PetscRealPart(coords[7]), PetscRealPart(coords[0]), PetscRealPart(coords[1]), PETSC_DRAW_BLACK);CHKERRQ(ierr); 800 break; 801 default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot draw cells with %D coordinates", numCoords); 802 } 803 ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, c, &numCoords, &coords);CHKERRQ(ierr); 804 } 805 ierr = PetscDrawFlush(draw);CHKERRQ(ierr); 806 ierr = PetscDrawPause(draw);CHKERRQ(ierr); 807 ierr = PetscDrawSave(draw);CHKERRQ(ierr); 808 PetscFunctionReturn(0); 809 } 810 811 #undef __FUNCT__ 812 #define __FUNCT__ "DMView_Plex" 813 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer) 814 { 815 PetscBool iascii, ishdf5, isvtk, isdraw; 816 PetscErrorCode ierr; 817 818 PetscFunctionBegin; 819 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 820 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 821 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 822 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr); 823 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 824 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERDRAW, &isdraw);CHKERRQ(ierr); 825 if (iascii) { 826 ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr); 827 } else if (ishdf5) { 828 #if defined(PETSC_HAVE_HDF5) 829 ierr = PetscViewerPushFormat(viewer, PETSC_VIEWER_HDF5_VIZ);CHKERRQ(ierr); 830 ierr = DMPlexView_HDF5(dm, viewer);CHKERRQ(ierr); 831 ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr); 832 #else 833 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 834 #endif 835 } else if (isvtk) { 836 ierr = DMPlexVTKWriteAll((PetscObject) dm,viewer);CHKERRQ(ierr); 837 } else if (isdraw) { 838 ierr = DMPlexView_Draw(dm, viewer);CHKERRQ(ierr); 839 } 840 PetscFunctionReturn(0); 841 } 842 843 #undef __FUNCT__ 844 #define __FUNCT__ "DMLoad_Plex" 845 PetscErrorCode DMLoad_Plex(DM dm, PetscViewer viewer) 846 { 847 PetscBool isbinary, ishdf5; 848 PetscErrorCode ierr; 849 850 PetscFunctionBegin; 851 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 852 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 853 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr); 854 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr); 855 if (isbinary) {SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Do not yet support binary viewers");} 856 else if (ishdf5) { 857 #if defined(PETSC_HAVE_HDF5) 858 ierr = DMPlexLoad_HDF5(dm, viewer);CHKERRQ(ierr); 859 #else 860 SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "HDF5 not supported in this build.\nPlease reconfigure using --download-hdf5"); 861 #endif 862 } 863 PetscFunctionReturn(0); 864 } 865 866 867 #undef __FUNCT__ 868 #define __FUNCT__ "DMDestroy_Plex" 869 PetscErrorCode DMDestroy_Plex(DM dm) 870 { 871 DM_Plex *mesh = (DM_Plex*) dm->data; 872 PetscErrorCode ierr; 873 874 PetscFunctionBegin; 875 if (--mesh->refct > 0) PetscFunctionReturn(0); 876 ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr); 877 ierr = PetscFree(mesh->cones);CHKERRQ(ierr); 878 ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr); 879 ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr); 880 ierr = PetscSectionDestroy(&mesh->subdomainSection);CHKERRQ(ierr); 881 ierr = PetscFree(mesh->supports);CHKERRQ(ierr); 882 ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr); 883 ierr = PetscFree(mesh->tetgenOpts);CHKERRQ(ierr); 884 ierr = PetscFree(mesh->triangleOpts);CHKERRQ(ierr); 885 ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr); 886 ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr); 887 ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr); 888 ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr); 889 ierr = PetscSectionDestroy(&mesh->anchorSection);CHKERRQ(ierr); 890 ierr = ISDestroy(&mesh->anchorIS);CHKERRQ(ierr); 891 ierr = PetscSectionDestroy(&mesh->parentSection);CHKERRQ(ierr); 892 ierr = PetscFree(mesh->parents);CHKERRQ(ierr); 893 ierr = PetscFree(mesh->childIDs);CHKERRQ(ierr); 894 ierr = PetscSectionDestroy(&mesh->childSection);CHKERRQ(ierr); 895 ierr = PetscFree(mesh->children);CHKERRQ(ierr); 896 ierr = DMDestroy(&mesh->referenceTree);CHKERRQ(ierr); 897 ierr = PetscGridHashDestroy(&mesh->lbox);CHKERRQ(ierr); 898 /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */ 899 ierr = PetscFree(mesh);CHKERRQ(ierr); 900 ierr = PetscObjectComposeFunction((PetscObject)dm,"DMAdaptLabel_C",NULL);CHKERRQ(ierr); 901 PetscFunctionReturn(0); 902 } 903 904 #undef __FUNCT__ 905 #define __FUNCT__ "DMCreateMatrix_Plex" 906 PetscErrorCode DMCreateMatrix_Plex(DM dm, Mat *J) 907 { 908 PetscSection sectionGlobal; 909 PetscInt bs = -1, mbs; 910 PetscInt localSize; 911 PetscBool isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isMatIS; 912 PetscErrorCode ierr; 913 MatType mtype; 914 ISLocalToGlobalMapping ltog; 915 916 PetscFunctionBegin; 917 ierr = MatInitializePackage();CHKERRQ(ierr); 918 mtype = dm->mattype; 919 ierr = DMGetDefaultGlobalSection(dm, §ionGlobal);CHKERRQ(ierr); 920 /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */ 921 ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); 922 ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr); 923 ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 924 ierr = MatSetType(*J, mtype);CHKERRQ(ierr); 925 ierr = MatSetFromOptions(*J);CHKERRQ(ierr); 926 ierr = MatGetBlockSize(*J, &mbs);CHKERRQ(ierr); 927 if (mbs > 1) bs = mbs; 928 ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr); 929 ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr); 930 ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr); 931 ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr); 932 ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr); 933 ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr); 934 ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr); 935 ierr = PetscStrcmp(mtype, MATIS, &isMatIS);CHKERRQ(ierr); 936 if (!isShell) { 937 PetscSection subSection; 938 PetscBool fillMatrix = (PetscBool)(!dm->prealloc_only && !isMatIS); 939 PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin, *ltogidx, lsize; 940 PetscInt pStart, pEnd, p, dof, cdof; 941 942 /* Set localtoglobalmapping on the matrix for MatSetValuesLocal() to work (it also creates the local matrices in case of MATIS) */ 943 if (isMatIS) { /* need a different l2g map than the one computed by DMGetLocalToGlobalMapping */ 944 PetscSection section; 945 PetscInt size; 946 947 ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr); 948 ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr); 949 ierr = PetscMalloc1(size,<ogidx);CHKERRQ(ierr); 950 ierr = DMPlexGetSubdomainSection(dm, &subSection);CHKERRQ(ierr); 951 } else { 952 ierr = DMGetLocalToGlobalMapping(dm,<og);CHKERRQ(ierr); 953 } 954 ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr); 955 for (p = pStart, lsize = 0; p < pEnd; ++p) { 956 PetscInt bdof; 957 958 ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr); 959 ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr); 960 dof = dof < 0 ? -(dof+1) : dof; 961 bdof = cdof && (dof-cdof) ? 1 : dof; 962 if (dof) { 963 if (bs < 0) {bs = bdof;} 964 else if (bs != bdof) {bs = 1; if (!isMatIS) break;} 965 } 966 if (isMatIS) { 967 PetscInt loff,c,off; 968 ierr = PetscSectionGetOffset(subSection, p, &loff);CHKERRQ(ierr); 969 ierr = PetscSectionGetOffset(sectionGlobal, p, &off);CHKERRQ(ierr); 970 for (c = 0; c < dof-cdof; ++c, ++lsize) ltogidx[loff+c] = off > -1 ? off+c : -(off+1)+c; 971 } 972 } 973 /* Must have same blocksize on all procs (some might have no points) */ 974 bsLocal = bs; 975 ierr = MPIU_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 976 bsLocal = bs < 0 ? bsMax : bs; 977 ierr = MPIU_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 978 if (bsMin != bsMax) {bs = 1;} 979 else {bs = bsMax;} 980 if (isMatIS) { 981 ierr = ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs < 0 ? 1 : bs, lsize, ltogidx, PETSC_OWN_POINTER, <og);CHKERRQ(ierr); 982 } 983 ierr = MatSetLocalToGlobalMapping(*J,ltog,ltog);CHKERRQ(ierr); 984 if (isMatIS) { 985 ierr = ISLocalToGlobalMappingDestroy(<og);CHKERRQ(ierr); 986 } 987 ierr = PetscCalloc4(localSize/bs, &dnz, localSize/bs, &onz, localSize/bs, &dnzu, localSize/bs, &onzu);CHKERRQ(ierr); 988 ierr = DMPlexPreallocateOperator(dm, bs, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr); 989 ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr); 990 } 991 PetscFunctionReturn(0); 992 } 993 994 #undef __FUNCT__ 995 #define __FUNCT__ "DMPlexGetSubdomainSection" 996 /* 997 DMPlexGetSubdomainGlobalSection - Returns the section associated with the subdomain 998 999 Not collective 1000 1001 Input Parameter: 1002 . mesh - The DMPlex 1003 1004 Output Parameters: 1005 . subsection - The subdomain section 1006 1007 Level: developer 1008 1009 .seealso: 1010 */ 1011 PetscErrorCode DMPlexGetSubdomainSection(DM dm, PetscSection *subsection) 1012 { 1013 DM_Plex *mesh = (DM_Plex*) dm->data; 1014 PetscErrorCode ierr; 1015 1016 PetscFunctionBegin; 1017 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1018 if (!mesh->subdomainSection) { 1019 PetscSection section; 1020 PetscSF sf; 1021 1022 ierr = PetscSFCreate(PETSC_COMM_SELF,&sf);CHKERRQ(ierr); 1023 ierr = DMGetDefaultSection(dm,§ion);CHKERRQ(ierr); 1024 ierr = PetscSectionCreateGlobalSection(section,sf,PETSC_FALSE,PETSC_TRUE,&mesh->subdomainSection);CHKERRQ(ierr); 1025 ierr = PetscSFDestroy(&sf);CHKERRQ(ierr); 1026 } 1027 *subsection = mesh->subdomainSection; 1028 PetscFunctionReturn(0); 1029 } 1030 1031 #undef __FUNCT__ 1032 #define __FUNCT__ "DMPlexGetChart" 1033 /*@ 1034 DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd) 1035 1036 Not collective 1037 1038 Input Parameter: 1039 . mesh - The DMPlex 1040 1041 Output Parameters: 1042 + pStart - The first mesh point 1043 - pEnd - The upper bound for mesh points 1044 1045 Level: beginner 1046 1047 .seealso: DMPlexCreate(), DMPlexSetChart() 1048 @*/ 1049 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd) 1050 { 1051 DM_Plex *mesh = (DM_Plex*) dm->data; 1052 PetscErrorCode ierr; 1053 1054 PetscFunctionBegin; 1055 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1056 ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr); 1057 PetscFunctionReturn(0); 1058 } 1059 1060 #undef __FUNCT__ 1061 #define __FUNCT__ "DMPlexSetChart" 1062 /*@ 1063 DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd) 1064 1065 Not collective 1066 1067 Input Parameters: 1068 + mesh - The DMPlex 1069 . pStart - The first mesh point 1070 - pEnd - The upper bound for mesh points 1071 1072 Output Parameters: 1073 1074 Level: beginner 1075 1076 .seealso: DMPlexCreate(), DMPlexGetChart() 1077 @*/ 1078 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd) 1079 { 1080 DM_Plex *mesh = (DM_Plex*) dm->data; 1081 PetscErrorCode ierr; 1082 1083 PetscFunctionBegin; 1084 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1085 ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr); 1086 ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr); 1087 PetscFunctionReturn(0); 1088 } 1089 1090 #undef __FUNCT__ 1091 #define __FUNCT__ "DMPlexGetConeSize" 1092 /*@ 1093 DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG 1094 1095 Not collective 1096 1097 Input Parameters: 1098 + mesh - The DMPlex 1099 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1100 1101 Output Parameter: 1102 . size - The cone size for point p 1103 1104 Level: beginner 1105 1106 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart() 1107 @*/ 1108 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size) 1109 { 1110 DM_Plex *mesh = (DM_Plex*) dm->data; 1111 PetscErrorCode ierr; 1112 1113 PetscFunctionBegin; 1114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1115 PetscValidPointer(size, 3); 1116 ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr); 1117 PetscFunctionReturn(0); 1118 } 1119 1120 #undef __FUNCT__ 1121 #define __FUNCT__ "DMPlexSetConeSize" 1122 /*@ 1123 DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG 1124 1125 Not collective 1126 1127 Input Parameters: 1128 + mesh - The DMPlex 1129 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1130 - size - The cone size for point p 1131 1132 Output Parameter: 1133 1134 Note: 1135 This should be called after DMPlexSetChart(). 1136 1137 Level: beginner 1138 1139 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart() 1140 @*/ 1141 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size) 1142 { 1143 DM_Plex *mesh = (DM_Plex*) dm->data; 1144 PetscErrorCode ierr; 1145 1146 PetscFunctionBegin; 1147 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1148 ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr); 1149 1150 mesh->maxConeSize = PetscMax(mesh->maxConeSize, size); 1151 PetscFunctionReturn(0); 1152 } 1153 1154 #undef __FUNCT__ 1155 #define __FUNCT__ "DMPlexAddConeSize" 1156 /*@ 1157 DMPlexAddConeSize - Add the given number of in-edges to this point in the Sieve DAG 1158 1159 Not collective 1160 1161 Input Parameters: 1162 + mesh - The DMPlex 1163 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1164 - size - The additional cone size for point p 1165 1166 Output Parameter: 1167 1168 Note: 1169 This should be called after DMPlexSetChart(). 1170 1171 Level: beginner 1172 1173 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexGetConeSize(), DMPlexSetChart() 1174 @*/ 1175 PetscErrorCode DMPlexAddConeSize(DM dm, PetscInt p, PetscInt size) 1176 { 1177 DM_Plex *mesh = (DM_Plex*) dm->data; 1178 PetscInt csize; 1179 PetscErrorCode ierr; 1180 1181 PetscFunctionBegin; 1182 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1183 ierr = PetscSectionAddDof(mesh->coneSection, p, size);CHKERRQ(ierr); 1184 ierr = PetscSectionGetDof(mesh->coneSection, p, &csize);CHKERRQ(ierr); 1185 1186 mesh->maxConeSize = PetscMax(mesh->maxConeSize, csize); 1187 PetscFunctionReturn(0); 1188 } 1189 1190 #undef __FUNCT__ 1191 #define __FUNCT__ "DMPlexGetCone" 1192 /*@C 1193 DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG 1194 1195 Not collective 1196 1197 Input Parameters: 1198 + mesh - The DMPlex 1199 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1200 1201 Output Parameter: 1202 . cone - An array of points which are on the in-edges for point p 1203 1204 Level: beginner 1205 1206 Fortran Notes: 1207 Since it returns an array, this routine is only available in Fortran 90, and you must 1208 include petsc.h90 in your code. 1209 1210 You must also call DMPlexRestoreCone() after you finish using the returned array. 1211 1212 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart() 1213 @*/ 1214 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[]) 1215 { 1216 DM_Plex *mesh = (DM_Plex*) dm->data; 1217 PetscInt off; 1218 PetscErrorCode ierr; 1219 1220 PetscFunctionBegin; 1221 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1222 PetscValidPointer(cone, 3); 1223 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 1224 *cone = &mesh->cones[off]; 1225 PetscFunctionReturn(0); 1226 } 1227 1228 #undef __FUNCT__ 1229 #define __FUNCT__ "DMPlexSetCone" 1230 /*@ 1231 DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG 1232 1233 Not collective 1234 1235 Input Parameters: 1236 + mesh - The DMPlex 1237 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1238 - cone - An array of points which are on the in-edges for point p 1239 1240 Output Parameter: 1241 1242 Note: 1243 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 1244 1245 Level: beginner 1246 1247 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 1248 @*/ 1249 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[]) 1250 { 1251 DM_Plex *mesh = (DM_Plex*) dm->data; 1252 PetscInt pStart, pEnd; 1253 PetscInt dof, off, c; 1254 PetscErrorCode ierr; 1255 1256 PetscFunctionBegin; 1257 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1258 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 1259 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 1260 if (dof) PetscValidPointer(cone, 3); 1261 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 1262 if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 1263 for (c = 0; c < dof; ++c) { 1264 if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd); 1265 mesh->cones[off+c] = cone[c]; 1266 } 1267 PetscFunctionReturn(0); 1268 } 1269 1270 #undef __FUNCT__ 1271 #define __FUNCT__ "DMPlexGetConeOrientation" 1272 /*@C 1273 DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG 1274 1275 Not collective 1276 1277 Input Parameters: 1278 + mesh - The DMPlex 1279 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1280 1281 Output Parameter: 1282 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 1283 integer giving the prescription for cone traversal. If it is negative, the cone is 1284 traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives 1285 the index of the cone point on which to start. 1286 1287 Level: beginner 1288 1289 Fortran Notes: 1290 Since it returns an array, this routine is only available in Fortran 90, and you must 1291 include petsc.h90 in your code. 1292 1293 You must also call DMPlexRestoreConeOrientation() after you finish using the returned array. 1294 1295 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart() 1296 @*/ 1297 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[]) 1298 { 1299 DM_Plex *mesh = (DM_Plex*) dm->data; 1300 PetscInt off; 1301 PetscErrorCode ierr; 1302 1303 PetscFunctionBegin; 1304 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1305 #if defined(PETSC_USE_DEBUG) 1306 { 1307 PetscInt dof; 1308 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 1309 if (dof) PetscValidPointer(coneOrientation, 3); 1310 } 1311 #endif 1312 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 1313 1314 *coneOrientation = &mesh->coneOrientations[off]; 1315 PetscFunctionReturn(0); 1316 } 1317 1318 #undef __FUNCT__ 1319 #define __FUNCT__ "DMPlexSetConeOrientation" 1320 /*@ 1321 DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG 1322 1323 Not collective 1324 1325 Input Parameters: 1326 + mesh - The DMPlex 1327 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1328 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an 1329 integer giving the prescription for cone traversal. If it is negative, the cone is 1330 traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives 1331 the index of the cone point on which to start. 1332 1333 Output Parameter: 1334 1335 Note: 1336 This should be called after all calls to DMPlexSetConeSize() and DMSetUp(). 1337 1338 Level: beginner 1339 1340 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp() 1341 @*/ 1342 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[]) 1343 { 1344 DM_Plex *mesh = (DM_Plex*) dm->data; 1345 PetscInt pStart, pEnd; 1346 PetscInt dof, off, c; 1347 PetscErrorCode ierr; 1348 1349 PetscFunctionBegin; 1350 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1351 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 1352 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 1353 if (dof) PetscValidPointer(coneOrientation, 3); 1354 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 1355 if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 1356 for (c = 0; c < dof; ++c) { 1357 PetscInt cdof, o = coneOrientation[c]; 1358 1359 ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr); 1360 if (o && ((o < -(cdof+1)) || (o >= cdof))) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof); 1361 mesh->coneOrientations[off+c] = o; 1362 } 1363 PetscFunctionReturn(0); 1364 } 1365 1366 #undef __FUNCT__ 1367 #define __FUNCT__ "DMPlexInsertCone" 1368 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint) 1369 { 1370 DM_Plex *mesh = (DM_Plex*) dm->data; 1371 PetscInt pStart, pEnd; 1372 PetscInt dof, off; 1373 PetscErrorCode ierr; 1374 1375 PetscFunctionBegin; 1376 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1377 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 1378 if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 1379 if ((conePoint < pStart) || (conePoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd); 1380 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 1381 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 1382 if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof); 1383 mesh->cones[off+conePos] = conePoint; 1384 PetscFunctionReturn(0); 1385 } 1386 1387 #undef __FUNCT__ 1388 #define __FUNCT__ "DMPlexInsertConeOrientation" 1389 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation) 1390 { 1391 DM_Plex *mesh = (DM_Plex*) dm->data; 1392 PetscInt pStart, pEnd; 1393 PetscInt dof, off; 1394 PetscErrorCode ierr; 1395 1396 PetscFunctionBegin; 1397 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1398 ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr); 1399 if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 1400 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 1401 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 1402 if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof); 1403 mesh->coneOrientations[off+conePos] = coneOrientation; 1404 PetscFunctionReturn(0); 1405 } 1406 1407 #undef __FUNCT__ 1408 #define __FUNCT__ "DMPlexGetSupportSize" 1409 /*@ 1410 DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG 1411 1412 Not collective 1413 1414 Input Parameters: 1415 + mesh - The DMPlex 1416 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1417 1418 Output Parameter: 1419 . size - The support size for point p 1420 1421 Level: beginner 1422 1423 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize() 1424 @*/ 1425 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size) 1426 { 1427 DM_Plex *mesh = (DM_Plex*) dm->data; 1428 PetscErrorCode ierr; 1429 1430 PetscFunctionBegin; 1431 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1432 PetscValidPointer(size, 3); 1433 ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr); 1434 PetscFunctionReturn(0); 1435 } 1436 1437 #undef __FUNCT__ 1438 #define __FUNCT__ "DMPlexSetSupportSize" 1439 /*@ 1440 DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG 1441 1442 Not collective 1443 1444 Input Parameters: 1445 + mesh - The DMPlex 1446 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1447 - size - The support size for point p 1448 1449 Output Parameter: 1450 1451 Note: 1452 This should be called after DMPlexSetChart(). 1453 1454 Level: beginner 1455 1456 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart() 1457 @*/ 1458 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size) 1459 { 1460 DM_Plex *mesh = (DM_Plex*) dm->data; 1461 PetscErrorCode ierr; 1462 1463 PetscFunctionBegin; 1464 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1465 ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr); 1466 1467 mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size); 1468 PetscFunctionReturn(0); 1469 } 1470 1471 #undef __FUNCT__ 1472 #define __FUNCT__ "DMPlexGetSupport" 1473 /*@C 1474 DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG 1475 1476 Not collective 1477 1478 Input Parameters: 1479 + mesh - The DMPlex 1480 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1481 1482 Output Parameter: 1483 . support - An array of points which are on the out-edges for point p 1484 1485 Level: beginner 1486 1487 Fortran Notes: 1488 Since it returns an array, this routine is only available in Fortran 90, and you must 1489 include petsc.h90 in your code. 1490 1491 You must also call DMPlexRestoreSupport() after you finish using the returned array. 1492 1493 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 1494 @*/ 1495 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[]) 1496 { 1497 DM_Plex *mesh = (DM_Plex*) dm->data; 1498 PetscInt off; 1499 PetscErrorCode ierr; 1500 1501 PetscFunctionBegin; 1502 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1503 PetscValidPointer(support, 3); 1504 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 1505 *support = &mesh->supports[off]; 1506 PetscFunctionReturn(0); 1507 } 1508 1509 #undef __FUNCT__ 1510 #define __FUNCT__ "DMPlexSetSupport" 1511 /*@ 1512 DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG 1513 1514 Not collective 1515 1516 Input Parameters: 1517 + mesh - The DMPlex 1518 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1519 - support - An array of points which are on the in-edges for point p 1520 1521 Output Parameter: 1522 1523 Note: 1524 This should be called after all calls to DMPlexSetSupportSize() and DMSetUp(). 1525 1526 Level: beginner 1527 1528 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp() 1529 @*/ 1530 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[]) 1531 { 1532 DM_Plex *mesh = (DM_Plex*) dm->data; 1533 PetscInt pStart, pEnd; 1534 PetscInt dof, off, c; 1535 PetscErrorCode ierr; 1536 1537 PetscFunctionBegin; 1538 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1539 ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr); 1540 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 1541 if (dof) PetscValidPointer(support, 3); 1542 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 1543 if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 1544 for (c = 0; c < dof; ++c) { 1545 if ((support[c] < pStart) || (support[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd); 1546 mesh->supports[off+c] = support[c]; 1547 } 1548 PetscFunctionReturn(0); 1549 } 1550 1551 #undef __FUNCT__ 1552 #define __FUNCT__ "DMPlexInsertSupport" 1553 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint) 1554 { 1555 DM_Plex *mesh = (DM_Plex*) dm->data; 1556 PetscInt pStart, pEnd; 1557 PetscInt dof, off; 1558 PetscErrorCode ierr; 1559 1560 PetscFunctionBegin; 1561 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1562 ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr); 1563 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 1564 ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr); 1565 if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd); 1566 if ((supportPoint < pStart) || (supportPoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd); 1567 if (supportPos >= dof) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof); 1568 mesh->supports[off+supportPos] = supportPoint; 1569 PetscFunctionReturn(0); 1570 } 1571 1572 #undef __FUNCT__ 1573 #define __FUNCT__ "DMPlexGetTransitiveClosure" 1574 /*@C 1575 DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG 1576 1577 Not collective 1578 1579 Input Parameters: 1580 + mesh - The DMPlex 1581 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1582 . useCone - PETSC_TRUE for in-edges, otherwise use out-edges 1583 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used 1584 1585 Output Parameters: 1586 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints 1587 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 1588 1589 Note: 1590 If using internal storage (points is NULL on input), each call overwrites the last output. 1591 1592 Fortran Notes: 1593 Since it returns an array, this routine is only available in Fortran 90, and you must 1594 include petsc.h90 in your code. 1595 1596 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 1597 1598 Level: beginner 1599 1600 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 1601 @*/ 1602 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 1603 { 1604 DM_Plex *mesh = (DM_Plex*) dm->data; 1605 PetscInt *closure, *fifo; 1606 const PetscInt *tmp = NULL, *tmpO = NULL; 1607 PetscInt tmpSize, t; 1608 PetscInt depth = 0, maxSize; 1609 PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0; 1610 PetscErrorCode ierr; 1611 1612 PetscFunctionBegin; 1613 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1614 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 1615 /* This is only 1-level */ 1616 if (useCone) { 1617 ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr); 1618 ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr); 1619 ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr); 1620 } else { 1621 ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr); 1622 ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr); 1623 } 1624 if (depth == 1) { 1625 if (*points) { 1626 closure = *points; 1627 } else { 1628 maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1); 1629 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr); 1630 } 1631 closure[0] = p; closure[1] = 0; 1632 for (t = 0; t < tmpSize; ++t, closureSize += 2) { 1633 closure[closureSize] = tmp[t]; 1634 closure[closureSize+1] = tmpO ? tmpO[t] : 0; 1635 } 1636 if (numPoints) *numPoints = closureSize/2; 1637 if (points) *points = closure; 1638 PetscFunctionReturn(0); 1639 } 1640 { 1641 PetscInt c, coneSeries, s,supportSeries; 1642 1643 c = mesh->maxConeSize; 1644 coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1; 1645 s = mesh->maxSupportSize; 1646 supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1; 1647 maxSize = 2*PetscMax(coneSeries,supportSeries); 1648 } 1649 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr); 1650 if (*points) { 1651 closure = *points; 1652 } else { 1653 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr); 1654 } 1655 closure[0] = p; closure[1] = 0; 1656 for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) { 1657 const PetscInt cp = tmp[t]; 1658 const PetscInt co = tmpO ? tmpO[t] : 0; 1659 1660 closure[closureSize] = cp; 1661 closure[closureSize+1] = co; 1662 fifo[fifoSize] = cp; 1663 fifo[fifoSize+1] = co; 1664 } 1665 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 1666 while (fifoSize - fifoStart) { 1667 const PetscInt q = fifo[fifoStart]; 1668 const PetscInt o = fifo[fifoStart+1]; 1669 const PetscInt rev = o >= 0 ? 0 : 1; 1670 const PetscInt off = rev ? -(o+1) : o; 1671 1672 if (useCone) { 1673 ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr); 1674 ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr); 1675 ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr); 1676 } else { 1677 ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr); 1678 ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr); 1679 tmpO = NULL; 1680 } 1681 for (t = 0; t < tmpSize; ++t) { 1682 const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize; 1683 const PetscInt cp = tmp[i]; 1684 /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */ 1685 /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1) 1686 const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */ 1687 PetscInt co = tmpO ? tmpO[i] : 0; 1688 PetscInt c; 1689 1690 if (rev) { 1691 PetscInt childSize, coff; 1692 ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr); 1693 coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i]; 1694 co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0; 1695 } 1696 /* Check for duplicate */ 1697 for (c = 0; c < closureSize; c += 2) { 1698 if (closure[c] == cp) break; 1699 } 1700 if (c == closureSize) { 1701 closure[closureSize] = cp; 1702 closure[closureSize+1] = co; 1703 fifo[fifoSize] = cp; 1704 fifo[fifoSize+1] = co; 1705 closureSize += 2; 1706 fifoSize += 2; 1707 } 1708 } 1709 fifoStart += 2; 1710 } 1711 if (numPoints) *numPoints = closureSize/2; 1712 if (points) *points = closure; 1713 ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr); 1714 PetscFunctionReturn(0); 1715 } 1716 1717 #undef __FUNCT__ 1718 #define __FUNCT__ "DMPlexGetTransitiveClosure_Internal" 1719 /*@C 1720 DMPlexGetTransitiveClosure_Internal - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG with a specified initial orientation 1721 1722 Not collective 1723 1724 Input Parameters: 1725 + mesh - The DMPlex 1726 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1727 . orientation - The orientation of the point 1728 . useCone - PETSC_TRUE for in-edges, otherwise use out-edges 1729 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used 1730 1731 Output Parameters: 1732 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints 1733 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...] 1734 1735 Note: 1736 If using internal storage (points is NULL on input), each call overwrites the last output. 1737 1738 Fortran Notes: 1739 Since it returns an array, this routine is only available in Fortran 90, and you must 1740 include petsc.h90 in your code. 1741 1742 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 1743 1744 Level: beginner 1745 1746 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 1747 @*/ 1748 PetscErrorCode DMPlexGetTransitiveClosure_Internal(DM dm, PetscInt p, PetscInt ornt, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 1749 { 1750 DM_Plex *mesh = (DM_Plex*) dm->data; 1751 PetscInt *closure, *fifo; 1752 const PetscInt *tmp = NULL, *tmpO = NULL; 1753 PetscInt tmpSize, t; 1754 PetscInt depth = 0, maxSize; 1755 PetscInt closureSize = 2, fifoSize = 0, fifoStart = 0; 1756 PetscErrorCode ierr; 1757 1758 PetscFunctionBegin; 1759 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1760 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 1761 /* This is only 1-level */ 1762 if (useCone) { 1763 ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr); 1764 ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr); 1765 ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr); 1766 } else { 1767 ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr); 1768 ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr); 1769 } 1770 if (depth == 1) { 1771 if (*points) { 1772 closure = *points; 1773 } else { 1774 maxSize = 2*(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)+1); 1775 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr); 1776 } 1777 closure[0] = p; closure[1] = ornt; 1778 for (t = 0; t < tmpSize; ++t, closureSize += 2) { 1779 const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize; 1780 closure[closureSize] = tmp[i]; 1781 closure[closureSize+1] = tmpO ? tmpO[i] : 0; 1782 } 1783 if (numPoints) *numPoints = closureSize/2; 1784 if (points) *points = closure; 1785 PetscFunctionReturn(0); 1786 } 1787 { 1788 PetscInt c, coneSeries, s,supportSeries; 1789 1790 c = mesh->maxConeSize; 1791 coneSeries = (c > 1) ? ((PetscPowInt(c,depth+1)-1)/(c-1)) : depth+1; 1792 s = mesh->maxSupportSize; 1793 supportSeries = (s > 1) ? ((PetscPowInt(s,depth+1)-1)/(s-1)) : depth+1; 1794 maxSize = 2*PetscMax(coneSeries,supportSeries); 1795 } 1796 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr); 1797 if (*points) { 1798 closure = *points; 1799 } else { 1800 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr); 1801 } 1802 closure[0] = p; closure[1] = ornt; 1803 for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) { 1804 const PetscInt i = ornt >= 0 ? (t+ornt)%tmpSize : (-(ornt+1) + tmpSize-t)%tmpSize; 1805 const PetscInt cp = tmp[i]; 1806 PetscInt co = tmpO ? tmpO[i] : 0; 1807 1808 if (ornt < 0) { 1809 PetscInt childSize, coff; 1810 ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr); 1811 coff = co < 0 ? -(tmpO[i]+1) : tmpO[i]; 1812 co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0; 1813 } 1814 closure[closureSize] = cp; 1815 closure[closureSize+1] = co; 1816 fifo[fifoSize] = cp; 1817 fifo[fifoSize+1] = co; 1818 } 1819 /* Should kick out early when depth is reached, rather than checking all vertices for empty cones */ 1820 while (fifoSize - fifoStart) { 1821 const PetscInt q = fifo[fifoStart]; 1822 const PetscInt o = fifo[fifoStart+1]; 1823 const PetscInt rev = o >= 0 ? 0 : 1; 1824 const PetscInt off = rev ? -(o+1) : o; 1825 1826 if (useCone) { 1827 ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr); 1828 ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr); 1829 ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr); 1830 } else { 1831 ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr); 1832 ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr); 1833 tmpO = NULL; 1834 } 1835 for (t = 0; t < tmpSize; ++t) { 1836 const PetscInt i = ((rev ? tmpSize-t : t) + off)%tmpSize; 1837 const PetscInt cp = tmp[i]; 1838 /* Must propogate orientation: When we reverse orientation, we both reverse the direction of iteration and start at the other end of the chain. */ 1839 /* HACK: It is worse to get the size here, than to change the interpretation of -(*+1) 1840 const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0; */ 1841 PetscInt co = tmpO ? tmpO[i] : 0; 1842 PetscInt c; 1843 1844 if (rev) { 1845 PetscInt childSize, coff; 1846 ierr = DMPlexGetConeSize(dm, cp, &childSize);CHKERRQ(ierr); 1847 coff = tmpO[i] < 0 ? -(tmpO[i]+1) : tmpO[i]; 1848 co = childSize ? -(((coff+childSize-1)%childSize)+1) : 0; 1849 } 1850 /* Check for duplicate */ 1851 for (c = 0; c < closureSize; c += 2) { 1852 if (closure[c] == cp) break; 1853 } 1854 if (c == closureSize) { 1855 closure[closureSize] = cp; 1856 closure[closureSize+1] = co; 1857 fifo[fifoSize] = cp; 1858 fifo[fifoSize+1] = co; 1859 closureSize += 2; 1860 fifoSize += 2; 1861 } 1862 } 1863 fifoStart += 2; 1864 } 1865 if (numPoints) *numPoints = closureSize/2; 1866 if (points) *points = closure; 1867 ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr); 1868 PetscFunctionReturn(0); 1869 } 1870 1871 #undef __FUNCT__ 1872 #define __FUNCT__ "DMPlexRestoreTransitiveClosure" 1873 /*@C 1874 DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG 1875 1876 Not collective 1877 1878 Input Parameters: 1879 + mesh - The DMPlex 1880 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart() 1881 . useCone - PETSC_TRUE for in-edges, otherwise use out-edges 1882 . numPoints - The number of points in the closure, so points[] is of size 2*numPoints, zeroed on exit 1883 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...], zeroed on exit 1884 1885 Note: 1886 If not using internal storage (points is not NULL on input), this call is unnecessary 1887 1888 Fortran Notes: 1889 Since it returns an array, this routine is only available in Fortran 90, and you must 1890 include petsc.h90 in your code. 1891 1892 The numPoints argument is not present in the Fortran 90 binding since it is internal to the array. 1893 1894 Level: beginner 1895 1896 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone() 1897 @*/ 1898 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[]) 1899 { 1900 PetscErrorCode ierr; 1901 1902 PetscFunctionBegin; 1903 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1904 if (numPoints) PetscValidIntPointer(numPoints,4); 1905 if (points) PetscValidPointer(points,5); 1906 ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr); 1907 if (numPoints) *numPoints = 0; 1908 PetscFunctionReturn(0); 1909 } 1910 1911 #undef __FUNCT__ 1912 #define __FUNCT__ "DMPlexGetMaxSizes" 1913 /*@ 1914 DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG 1915 1916 Not collective 1917 1918 Input Parameter: 1919 . mesh - The DMPlex 1920 1921 Output Parameters: 1922 + maxConeSize - The maximum number of in-edges 1923 - maxSupportSize - The maximum number of out-edges 1924 1925 Level: beginner 1926 1927 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart() 1928 @*/ 1929 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize) 1930 { 1931 DM_Plex *mesh = (DM_Plex*) dm->data; 1932 1933 PetscFunctionBegin; 1934 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1935 if (maxConeSize) *maxConeSize = mesh->maxConeSize; 1936 if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize; 1937 PetscFunctionReturn(0); 1938 } 1939 1940 #undef __FUNCT__ 1941 #define __FUNCT__ "DMSetUp_Plex" 1942 PetscErrorCode DMSetUp_Plex(DM dm) 1943 { 1944 DM_Plex *mesh = (DM_Plex*) dm->data; 1945 PetscInt size; 1946 PetscErrorCode ierr; 1947 1948 PetscFunctionBegin; 1949 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1950 ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr); 1951 ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr); 1952 ierr = PetscMalloc1(size, &mesh->cones);CHKERRQ(ierr); 1953 ierr = PetscCalloc1(size, &mesh->coneOrientations);CHKERRQ(ierr); 1954 if (mesh->maxSupportSize) { 1955 ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr); 1956 ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr); 1957 ierr = PetscMalloc1(size, &mesh->supports);CHKERRQ(ierr); 1958 } 1959 PetscFunctionReturn(0); 1960 } 1961 1962 #undef __FUNCT__ 1963 #define __FUNCT__ "DMCreateSubDM_Plex" 1964 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm) 1965 { 1966 PetscErrorCode ierr; 1967 1968 PetscFunctionBegin; 1969 if (subdm) {ierr = DMClone(dm, subdm);CHKERRQ(ierr);} 1970 ierr = DMCreateSubDM_Section_Private(dm, numFields, fields, is, subdm);CHKERRQ(ierr); 1971 PetscFunctionReturn(0); 1972 } 1973 1974 #undef __FUNCT__ 1975 #define __FUNCT__ "DMPlexSymmetrize" 1976 /*@ 1977 DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation 1978 1979 Not collective 1980 1981 Input Parameter: 1982 . mesh - The DMPlex 1983 1984 Output Parameter: 1985 1986 Note: 1987 This should be called after all calls to DMPlexSetCone() 1988 1989 Level: beginner 1990 1991 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone() 1992 @*/ 1993 PetscErrorCode DMPlexSymmetrize(DM dm) 1994 { 1995 DM_Plex *mesh = (DM_Plex*) dm->data; 1996 PetscInt *offsets; 1997 PetscInt supportSize; 1998 PetscInt pStart, pEnd, p; 1999 PetscErrorCode ierr; 2000 2001 PetscFunctionBegin; 2002 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2003 if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex"); 2004 /* Calculate support sizes */ 2005 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 2006 for (p = pStart; p < pEnd; ++p) { 2007 PetscInt dof, off, c; 2008 2009 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 2010 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2011 for (c = off; c < off+dof; ++c) { 2012 ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr); 2013 } 2014 } 2015 for (p = pStart; p < pEnd; ++p) { 2016 PetscInt dof; 2017 2018 ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr); 2019 2020 mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof); 2021 } 2022 ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr); 2023 /* Calculate supports */ 2024 ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr); 2025 ierr = PetscMalloc1(supportSize, &mesh->supports);CHKERRQ(ierr); 2026 ierr = PetscCalloc1(pEnd - pStart, &offsets);CHKERRQ(ierr); 2027 for (p = pStart; p < pEnd; ++p) { 2028 PetscInt dof, off, c; 2029 2030 ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr); 2031 ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr); 2032 for (c = off; c < off+dof; ++c) { 2033 const PetscInt q = mesh->cones[c]; 2034 PetscInt offS; 2035 2036 ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr); 2037 2038 mesh->supports[offS+offsets[q]] = p; 2039 ++offsets[q]; 2040 } 2041 } 2042 ierr = PetscFree(offsets);CHKERRQ(ierr); 2043 PetscFunctionReturn(0); 2044 } 2045 2046 #undef __FUNCT__ 2047 #define __FUNCT__ "DMPlexStratify" 2048 /*@ 2049 DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and 2050 can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the 2051 same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in 2052 the DAG. 2053 2054 Collective on dm 2055 2056 Input Parameter: 2057 . mesh - The DMPlex 2058 2059 Output Parameter: 2060 2061 Notes: 2062 Concretely, DMPlexStratify() creates a new label named "depth" containing the dimension of each element: 0 for vertices, 2063 1 for edges, and so on. The depth label can be accessed through DMPlexGetDepthLabel() or DMPlexGetDepthStratum(), or 2064 manually via DMGetLabel(). The height is defined implicitly by height = maxDimension - depth, and can be accessed 2065 via DMPlexGetHeightStratum(). For example, cells have height 0 and faces have height 1. 2066 2067 DMPlexStratify() should be called after all calls to DMPlexSymmetrize() 2068 2069 Level: beginner 2070 2071 .seealso: DMPlexCreate(), DMPlexSymmetrize() 2072 @*/ 2073 PetscErrorCode DMPlexStratify(DM dm) 2074 { 2075 DM_Plex *mesh = (DM_Plex*) dm->data; 2076 DMLabel label; 2077 PetscInt pStart, pEnd, p; 2078 PetscInt numRoots = 0, numLeaves = 0; 2079 PetscErrorCode ierr; 2080 2081 PetscFunctionBegin; 2082 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2083 ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr); 2084 /* Calculate depth */ 2085 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 2086 ierr = DMCreateLabel(dm, "depth");CHKERRQ(ierr); 2087 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 2088 /* Initialize roots and count leaves */ 2089 for (p = pStart; p < pEnd; ++p) { 2090 PetscInt coneSize, supportSize; 2091 2092 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 2093 ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr); 2094 if (!coneSize && supportSize) { 2095 ++numRoots; 2096 ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr); 2097 } else if (!supportSize && coneSize) { 2098 ++numLeaves; 2099 } else if (!supportSize && !coneSize) { 2100 /* Isolated points */ 2101 ierr = DMLabelSetValue(label, p, 0);CHKERRQ(ierr); 2102 } 2103 } 2104 if (numRoots + numLeaves == (pEnd - pStart)) { 2105 for (p = pStart; p < pEnd; ++p) { 2106 PetscInt coneSize, supportSize; 2107 2108 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 2109 ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr); 2110 if (!supportSize && coneSize) { 2111 ierr = DMLabelSetValue(label, p, 1);CHKERRQ(ierr); 2112 } 2113 } 2114 } else { 2115 IS pointIS; 2116 PetscInt numPoints = 0, level = 0; 2117 2118 ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr); 2119 if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);} 2120 while (numPoints) { 2121 const PetscInt *points; 2122 const PetscInt newLevel = level+1; 2123 2124 ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr); 2125 for (p = 0; p < numPoints; ++p) { 2126 const PetscInt point = points[p]; 2127 const PetscInt *support; 2128 PetscInt supportSize, s; 2129 2130 ierr = DMPlexGetSupportSize(dm, point, &supportSize);CHKERRQ(ierr); 2131 ierr = DMPlexGetSupport(dm, point, &support);CHKERRQ(ierr); 2132 for (s = 0; s < supportSize; ++s) { 2133 ierr = DMLabelSetValue(label, support[s], newLevel);CHKERRQ(ierr); 2134 } 2135 } 2136 ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr); 2137 ++level; 2138 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 2139 ierr = DMLabelGetStratumIS(label, level, &pointIS);CHKERRQ(ierr); 2140 if (pointIS) {ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);} 2141 else {numPoints = 0;} 2142 } 2143 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 2144 } 2145 { /* just in case there is an empty process */ 2146 PetscInt numValues, maxValues = 0, v; 2147 2148 ierr = DMLabelGetNumValues(label,&numValues);CHKERRQ(ierr); 2149 for (v = 0; v < numValues; v++) { 2150 IS pointIS; 2151 2152 ierr = DMLabelGetStratumIS(label, v, &pointIS);CHKERRQ(ierr); 2153 if (pointIS) { 2154 PetscInt min, max, numPoints; 2155 PetscInt start; 2156 PetscBool contig; 2157 2158 ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr); 2159 ierr = ISGetMinMax(pointIS, &min, &max);CHKERRQ(ierr); 2160 ierr = ISContiguousLocal(pointIS,min,max+1,&start,&contig);CHKERRQ(ierr); 2161 if (start == 0 && contig) { 2162 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 2163 ierr = ISCreateStride(PETSC_COMM_SELF,numPoints,min,1,&pointIS);CHKERRQ(ierr); 2164 ierr = DMLabelSetStratumIS(label, v, pointIS);CHKERRQ(ierr); 2165 } 2166 } 2167 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 2168 } 2169 ierr = MPI_Allreduce(&numValues,&maxValues,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 2170 for (v = numValues; v < maxValues; v++) { 2171 DMLabelAddStratum(label,v);CHKERRQ(ierr); 2172 } 2173 } 2174 2175 ierr = DMLabelGetState(label, &mesh->depthState);CHKERRQ(ierr); 2176 ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr); 2177 PetscFunctionReturn(0); 2178 } 2179 2180 #undef __FUNCT__ 2181 #define __FUNCT__ "DMPlexGetJoin" 2182 /*@C 2183 DMPlexGetJoin - Get an array for the join of the set of points 2184 2185 Not Collective 2186 2187 Input Parameters: 2188 + dm - The DMPlex object 2189 . numPoints - The number of input points for the join 2190 - points - The input points 2191 2192 Output Parameters: 2193 + numCoveredPoints - The number of points in the join 2194 - coveredPoints - The points in the join 2195 2196 Level: intermediate 2197 2198 Note: Currently, this is restricted to a single level join 2199 2200 Fortran Notes: 2201 Since it returns an array, this routine is only available in Fortran 90, and you must 2202 include petsc.h90 in your code. 2203 2204 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 2205 2206 .keywords: mesh 2207 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet() 2208 @*/ 2209 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 2210 { 2211 DM_Plex *mesh = (DM_Plex*) dm->data; 2212 PetscInt *join[2]; 2213 PetscInt joinSize, i = 0; 2214 PetscInt dof, off, p, c, m; 2215 PetscErrorCode ierr; 2216 2217 PetscFunctionBegin; 2218 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2219 PetscValidPointer(points, 2); 2220 PetscValidPointer(numCoveredPoints, 3); 2221 PetscValidPointer(coveredPoints, 4); 2222 ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr); 2223 ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr); 2224 /* Copy in support of first point */ 2225 ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr); 2226 ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr); 2227 for (joinSize = 0; joinSize < dof; ++joinSize) { 2228 join[i][joinSize] = mesh->supports[off+joinSize]; 2229 } 2230 /* Check each successive support */ 2231 for (p = 1; p < numPoints; ++p) { 2232 PetscInt newJoinSize = 0; 2233 2234 ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr); 2235 ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr); 2236 for (c = 0; c < dof; ++c) { 2237 const PetscInt point = mesh->supports[off+c]; 2238 2239 for (m = 0; m < joinSize; ++m) { 2240 if (point == join[i][m]) { 2241 join[1-i][newJoinSize++] = point; 2242 break; 2243 } 2244 } 2245 } 2246 joinSize = newJoinSize; 2247 i = 1-i; 2248 } 2249 *numCoveredPoints = joinSize; 2250 *coveredPoints = join[i]; 2251 ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr); 2252 PetscFunctionReturn(0); 2253 } 2254 2255 #undef __FUNCT__ 2256 #define __FUNCT__ "DMPlexRestoreJoin" 2257 /*@C 2258 DMPlexRestoreJoin - Restore an array for the join of the set of points 2259 2260 Not Collective 2261 2262 Input Parameters: 2263 + dm - The DMPlex object 2264 . numPoints - The number of input points for the join 2265 - points - The input points 2266 2267 Output Parameters: 2268 + numCoveredPoints - The number of points in the join 2269 - coveredPoints - The points in the join 2270 2271 Fortran Notes: 2272 Since it returns an array, this routine is only available in Fortran 90, and you must 2273 include petsc.h90 in your code. 2274 2275 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 2276 2277 Level: intermediate 2278 2279 .keywords: mesh 2280 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet() 2281 @*/ 2282 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 2283 { 2284 PetscErrorCode ierr; 2285 2286 PetscFunctionBegin; 2287 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2288 if (points) PetscValidIntPointer(points,3); 2289 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 2290 PetscValidPointer(coveredPoints, 5); 2291 ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr); 2292 if (numCoveredPoints) *numCoveredPoints = 0; 2293 PetscFunctionReturn(0); 2294 } 2295 2296 #undef __FUNCT__ 2297 #define __FUNCT__ "DMPlexGetFullJoin" 2298 /*@C 2299 DMPlexGetFullJoin - Get an array for the join of the set of points 2300 2301 Not Collective 2302 2303 Input Parameters: 2304 + dm - The DMPlex object 2305 . numPoints - The number of input points for the join 2306 - points - The input points 2307 2308 Output Parameters: 2309 + numCoveredPoints - The number of points in the join 2310 - coveredPoints - The points in the join 2311 2312 Fortran Notes: 2313 Since it returns an array, this routine is only available in Fortran 90, and you must 2314 include petsc.h90 in your code. 2315 2316 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 2317 2318 Level: intermediate 2319 2320 .keywords: mesh 2321 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet() 2322 @*/ 2323 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 2324 { 2325 DM_Plex *mesh = (DM_Plex*) dm->data; 2326 PetscInt *offsets, **closures; 2327 PetscInt *join[2]; 2328 PetscInt depth = 0, maxSize, joinSize = 0, i = 0; 2329 PetscInt p, d, c, m, ms; 2330 PetscErrorCode ierr; 2331 2332 PetscFunctionBegin; 2333 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2334 PetscValidPointer(points, 2); 2335 PetscValidPointer(numCoveredPoints, 3); 2336 PetscValidPointer(coveredPoints, 4); 2337 2338 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 2339 ierr = PetscCalloc1(numPoints, &closures);CHKERRQ(ierr); 2340 ierr = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr); 2341 ms = mesh->maxSupportSize; 2342 maxSize = (ms > 1) ? ((PetscPowInt(ms,depth+1)-1)/(ms-1)) : depth + 1; 2343 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr); 2344 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr); 2345 2346 for (p = 0; p < numPoints; ++p) { 2347 PetscInt closureSize; 2348 2349 ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr); 2350 2351 offsets[p*(depth+2)+0] = 0; 2352 for (d = 0; d < depth+1; ++d) { 2353 PetscInt pStart, pEnd, i; 2354 2355 ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr); 2356 for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) { 2357 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 2358 offsets[p*(depth+2)+d+1] = i; 2359 break; 2360 } 2361 } 2362 if (i == closureSize) offsets[p*(depth+2)+d+1] = i; 2363 } 2364 if (offsets[p*(depth+2)+depth+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize); 2365 } 2366 for (d = 0; d < depth+1; ++d) { 2367 PetscInt dof; 2368 2369 /* Copy in support of first point */ 2370 dof = offsets[d+1] - offsets[d]; 2371 for (joinSize = 0; joinSize < dof; ++joinSize) { 2372 join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2]; 2373 } 2374 /* Check each successive cone */ 2375 for (p = 1; p < numPoints && joinSize; ++p) { 2376 PetscInt newJoinSize = 0; 2377 2378 dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d]; 2379 for (c = 0; c < dof; ++c) { 2380 const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2]; 2381 2382 for (m = 0; m < joinSize; ++m) { 2383 if (point == join[i][m]) { 2384 join[1-i][newJoinSize++] = point; 2385 break; 2386 } 2387 } 2388 } 2389 joinSize = newJoinSize; 2390 i = 1-i; 2391 } 2392 if (joinSize) break; 2393 } 2394 *numCoveredPoints = joinSize; 2395 *coveredPoints = join[i]; 2396 for (p = 0; p < numPoints; ++p) { 2397 ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr); 2398 } 2399 ierr = PetscFree(closures);CHKERRQ(ierr); 2400 ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr); 2401 ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr); 2402 PetscFunctionReturn(0); 2403 } 2404 2405 #undef __FUNCT__ 2406 #define __FUNCT__ "DMPlexGetMeet" 2407 /*@C 2408 DMPlexGetMeet - Get an array for the meet of the set of points 2409 2410 Not Collective 2411 2412 Input Parameters: 2413 + dm - The DMPlex object 2414 . numPoints - The number of input points for the meet 2415 - points - The input points 2416 2417 Output Parameters: 2418 + numCoveredPoints - The number of points in the meet 2419 - coveredPoints - The points in the meet 2420 2421 Level: intermediate 2422 2423 Note: Currently, this is restricted to a single level meet 2424 2425 Fortran Notes: 2426 Since it returns an array, this routine is only available in Fortran 90, and you must 2427 include petsc.h90 in your code. 2428 2429 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 2430 2431 .keywords: mesh 2432 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin() 2433 @*/ 2434 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints) 2435 { 2436 DM_Plex *mesh = (DM_Plex*) dm->data; 2437 PetscInt *meet[2]; 2438 PetscInt meetSize, i = 0; 2439 PetscInt dof, off, p, c, m; 2440 PetscErrorCode ierr; 2441 2442 PetscFunctionBegin; 2443 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2444 PetscValidPointer(points, 2); 2445 PetscValidPointer(numCoveringPoints, 3); 2446 PetscValidPointer(coveringPoints, 4); 2447 ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr); 2448 ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr); 2449 /* Copy in cone of first point */ 2450 ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr); 2451 ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr); 2452 for (meetSize = 0; meetSize < dof; ++meetSize) { 2453 meet[i][meetSize] = mesh->cones[off+meetSize]; 2454 } 2455 /* Check each successive cone */ 2456 for (p = 1; p < numPoints; ++p) { 2457 PetscInt newMeetSize = 0; 2458 2459 ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr); 2460 ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr); 2461 for (c = 0; c < dof; ++c) { 2462 const PetscInt point = mesh->cones[off+c]; 2463 2464 for (m = 0; m < meetSize; ++m) { 2465 if (point == meet[i][m]) { 2466 meet[1-i][newMeetSize++] = point; 2467 break; 2468 } 2469 } 2470 } 2471 meetSize = newMeetSize; 2472 i = 1-i; 2473 } 2474 *numCoveringPoints = meetSize; 2475 *coveringPoints = meet[i]; 2476 ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr); 2477 PetscFunctionReturn(0); 2478 } 2479 2480 #undef __FUNCT__ 2481 #define __FUNCT__ "DMPlexRestoreMeet" 2482 /*@C 2483 DMPlexRestoreMeet - Restore an array for the meet of the set of points 2484 2485 Not Collective 2486 2487 Input Parameters: 2488 + dm - The DMPlex object 2489 . numPoints - The number of input points for the meet 2490 - points - The input points 2491 2492 Output Parameters: 2493 + numCoveredPoints - The number of points in the meet 2494 - coveredPoints - The points in the meet 2495 2496 Level: intermediate 2497 2498 Fortran Notes: 2499 Since it returns an array, this routine is only available in Fortran 90, and you must 2500 include petsc.h90 in your code. 2501 2502 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 2503 2504 .keywords: mesh 2505 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin() 2506 @*/ 2507 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 2508 { 2509 PetscErrorCode ierr; 2510 2511 PetscFunctionBegin; 2512 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2513 if (points) PetscValidIntPointer(points,3); 2514 if (numCoveredPoints) PetscValidIntPointer(numCoveredPoints,4); 2515 PetscValidPointer(coveredPoints,5); 2516 ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr); 2517 if (numCoveredPoints) *numCoveredPoints = 0; 2518 PetscFunctionReturn(0); 2519 } 2520 2521 #undef __FUNCT__ 2522 #define __FUNCT__ "DMPlexGetFullMeet" 2523 /*@C 2524 DMPlexGetFullMeet - Get an array for the meet of the set of points 2525 2526 Not Collective 2527 2528 Input Parameters: 2529 + dm - The DMPlex object 2530 . numPoints - The number of input points for the meet 2531 - points - The input points 2532 2533 Output Parameters: 2534 + numCoveredPoints - The number of points in the meet 2535 - coveredPoints - The points in the meet 2536 2537 Level: intermediate 2538 2539 Fortran Notes: 2540 Since it returns an array, this routine is only available in Fortran 90, and you must 2541 include petsc.h90 in your code. 2542 2543 The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array. 2544 2545 .keywords: mesh 2546 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin() 2547 @*/ 2548 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints) 2549 { 2550 DM_Plex *mesh = (DM_Plex*) dm->data; 2551 PetscInt *offsets, **closures; 2552 PetscInt *meet[2]; 2553 PetscInt height = 0, maxSize, meetSize = 0, i = 0; 2554 PetscInt p, h, c, m, mc; 2555 PetscErrorCode ierr; 2556 2557 PetscFunctionBegin; 2558 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2559 PetscValidPointer(points, 2); 2560 PetscValidPointer(numCoveredPoints, 3); 2561 PetscValidPointer(coveredPoints, 4); 2562 2563 ierr = DMPlexGetDepth(dm, &height);CHKERRQ(ierr); 2564 ierr = PetscMalloc1(numPoints, &closures);CHKERRQ(ierr); 2565 ierr = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr); 2566 mc = mesh->maxConeSize; 2567 maxSize = (mc > 1) ? ((PetscPowInt(mc,height+1)-1)/(mc-1)) : height + 1; 2568 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr); 2569 ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr); 2570 2571 for (p = 0; p < numPoints; ++p) { 2572 PetscInt closureSize; 2573 2574 ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr); 2575 2576 offsets[p*(height+2)+0] = 0; 2577 for (h = 0; h < height+1; ++h) { 2578 PetscInt pStart, pEnd, i; 2579 2580 ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr); 2581 for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) { 2582 if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) { 2583 offsets[p*(height+2)+h+1] = i; 2584 break; 2585 } 2586 } 2587 if (i == closureSize) offsets[p*(height+2)+h+1] = i; 2588 } 2589 if (offsets[p*(height+2)+height+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize); 2590 } 2591 for (h = 0; h < height+1; ++h) { 2592 PetscInt dof; 2593 2594 /* Copy in cone of first point */ 2595 dof = offsets[h+1] - offsets[h]; 2596 for (meetSize = 0; meetSize < dof; ++meetSize) { 2597 meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2]; 2598 } 2599 /* Check each successive cone */ 2600 for (p = 1; p < numPoints && meetSize; ++p) { 2601 PetscInt newMeetSize = 0; 2602 2603 dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h]; 2604 for (c = 0; c < dof; ++c) { 2605 const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2]; 2606 2607 for (m = 0; m < meetSize; ++m) { 2608 if (point == meet[i][m]) { 2609 meet[1-i][newMeetSize++] = point; 2610 break; 2611 } 2612 } 2613 } 2614 meetSize = newMeetSize; 2615 i = 1-i; 2616 } 2617 if (meetSize) break; 2618 } 2619 *numCoveredPoints = meetSize; 2620 *coveredPoints = meet[i]; 2621 for (p = 0; p < numPoints; ++p) { 2622 ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr); 2623 } 2624 ierr = PetscFree(closures);CHKERRQ(ierr); 2625 ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr); 2626 ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr); 2627 PetscFunctionReturn(0); 2628 } 2629 2630 #undef __FUNCT__ 2631 #define __FUNCT__ "DMPlexEqual" 2632 /*@C 2633 DMPlexEqual - Determine if two DMs have the same topology 2634 2635 Not Collective 2636 2637 Input Parameters: 2638 + dmA - A DMPlex object 2639 - dmB - A DMPlex object 2640 2641 Output Parameters: 2642 . equal - PETSC_TRUE if the topologies are identical 2643 2644 Level: intermediate 2645 2646 Notes: 2647 We are not solving graph isomorphism, so we do not permutation. 2648 2649 .keywords: mesh 2650 .seealso: DMPlexGetCone() 2651 @*/ 2652 PetscErrorCode DMPlexEqual(DM dmA, DM dmB, PetscBool *equal) 2653 { 2654 PetscInt depth, depthB, pStart, pEnd, pStartB, pEndB, p; 2655 PetscErrorCode ierr; 2656 2657 PetscFunctionBegin; 2658 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 2659 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 2660 PetscValidPointer(equal, 3); 2661 2662 *equal = PETSC_FALSE; 2663 ierr = DMPlexGetDepth(dmA, &depth);CHKERRQ(ierr); 2664 ierr = DMPlexGetDepth(dmB, &depthB);CHKERRQ(ierr); 2665 if (depth != depthB) PetscFunctionReturn(0); 2666 ierr = DMPlexGetChart(dmA, &pStart, &pEnd);CHKERRQ(ierr); 2667 ierr = DMPlexGetChart(dmB, &pStartB, &pEndB);CHKERRQ(ierr); 2668 if ((pStart != pStartB) || (pEnd != pEndB)) PetscFunctionReturn(0); 2669 for (p = pStart; p < pEnd; ++p) { 2670 const PetscInt *cone, *coneB, *ornt, *orntB, *support, *supportB; 2671 PetscInt coneSize, coneSizeB, c, supportSize, supportSizeB, s; 2672 2673 ierr = DMPlexGetConeSize(dmA, p, &coneSize);CHKERRQ(ierr); 2674 ierr = DMPlexGetCone(dmA, p, &cone);CHKERRQ(ierr); 2675 ierr = DMPlexGetConeOrientation(dmA, p, &ornt);CHKERRQ(ierr); 2676 ierr = DMPlexGetConeSize(dmB, p, &coneSizeB);CHKERRQ(ierr); 2677 ierr = DMPlexGetCone(dmB, p, &coneB);CHKERRQ(ierr); 2678 ierr = DMPlexGetConeOrientation(dmB, p, &orntB);CHKERRQ(ierr); 2679 if (coneSize != coneSizeB) PetscFunctionReturn(0); 2680 for (c = 0; c < coneSize; ++c) { 2681 if (cone[c] != coneB[c]) PetscFunctionReturn(0); 2682 if (ornt[c] != orntB[c]) PetscFunctionReturn(0); 2683 } 2684 ierr = DMPlexGetSupportSize(dmA, p, &supportSize);CHKERRQ(ierr); 2685 ierr = DMPlexGetSupport(dmA, p, &support);CHKERRQ(ierr); 2686 ierr = DMPlexGetSupportSize(dmB, p, &supportSizeB);CHKERRQ(ierr); 2687 ierr = DMPlexGetSupport(dmB, p, &supportB);CHKERRQ(ierr); 2688 if (supportSize != supportSizeB) PetscFunctionReturn(0); 2689 for (s = 0; s < supportSize; ++s) { 2690 if (support[s] != supportB[s]) PetscFunctionReturn(0); 2691 } 2692 } 2693 *equal = PETSC_TRUE; 2694 PetscFunctionReturn(0); 2695 } 2696 2697 #undef __FUNCT__ 2698 #define __FUNCT__ "DMPlexGetNumFaceVertices" 2699 PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices) 2700 { 2701 MPI_Comm comm; 2702 PetscErrorCode ierr; 2703 2704 PetscFunctionBegin; 2705 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 2706 PetscValidPointer(numFaceVertices,3); 2707 switch (cellDim) { 2708 case 0: 2709 *numFaceVertices = 0; 2710 break; 2711 case 1: 2712 *numFaceVertices = 1; 2713 break; 2714 case 2: 2715 switch (numCorners) { 2716 case 3: /* triangle */ 2717 *numFaceVertices = 2; /* Edge has 2 vertices */ 2718 break; 2719 case 4: /* quadrilateral */ 2720 *numFaceVertices = 2; /* Edge has 2 vertices */ 2721 break; 2722 case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */ 2723 *numFaceVertices = 3; /* Edge has 3 vertices */ 2724 break; 2725 case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */ 2726 *numFaceVertices = 3; /* Edge has 3 vertices */ 2727 break; 2728 default: 2729 SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim); 2730 } 2731 break; 2732 case 3: 2733 switch (numCorners) { 2734 case 4: /* tetradehdron */ 2735 *numFaceVertices = 3; /* Face has 3 vertices */ 2736 break; 2737 case 6: /* tet cohesive cells */ 2738 *numFaceVertices = 4; /* Face has 4 vertices */ 2739 break; 2740 case 8: /* hexahedron */ 2741 *numFaceVertices = 4; /* Face has 4 vertices */ 2742 break; 2743 case 9: /* tet cohesive Lagrange cells */ 2744 *numFaceVertices = 6; /* Face has 6 vertices */ 2745 break; 2746 case 10: /* quadratic tetrahedron */ 2747 *numFaceVertices = 6; /* Face has 6 vertices */ 2748 break; 2749 case 12: /* hex cohesive Lagrange cells */ 2750 *numFaceVertices = 6; /* Face has 6 vertices */ 2751 break; 2752 case 18: /* quadratic tet cohesive Lagrange cells */ 2753 *numFaceVertices = 6; /* Face has 6 vertices */ 2754 break; 2755 case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */ 2756 *numFaceVertices = 9; /* Face has 9 vertices */ 2757 break; 2758 default: 2759 SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %D for dimension %D", numCorners, cellDim); 2760 } 2761 break; 2762 default: 2763 SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %D", cellDim); 2764 } 2765 PetscFunctionReturn(0); 2766 } 2767 2768 #undef __FUNCT__ 2769 #define __FUNCT__ "DMPlexGetDepthLabel" 2770 /*@ 2771 DMPlexGetDepthLabel - Get the DMLabel recording the depth of each point 2772 2773 Not Collective 2774 2775 Input Parameter: 2776 . dm - The DMPlex object 2777 2778 Output Parameter: 2779 . depthLabel - The DMLabel recording point depth 2780 2781 Level: developer 2782 2783 .keywords: mesh, points 2784 .seealso: DMPlexGetDepth(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum() 2785 @*/ 2786 PetscErrorCode DMPlexGetDepthLabel(DM dm, DMLabel *depthLabel) 2787 { 2788 PetscErrorCode ierr; 2789 2790 PetscFunctionBegin; 2791 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2792 PetscValidPointer(depthLabel, 2); 2793 if (!dm->depthLabel) {ierr = DMGetLabel(dm, "depth", &dm->depthLabel);CHKERRQ(ierr);} 2794 *depthLabel = dm->depthLabel; 2795 PetscFunctionReturn(0); 2796 } 2797 2798 #undef __FUNCT__ 2799 #define __FUNCT__ "DMPlexGetDepth" 2800 /*@ 2801 DMPlexGetDepth - Get the depth of the DAG representing this mesh 2802 2803 Not Collective 2804 2805 Input Parameter: 2806 . dm - The DMPlex object 2807 2808 Output Parameter: 2809 . depth - The number of strata (breadth first levels) in the DAG 2810 2811 Level: developer 2812 2813 .keywords: mesh, points 2814 .seealso: DMPlexGetDepthLabel(), DMPlexGetHeightStratum(), DMPlexGetDepthStratum() 2815 @*/ 2816 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth) 2817 { 2818 DMLabel label; 2819 PetscInt d = 0; 2820 PetscErrorCode ierr; 2821 2822 PetscFunctionBegin; 2823 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2824 PetscValidPointer(depth, 2); 2825 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 2826 if (label) {ierr = DMLabelGetNumValues(label, &d);CHKERRQ(ierr);} 2827 *depth = d-1; 2828 PetscFunctionReturn(0); 2829 } 2830 2831 #undef __FUNCT__ 2832 #define __FUNCT__ "DMPlexGetDepthStratum" 2833 /*@ 2834 DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth. 2835 2836 Not Collective 2837 2838 Input Parameters: 2839 + dm - The DMPlex object 2840 - stratumValue - The requested depth 2841 2842 Output Parameters: 2843 + start - The first point at this depth 2844 - end - One beyond the last point at this depth 2845 2846 Level: developer 2847 2848 .keywords: mesh, points 2849 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth() 2850 @*/ 2851 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 2852 { 2853 DMLabel label; 2854 PetscInt pStart, pEnd; 2855 PetscErrorCode ierr; 2856 2857 PetscFunctionBegin; 2858 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2859 if (start) {PetscValidPointer(start, 3); *start = 0;} 2860 if (end) {PetscValidPointer(end, 4); *end = 0;} 2861 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 2862 if (pStart == pEnd) PetscFunctionReturn(0); 2863 if (stratumValue < 0) { 2864 if (start) *start = pStart; 2865 if (end) *end = pEnd; 2866 PetscFunctionReturn(0); 2867 } 2868 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 2869 if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found"); 2870 ierr = DMLabelGetStratumBounds(label, stratumValue, start, end);CHKERRQ(ierr); 2871 PetscFunctionReturn(0); 2872 } 2873 2874 #undef __FUNCT__ 2875 #define __FUNCT__ "DMPlexGetHeightStratum" 2876 /*@ 2877 DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height. 2878 2879 Not Collective 2880 2881 Input Parameters: 2882 + dm - The DMPlex object 2883 - stratumValue - The requested height 2884 2885 Output Parameters: 2886 + start - The first point at this height 2887 - end - One beyond the last point at this height 2888 2889 Level: developer 2890 2891 .keywords: mesh, points 2892 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth() 2893 @*/ 2894 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) 2895 { 2896 DMLabel label; 2897 PetscInt depth, pStart, pEnd; 2898 PetscErrorCode ierr; 2899 2900 PetscFunctionBegin; 2901 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2902 if (start) {PetscValidPointer(start, 3); *start = 0;} 2903 if (end) {PetscValidPointer(end, 4); *end = 0;} 2904 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 2905 if (pStart == pEnd) PetscFunctionReturn(0); 2906 if (stratumValue < 0) { 2907 if (start) *start = pStart; 2908 if (end) *end = pEnd; 2909 PetscFunctionReturn(0); 2910 } 2911 ierr = DMPlexGetDepthLabel(dm, &label);CHKERRQ(ierr); 2912 if (!label) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr); 2913 ierr = DMLabelGetNumValues(label, &depth);CHKERRQ(ierr); 2914 ierr = DMLabelGetStratumBounds(label, depth-1-stratumValue, start, end);CHKERRQ(ierr); 2915 PetscFunctionReturn(0); 2916 } 2917 2918 #undef __FUNCT__ 2919 #define __FUNCT__ "DMPlexCreateSectionInitial" 2920 /* Set the number of dof on each point and separate by fields */ 2921 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section) 2922 { 2923 PetscInt *pMax; 2924 PetscInt depth, pStart = 0, pEnd = 0; 2925 PetscInt Nf, p, d, dep, f; 2926 PetscBool *isFE; 2927 PetscErrorCode ierr; 2928 2929 PetscFunctionBegin; 2930 ierr = PetscMalloc1(numFields, &isFE);CHKERRQ(ierr); 2931 ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr); 2932 for (f = 0; f < numFields; ++f) { 2933 PetscObject obj; 2934 PetscClassId id; 2935 2936 isFE[f] = PETSC_FALSE; 2937 if (f >= Nf) continue; 2938 ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr); 2939 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2940 if (id == PETSCFE_CLASSID) {isFE[f] = PETSC_TRUE;} 2941 else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;} 2942 } 2943 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr); 2944 if (numFields > 0) { 2945 ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr); 2946 if (numComp) { 2947 for (f = 0; f < numFields; ++f) { 2948 ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr); 2949 if (isFE[f]) { 2950 PetscFE fe; 2951 PetscDualSpace dspace; 2952 const PetscInt ***perms; 2953 const PetscScalar ***flips; 2954 const PetscInt *numDof; 2955 2956 ierr = DMGetField(dm,f,(PetscObject *) &fe);CHKERRQ(ierr); 2957 ierr = PetscFEGetDualSpace(fe,&dspace);CHKERRQ(ierr); 2958 ierr = PetscDualSpaceGetSymmetries(dspace,&perms,&flips);CHKERRQ(ierr); 2959 ierr = PetscDualSpaceGetNumDof(dspace,&numDof);CHKERRQ(ierr); 2960 if (perms || flips) { 2961 DM K; 2962 DMLabel depthLabel; 2963 PetscInt depth, h; 2964 PetscSectionSym sym; 2965 2966 ierr = PetscDualSpaceGetDM(dspace,&K);CHKERRQ(ierr); 2967 ierr = DMPlexGetDepthLabel(dm,&depthLabel);CHKERRQ(ierr); 2968 ierr = DMPlexGetDepth(dm,&depth);CHKERRQ(ierr); 2969 ierr = PetscSectionSymCreateLabel(PetscObjectComm((PetscObject)*section),depthLabel,&sym);CHKERRQ(ierr); 2970 for (h = 0; h <= depth; h++) { 2971 PetscDualSpace hspace; 2972 PetscInt kStart, kEnd; 2973 PetscInt kConeSize; 2974 const PetscInt **perms0 = NULL; 2975 const PetscScalar **flips0 = NULL; 2976 2977 ierr = PetscDualSpaceGetHeightSubspace(dspace,h,&hspace);CHKERRQ(ierr); 2978 ierr = DMPlexGetHeightStratum(K,h,&kStart,&kEnd);CHKERRQ(ierr); 2979 if (!hspace) continue; 2980 ierr = PetscDualSpaceGetSymmetries(hspace,&perms,&flips);CHKERRQ(ierr); 2981 if (perms) perms0 = perms[0]; 2982 if (flips) flips0 = flips[0]; 2983 if (!(perms0 || flips0)) continue; 2984 ierr = DMPlexGetConeSize(K,kStart,&kConeSize);CHKERRQ(ierr); 2985 if (numComp[f] == 1) { 2986 ierr = PetscSectionSymLabelSetStratum(sym,depth - h,numDof[depth - h],-kConeSize,kConeSize,PETSC_USE_POINTER,perms0 ? &perms0[-kConeSize] : NULL,flips0 ? &flips0[-kConeSize] : NULL);CHKERRQ(ierr); 2987 } else { 2988 PetscInt **fieldPerms = NULL, o; 2989 PetscScalar **fieldFlips = NULL; 2990 2991 ierr = PetscCalloc1(2 * kConeSize,&fieldPerms);CHKERRQ(ierr); 2992 ierr = PetscCalloc1(2 * kConeSize,&fieldFlips);CHKERRQ(ierr); 2993 for (o = -kConeSize; o < kConeSize; o++) { 2994 if (perms0 && perms0[o]) { 2995 PetscInt r, s; 2996 2997 ierr = PetscMalloc1(numComp[f] * numDof[depth - h],&fieldPerms[o+kConeSize]);CHKERRQ(ierr); 2998 for (r = 0; r < numDof[depth - h]; r++) { 2999 for (s = 0; s < numComp[f]; s++) { 3000 fieldPerms[o+kConeSize][r * numComp[f] + s] = numComp[f] * perms0[o][r] + s; 3001 } 3002 } 3003 } 3004 if (flips0 && flips0[o]) { 3005 PetscInt r, s; 3006 3007 ierr = PetscMalloc1(numComp[f] * numDof[depth - h],&fieldFlips[o+kConeSize]);CHKERRQ(ierr); 3008 for (r = 0; r < numDof[depth - h]; r++) { 3009 for (s = 0; s < numComp[f]; s++) { 3010 fieldFlips[o+kConeSize][r * numComp[f] + s] = flips0[o][r]; 3011 } 3012 } 3013 } 3014 } 3015 ierr = PetscSectionSymLabelSetStratum(sym,depth - h,numComp[f] * numDof[depth - h],-kConeSize,kConeSize,PETSC_OWN_POINTER,(const PetscInt **) fieldPerms,(const PetscScalar **)fieldFlips);CHKERRQ(ierr); 3016 } 3017 } 3018 ierr = PetscSectionSetFieldSym(*section,f,sym);CHKERRQ(ierr); 3019 ierr = PetscSectionSymDestroy(&sym);CHKERRQ(ierr); 3020 } 3021 } 3022 } 3023 } 3024 } 3025 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 3026 ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr); 3027 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 3028 ierr = PetscMalloc1(depth+1,&pMax);CHKERRQ(ierr); 3029 ierr = DMPlexGetHybridBounds(dm, depth >= 0 ? &pMax[depth] : NULL, depth>1 ? &pMax[depth-1] : NULL, depth>2 ? &pMax[1] : NULL, &pMax[0]);CHKERRQ(ierr); 3030 for (dep = 0; dep <= depth; ++dep) { 3031 d = dim == depth ? dep : (!dep ? 0 : dim); 3032 ierr = DMPlexGetDepthStratum(dm, dep, &pStart, &pEnd);CHKERRQ(ierr); 3033 pMax[dep] = pMax[dep] < 0 ? pEnd : pMax[dep]; 3034 for (p = pStart; p < pEnd; ++p) { 3035 PetscInt tot = 0; 3036 3037 for (f = 0; f < numFields; ++f) { 3038 if (isFE[f] && p >= pMax[dep]) continue; 3039 ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr); 3040 tot += numDof[f*(dim+1)+d]; 3041 } 3042 ierr = PetscSectionSetDof(*section, p, tot);CHKERRQ(ierr); 3043 } 3044 } 3045 ierr = PetscFree(pMax);CHKERRQ(ierr); 3046 ierr = PetscFree(isFE);CHKERRQ(ierr); 3047 PetscFunctionReturn(0); 3048 } 3049 3050 #undef __FUNCT__ 3051 #define __FUNCT__ "DMPlexCreateSectionBCDof" 3052 /* Set the number of dof on each point and separate by fields 3053 If bcComps is NULL or the IS is NULL, constrain every dof on the point 3054 */ 3055 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC, const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section) 3056 { 3057 PetscInt numFields; 3058 PetscInt bc; 3059 PetscSection aSec; 3060 PetscErrorCode ierr; 3061 3062 PetscFunctionBegin; 3063 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 3064 for (bc = 0; bc < numBC; ++bc) { 3065 PetscInt field = 0; 3066 const PetscInt *comp; 3067 const PetscInt *idx; 3068 PetscInt Nc = -1, n, i; 3069 3070 if (numFields) field = bcField[bc]; 3071 if (bcComps && bcComps[bc]) {ierr = ISGetLocalSize(bcComps[bc], &Nc);CHKERRQ(ierr);} 3072 if (bcComps && bcComps[bc]) {ierr = ISGetIndices(bcComps[bc], &comp);CHKERRQ(ierr);} 3073 ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr); 3074 ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr); 3075 for (i = 0; i < n; ++i) { 3076 const PetscInt p = idx[i]; 3077 PetscInt numConst; 3078 3079 if (numFields) { 3080 ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr); 3081 } else { 3082 ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr); 3083 } 3084 /* If Nc < 0, constrain every dof on the point */ 3085 if (Nc > 0) numConst = PetscMin(numConst, Nc); 3086 if (numFields) {ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);} 3087 ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr); 3088 } 3089 ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr); 3090 if (bcComps && bcComps[bc]) {ierr = ISRestoreIndices(bcComps[bc], &comp);CHKERRQ(ierr);} 3091 } 3092 ierr = DMPlexGetAnchors(dm, &aSec, NULL);CHKERRQ(ierr); 3093 if (aSec) { 3094 PetscInt aStart, aEnd, a; 3095 3096 ierr = PetscSectionGetChart(aSec, &aStart, &aEnd);CHKERRQ(ierr); 3097 for (a = aStart; a < aEnd; a++) { 3098 PetscInt dof, f; 3099 3100 ierr = PetscSectionGetDof(aSec, a, &dof);CHKERRQ(ierr); 3101 if (dof) { 3102 /* if there are point-to-point constraints, then all dofs are constrained */ 3103 ierr = PetscSectionGetDof(section, a, &dof);CHKERRQ(ierr); 3104 ierr = PetscSectionSetConstraintDof(section, a, dof);CHKERRQ(ierr); 3105 for (f = 0; f < numFields; f++) { 3106 ierr = PetscSectionGetFieldDof(section, a, f, &dof);CHKERRQ(ierr); 3107 ierr = PetscSectionSetFieldConstraintDof(section, a, f, dof);CHKERRQ(ierr); 3108 } 3109 } 3110 } 3111 } 3112 PetscFunctionReturn(0); 3113 } 3114 3115 #undef __FUNCT__ 3116 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField" 3117 /* Set the constrained field indices on each point 3118 If bcComps is NULL or the IS is NULL, constrain every dof on the point 3119 */ 3120 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], PetscSection section) 3121 { 3122 PetscSection aSec; 3123 PetscInt *indices; 3124 PetscInt numFields, maxDof, pStart, pEnd, p, bc, f, d; 3125 PetscErrorCode ierr; 3126 3127 PetscFunctionBegin; 3128 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 3129 if (!numFields) PetscFunctionReturn(0); 3130 /* Initialize all field indices to -1 */ 3131 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 3132 ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr); 3133 ierr = PetscMalloc1(maxDof, &indices);CHKERRQ(ierr); 3134 for (d = 0; d < maxDof; ++d) indices[d] = -1; 3135 for (p = pStart; p < pEnd; ++p) for (f = 0; f < numFields; ++f) {ierr = PetscSectionSetFieldConstraintIndices(section, p, f, indices);CHKERRQ(ierr);} 3136 /* Handle BC constraints */ 3137 for (bc = 0; bc < numBC; ++bc) { 3138 const PetscInt field = bcField[bc]; 3139 const PetscInt *comp, *idx; 3140 PetscInt Nc = -1, n, i; 3141 3142 if (bcComps && bcComps[bc]) {ierr = ISGetLocalSize(bcComps[bc], &Nc);CHKERRQ(ierr);} 3143 if (bcComps && bcComps[bc]) {ierr = ISGetIndices(bcComps[bc], &comp);CHKERRQ(ierr);} 3144 ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr); 3145 ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr); 3146 for (i = 0; i < n; ++i) { 3147 const PetscInt p = idx[i]; 3148 const PetscInt *find; 3149 PetscInt fcdof, c; 3150 3151 ierr = PetscSectionGetFieldConstraintDof(section, p, field, &fcdof);CHKERRQ(ierr); 3152 if (Nc < 0) { 3153 for (d = 0; d < fcdof; ++d) indices[d] = d; 3154 } else { 3155 ierr = PetscSectionGetFieldConstraintIndices(section, p, field, &find);CHKERRQ(ierr); 3156 for (d = 0; d < fcdof; ++d) {if (find[d] < 0) break; indices[d] = find[d];} 3157 for (c = 0; c < Nc; ++c) indices[d+c] = comp[c]; 3158 ierr = PetscSortInt(d+Nc, indices);CHKERRQ(ierr); 3159 for (c = d+Nc; c < fcdof; ++c) indices[c] = -1; 3160 } 3161 ierr = PetscSectionSetFieldConstraintIndices(section, p, field, indices);CHKERRQ(ierr); 3162 } 3163 if (bcComps && bcComps[bc]) {ierr = ISRestoreIndices(bcComps[bc], &comp);CHKERRQ(ierr);} 3164 ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr); 3165 } 3166 /* Handle anchors */ 3167 ierr = DMPlexGetAnchors(dm, &aSec, NULL);CHKERRQ(ierr); 3168 if (aSec) { 3169 PetscInt aStart, aEnd, a; 3170 3171 for (d = 0; d < maxDof; ++d) indices[d] = d; 3172 ierr = PetscSectionGetChart(aSec, &aStart, &aEnd);CHKERRQ(ierr); 3173 for (a = aStart; a < aEnd; a++) { 3174 PetscInt dof, fdof, f; 3175 3176 ierr = PetscSectionGetDof(aSec, a, &dof);CHKERRQ(ierr); 3177 if (dof) { 3178 /* if there are point-to-point constraints, then all dofs are constrained */ 3179 for (f = 0; f < numFields; f++) { 3180 ierr = PetscSectionGetFieldDof(section, a, f, &fdof);CHKERRQ(ierr); 3181 ierr = PetscSectionSetFieldConstraintIndices(section, a, f, indices);CHKERRQ(ierr); 3182 } 3183 } 3184 } 3185 } 3186 ierr = PetscFree(indices);CHKERRQ(ierr); 3187 PetscFunctionReturn(0); 3188 } 3189 3190 #undef __FUNCT__ 3191 #define __FUNCT__ "DMPlexCreateSectionBCIndices" 3192 /* Set the constrained indices on each point */ 3193 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section) 3194 { 3195 PetscInt *indices; 3196 PetscInt numFields, maxDof, pStart, pEnd, p, f, d; 3197 PetscErrorCode ierr; 3198 3199 PetscFunctionBegin; 3200 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 3201 ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr); 3202 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 3203 ierr = PetscMalloc1(maxDof, &indices);CHKERRQ(ierr); 3204 for (d = 0; d < maxDof; ++d) indices[d] = -1; 3205 for (p = pStart; p < pEnd; ++p) { 3206 PetscInt cdof, d; 3207 3208 ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr); 3209 if (cdof) { 3210 if (numFields) { 3211 PetscInt numConst = 0, foff = 0; 3212 3213 for (f = 0; f < numFields; ++f) { 3214 const PetscInt *find; 3215 PetscInt fcdof, fdof; 3216 3217 ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr); 3218 ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr); 3219 /* Change constraint numbering from field component to local dof number */ 3220 ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &find);CHKERRQ(ierr); 3221 for (d = 0; d < fcdof; ++d) indices[numConst+d] = find[d] + foff; 3222 numConst += fcdof; 3223 foff += fdof; 3224 } 3225 if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof); 3226 } else { 3227 for (d = 0; d < cdof; ++d) indices[d] = d; 3228 } 3229 ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr); 3230 } 3231 } 3232 ierr = PetscFree(indices);CHKERRQ(ierr); 3233 PetscFunctionReturn(0); 3234 } 3235 3236 #undef __FUNCT__ 3237 #define __FUNCT__ "DMPlexCreateSection" 3238 /*@C 3239 DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided. 3240 3241 Not Collective 3242 3243 Input Parameters: 3244 + dm - The DMPlex object 3245 . dim - The spatial dimension of the problem 3246 . numFields - The number of fields in the problem 3247 . numComp - An array of size numFields that holds the number of components for each field 3248 . numDof - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d 3249 . numBC - The number of boundary conditions 3250 . bcField - An array of size numBC giving the field number for each boundry condition 3251 . bcComps - [Optional] An array of size numBC giving an IS holding the field components to which each boundary condition applies 3252 . bcPoints - An array of size numBC giving an IS holding the Plex points to which each boundary condition applies 3253 - perm - Optional permutation of the chart, or NULL 3254 3255 Output Parameter: 3256 . section - The PetscSection object 3257 3258 Notes: numDof[f*(dim+1)+d] gives the number of dof for field f on sieve points of dimension d. For instance, numDof[1] is the 3259 number of dof for field 0 on each edge. 3260 3261 The chart permutation is the same one set using PetscSectionSetPermutation() 3262 3263 Level: developer 3264 3265 Fortran Notes: 3266 A Fortran 90 version is available as DMPlexCreateSectionF90() 3267 3268 .keywords: mesh, elements 3269 .seealso: DMPlexCreate(), PetscSectionCreate(), PetscSectionSetPermutation() 3270 @*/ 3271 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[], const IS bcComps[], const IS bcPoints[], IS perm, PetscSection *section) 3272 { 3273 PetscSection aSec; 3274 PetscErrorCode ierr; 3275 3276 PetscFunctionBegin; 3277 ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr); 3278 ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcComps, bcPoints, *section);CHKERRQ(ierr); 3279 if (perm) {ierr = PetscSectionSetPermutation(*section, perm);CHKERRQ(ierr);} 3280 ierr = PetscSectionSetUp(*section);CHKERRQ(ierr); 3281 ierr = DMPlexGetAnchors(dm,&aSec,NULL);CHKERRQ(ierr); 3282 if (numBC || aSec) { 3283 ierr = DMPlexCreateSectionBCIndicesField(dm, numBC, bcField, bcComps, bcPoints, *section);CHKERRQ(ierr); 3284 ierr = DMPlexCreateSectionBCIndices(dm, *section);CHKERRQ(ierr); 3285 } 3286 ierr = PetscSectionViewFromOptions(*section,NULL,"-section_view");CHKERRQ(ierr); 3287 PetscFunctionReturn(0); 3288 } 3289 3290 #undef __FUNCT__ 3291 #define __FUNCT__ "DMCreateCoordinateDM_Plex" 3292 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) 3293 { 3294 PetscSection section, s; 3295 Mat m; 3296 PetscInt maxHeight; 3297 PetscErrorCode ierr; 3298 3299 PetscFunctionBegin; 3300 ierr = DMClone(dm, cdm);CHKERRQ(ierr); 3301 ierr = DMPlexGetMaxProjectionHeight(dm, &maxHeight);CHKERRQ(ierr); 3302 ierr = DMPlexSetMaxProjectionHeight(*cdm, maxHeight);CHKERRQ(ierr); 3303 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);CHKERRQ(ierr); 3304 ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr); 3305 ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); 3306 ierr = PetscSectionCreate(PETSC_COMM_SELF, &s);CHKERRQ(ierr); 3307 ierr = MatCreate(PETSC_COMM_SELF, &m);CHKERRQ(ierr); 3308 ierr = DMSetDefaultConstraints(*cdm, s, m);CHKERRQ(ierr); 3309 ierr = PetscSectionDestroy(&s);CHKERRQ(ierr); 3310 ierr = MatDestroy(&m);CHKERRQ(ierr); 3311 PetscFunctionReturn(0); 3312 } 3313 3314 #undef __FUNCT__ 3315 #define __FUNCT__ "DMPlexGetConeSection" 3316 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) 3317 { 3318 DM_Plex *mesh = (DM_Plex*) dm->data; 3319 3320 PetscFunctionBegin; 3321 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3322 if (section) *section = mesh->coneSection; 3323 PetscFunctionReturn(0); 3324 } 3325 3326 #undef __FUNCT__ 3327 #define __FUNCT__ "DMPlexGetSupportSection" 3328 PetscErrorCode DMPlexGetSupportSection(DM dm, PetscSection *section) 3329 { 3330 DM_Plex *mesh = (DM_Plex*) dm->data; 3331 3332 PetscFunctionBegin; 3333 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3334 if (section) *section = mesh->supportSection; 3335 PetscFunctionReturn(0); 3336 } 3337 3338 #undef __FUNCT__ 3339 #define __FUNCT__ "DMPlexGetCones" 3340 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) 3341 { 3342 DM_Plex *mesh = (DM_Plex*) dm->data; 3343 3344 PetscFunctionBegin; 3345 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3346 if (cones) *cones = mesh->cones; 3347 PetscFunctionReturn(0); 3348 } 3349 3350 #undef __FUNCT__ 3351 #define __FUNCT__ "DMPlexGetConeOrientations" 3352 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) 3353 { 3354 DM_Plex *mesh = (DM_Plex*) dm->data; 3355 3356 PetscFunctionBegin; 3357 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3358 if (coneOrientations) *coneOrientations = mesh->coneOrientations; 3359 PetscFunctionReturn(0); 3360 } 3361 3362 /******************************** FEM Support **********************************/ 3363 3364 #undef __FUNCT__ 3365 #define __FUNCT__ "DMPlexCreateSpectralClosurePermutation" 3366 PetscErrorCode DMPlexCreateSpectralClosurePermutation(DM dm, PetscSection section) 3367 { 3368 PetscInt *perm; 3369 PetscInt dim, eStart, k, Nf, f, Nc, c, i, j, size = 0, offset = 0, foffset = 0; 3370 PetscErrorCode ierr; 3371 3372 PetscFunctionBegin; 3373 if (!section) {ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr);} 3374 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 3375 ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr); 3376 if (dim <= 1) PetscFunctionReturn(0); 3377 for (f = 0; f < Nf; ++f) { 3378 /* An order k SEM disc has k-1 dofs on an edge */ 3379 ierr = DMPlexGetDepthStratum(dm, 1, &eStart, NULL);CHKERRQ(ierr); 3380 ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr); 3381 ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr); 3382 k = k/Nc + 1; 3383 size += PetscPowInt(k+1, dim)*Nc; 3384 } 3385 ierr = PetscMalloc1(size, &perm);CHKERRQ(ierr); 3386 for (f = 0; f < Nf; ++f) { 3387 switch (dim) { 3388 case 2: 3389 /* The original quad closure is oriented clockwise, {f, e_b, e_r, e_t, e_l, v_lb, v_rb, v_tr, v_tl} */ 3390 ierr = DMPlexGetDepthStratum(dm, 1, &eStart, NULL);CHKERRQ(ierr); 3391 ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr); 3392 ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr); 3393 k = k/Nc + 1; 3394 /* The SEM order is 3395 3396 v_lb, {e_b}, v_rb, 3397 e^{(k-1)-i}_l, {f^{i*(k-1)}}, e^i_r, 3398 v_lt, reverse {e_t}, v_rt 3399 */ 3400 { 3401 const PetscInt of = 0; 3402 const PetscInt oeb = of + PetscSqr(k-1); 3403 const PetscInt oer = oeb + (k-1); 3404 const PetscInt oet = oer + (k-1); 3405 const PetscInt oel = oet + (k-1); 3406 const PetscInt ovlb = oel + (k-1); 3407 const PetscInt ovrb = ovlb + 1; 3408 const PetscInt ovrt = ovrb + 1; 3409 const PetscInt ovlt = ovrt + 1; 3410 PetscInt o; 3411 3412 /* bottom */ 3413 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlb*Nc + c + foffset; 3414 for (o = oeb; o < oer; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 3415 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrb*Nc + c + foffset; 3416 /* middle */ 3417 for (i = 0; i < k-1; ++i) { 3418 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oel+(k-2)-i)*Nc + c + foffset; 3419 for (o = of+(k-1)*i; o < of+(k-1)*(i+1); ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 3420 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oer+i)*Nc + c + foffset; 3421 } 3422 /* top */ 3423 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovlt*Nc + c + foffset; 3424 for (o = oel-1; o >= oet; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 3425 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovrt*Nc + c + foffset; 3426 foffset = offset; 3427 } 3428 break; 3429 case 3: 3430 /* The original hex closure is 3431 3432 {c, 3433 f_b, f_t, f_f, f_b, f_r, f_l, 3434 e_bl, e_bb, e_br, e_bf, e_tf, e_tr, e_tb, e_tl, e_rf, e_lf, e_lb, e_rb, 3435 v_blf, v_blb, v_brb, v_brf, v_tlf, v_trf, v_trb, v_tlb} 3436 */ 3437 ierr = DMPlexGetDepthStratum(dm, 1, &eStart, NULL);CHKERRQ(ierr); 3438 ierr = PetscSectionGetFieldDof(section, eStart, f, &k);CHKERRQ(ierr); 3439 ierr = PetscSectionGetFieldComponents(section, f, &Nc);CHKERRQ(ierr); 3440 k = k/Nc + 1; 3441 /* The SEM order is 3442 Bottom Slice 3443 v_blf, {e^{(k-1)-n}_bf}, v_brf, 3444 e^{i}_bl, f^{n*(k-1)+(k-1)-i}_b, e^{(k-1)-i}_br, 3445 v_blb, {e_bb}, v_brb, 3446 3447 Middle Slice (j) 3448 {e^{(k-1)-j}_lf}, {f^{j*(k-1)+n}_f}, e^j_rf, 3449 f^{i*(k-1)+j}_l, {c^{(j*(k-1) + i)*(k-1)+n}_t}, f^{j*(k-1)+i}_r, 3450 e^j_lb, {f^{j*(k-1)+(k-1)-n}_b}, e^{(k-1)-j}_rb, 3451 3452 Top Slice 3453 v_tlf, {e_tf}, v_trf, 3454 e^{(k-1)-i}_tl, {f^{i*(k-1)}_t}, e^{i}_tr, 3455 v_tlb, {e^{(k-1)-n}_tb}, v_trb, 3456 */ 3457 { 3458 const PetscInt oc = 0; 3459 const PetscInt ofb = oc + PetscSqr(k-1)*(k-1); 3460 const PetscInt oft = ofb + PetscSqr(k-1); 3461 const PetscInt off = oft + PetscSqr(k-1); 3462 const PetscInt ofk = off + PetscSqr(k-1); 3463 const PetscInt ofr = ofk + PetscSqr(k-1); 3464 const PetscInt ofl = ofr + PetscSqr(k-1); 3465 const PetscInt oebl = ofl + PetscSqr(k-1); 3466 const PetscInt oebb = oebl + (k-1); 3467 const PetscInt oebr = oebb + (k-1); 3468 const PetscInt oebf = oebr + (k-1); 3469 const PetscInt oetf = oebf + (k-1); 3470 const PetscInt oetr = oetf + (k-1); 3471 const PetscInt oetb = oetr + (k-1); 3472 const PetscInt oetl = oetb + (k-1); 3473 const PetscInt oerf = oetl + (k-1); 3474 const PetscInt oelf = oerf + (k-1); 3475 const PetscInt oelb = oelf + (k-1); 3476 const PetscInt oerb = oelb + (k-1); 3477 const PetscInt ovblf = oerb + (k-1); 3478 const PetscInt ovblb = ovblf + 1; 3479 const PetscInt ovbrb = ovblb + 1; 3480 const PetscInt ovbrf = ovbrb + 1; 3481 const PetscInt ovtlf = ovbrf + 1; 3482 const PetscInt ovtrf = ovtlf + 1; 3483 const PetscInt ovtrb = ovtrf + 1; 3484 const PetscInt ovtlb = ovtrb + 1; 3485 PetscInt o, n; 3486 3487 /* Bottom Slice */ 3488 /* bottom */ 3489 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblf*Nc + c + foffset; 3490 for (o = oetf-1; o >= oebf; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 3491 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrf*Nc + c + foffset; 3492 /* middle */ 3493 for (i = 0; i < k-1; ++i) { 3494 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebl+i)*Nc + c + foffset; 3495 for (n = 0; n < k-1; ++n) {o = ofb+n*(k-1)+(k-2)-i; for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset;} 3496 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oebr+(k-2)-i)*Nc + c + foffset; 3497 } 3498 /* top */ 3499 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovblb*Nc + c + foffset; 3500 for (o = oebb; o < oebr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 3501 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovbrb*Nc + c + foffset; 3502 3503 /* Middle Slice */ 3504 for (j = 0; j < k-1; ++j) { 3505 /* bottom */ 3506 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelf+(k-2)-j)*Nc + c + foffset; 3507 for (o = off+j*(k-1); o < off+(j+1)*(k-1); ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 3508 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerf+j)*Nc + c + foffset; 3509 /* middle */ 3510 for (i = 0; i < k-1; ++i) { 3511 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofl+i*(k-1)+j)*Nc + c + foffset; 3512 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oc+(j*(k-1)+i)*(k-1)+n)*Nc + c + foffset; 3513 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (ofr+j*(k-1)+i)*Nc + c + foffset; 3514 } 3515 /* top */ 3516 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oelb+j)*Nc + c + foffset; 3517 for (o = ofk+j*(k-1)+(k-2); o >= ofk+j*(k-1); --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 3518 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oerb+(k-2)-j)*Nc + c + foffset; 3519 } 3520 3521 /* Top Slice */ 3522 /* bottom */ 3523 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlf*Nc + c + foffset; 3524 for (o = oetf; o < oetr; ++o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 3525 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrf*Nc + c + foffset; 3526 /* middle */ 3527 for (i = 0; i < k-1; ++i) { 3528 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetl+(k-2)-i)*Nc + c + foffset; 3529 for (n = 0; n < k-1; ++n) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oft+i*(k-1)+n)*Nc + c + foffset; 3530 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = (oetr+i)*Nc + c + foffset; 3531 } 3532 /* top */ 3533 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtlb*Nc + c + foffset; 3534 for (o = oetl-1; o >= oetb; --o) for (c = 0; c < Nc; ++c, ++offset) perm[offset] = o*Nc + c + foffset; 3535 for (c = 0; c < Nc; ++c, ++offset) perm[offset] = ovtrb*Nc + c + foffset; 3536 3537 foffset = offset; 3538 } 3539 break; 3540 default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "No spectral ordering for dimension %D", dim); 3541 } 3542 } 3543 if (offset != size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Number of permutation entries %D != %D", offset, size); 3544 /* Check permutation */ 3545 { 3546 PetscInt *check; 3547 3548 ierr = PetscMalloc1(size, &check);CHKERRQ(ierr); 3549 for (i = 0; i < size; ++i) {check[i] = -1; if (perm[i] < 0 || perm[i] >= size) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid permutation index p[%D] = %D", i, perm[i]);} 3550 for (i = 0; i < size; ++i) check[perm[i]] = i; 3551 for (i = 0; i < size; ++i) {if (check[i] < 0) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Missing permutation index %D", i);} 3552 ierr = PetscFree(check);CHKERRQ(ierr); 3553 } 3554 ierr = PetscSectionSetClosurePermutation_Internal(section, (PetscObject) dm, size, PETSC_OWN_POINTER, perm);CHKERRQ(ierr); 3555 PetscFunctionReturn(0); 3556 } 3557 3558 #undef __FUNCT__ 3559 #define __FUNCT__ "DMPlexGetPointDualSpaceFEM" 3560 PetscErrorCode DMPlexGetPointDualSpaceFEM(DM dm, PetscInt point, PetscInt field, PetscDualSpace *dspace) 3561 { 3562 PetscDS prob; 3563 PetscInt depth, Nf, h; 3564 DMLabel label; 3565 PetscErrorCode ierr; 3566 3567 PetscFunctionBeginHot; 3568 prob = dm->prob; 3569 Nf = prob->Nf; 3570 label = dm->depthLabel; 3571 *dspace = NULL; 3572 if (field < Nf) { 3573 PetscObject disc = prob->disc[field]; 3574 3575 if (disc->classid == PETSCFE_CLASSID) { 3576 PetscDualSpace dsp; 3577 3578 ierr = PetscFEGetDualSpace((PetscFE)disc,&dsp);CHKERRQ(ierr); 3579 ierr = DMLabelGetNumValues(label,&depth);CHKERRQ(ierr); 3580 ierr = DMLabelGetValue(label,point,&h);CHKERRQ(ierr); 3581 h = depth - 1 - h; 3582 if (h) { 3583 ierr = PetscDualSpaceGetHeightSubspace(dsp,h,dspace);CHKERRQ(ierr); 3584 } else { 3585 *dspace = dsp; 3586 } 3587 } 3588 } 3589 PetscFunctionReturn(0); 3590 } 3591 3592 3593 #undef __FUNCT__ 3594 #define __FUNCT__ "DMPlexVecGetClosure_Depth1_Static" 3595 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 3596 { 3597 PetscScalar *array, *vArray; 3598 const PetscInt *cone, *coneO; 3599 PetscInt pStart, pEnd, p, numPoints, size = 0, offset = 0; 3600 PetscErrorCode ierr; 3601 3602 PetscFunctionBeginHot; 3603 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 3604 ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr); 3605 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 3606 ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr); 3607 if (!values || !*values) { 3608 if ((point >= pStart) && (point < pEnd)) { 3609 PetscInt dof; 3610 3611 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 3612 size += dof; 3613 } 3614 for (p = 0; p < numPoints; ++p) { 3615 const PetscInt cp = cone[p]; 3616 PetscInt dof; 3617 3618 if ((cp < pStart) || (cp >= pEnd)) continue; 3619 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 3620 size += dof; 3621 } 3622 if (!values) { 3623 if (csize) *csize = size; 3624 PetscFunctionReturn(0); 3625 } 3626 ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr); 3627 } else { 3628 array = *values; 3629 } 3630 size = 0; 3631 ierr = VecGetArray(v, &vArray);CHKERRQ(ierr); 3632 if ((point >= pStart) && (point < pEnd)) { 3633 PetscInt dof, off, d; 3634 PetscScalar *varr; 3635 3636 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 3637 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 3638 varr = &vArray[off]; 3639 for (d = 0; d < dof; ++d, ++offset) { 3640 array[offset] = varr[d]; 3641 } 3642 size += dof; 3643 } 3644 for (p = 0; p < numPoints; ++p) { 3645 const PetscInt cp = cone[p]; 3646 PetscInt o = coneO[p]; 3647 PetscInt dof, off, d; 3648 PetscScalar *varr; 3649 3650 if ((cp < pStart) || (cp >= pEnd)) continue; 3651 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 3652 ierr = PetscSectionGetOffset(section, cp, &off);CHKERRQ(ierr); 3653 varr = &vArray[off]; 3654 if (o >= 0) { 3655 for (d = 0; d < dof; ++d, ++offset) { 3656 array[offset] = varr[d]; 3657 } 3658 } else { 3659 for (d = dof-1; d >= 0; --d, ++offset) { 3660 array[offset] = varr[d]; 3661 } 3662 } 3663 size += dof; 3664 } 3665 ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr); 3666 if (!*values) { 3667 if (csize) *csize = size; 3668 *values = array; 3669 } else { 3670 if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %d < actual size %d", *csize, size); 3671 *csize = size; 3672 } 3673 PetscFunctionReturn(0); 3674 } 3675 3676 #undef __FUNCT__ 3677 #define __FUNCT__ "DMPlexGetCompressedClosure" 3678 static PetscErrorCode DMPlexGetCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 3679 { 3680 const PetscInt *cla; 3681 PetscInt np, *pts = NULL; 3682 PetscErrorCode ierr; 3683 3684 PetscFunctionBeginHot; 3685 ierr = PetscSectionGetClosureIndex(section, (PetscObject) dm, clSec, clPoints);CHKERRQ(ierr); 3686 if (!*clPoints) { 3687 PetscInt pStart, pEnd, p, q; 3688 3689 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 3690 ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &np, &pts);CHKERRQ(ierr); 3691 /* Compress out points not in the section */ 3692 for (p = 0, q = 0; p < np; p++) { 3693 PetscInt r = pts[2*p]; 3694 if ((r >= pStart) && (r < pEnd)) { 3695 pts[q*2] = r; 3696 pts[q*2+1] = pts[2*p+1]; 3697 ++q; 3698 } 3699 } 3700 np = q; 3701 cla = NULL; 3702 } else { 3703 PetscInt dof, off; 3704 3705 ierr = PetscSectionGetDof(*clSec, point, &dof);CHKERRQ(ierr); 3706 ierr = PetscSectionGetOffset(*clSec, point, &off);CHKERRQ(ierr); 3707 ierr = ISGetIndices(*clPoints, &cla);CHKERRQ(ierr); 3708 np = dof/2; 3709 pts = (PetscInt *) &cla[off]; 3710 } 3711 *numPoints = np; 3712 *points = pts; 3713 *clp = cla; 3714 3715 PetscFunctionReturn(0); 3716 } 3717 3718 #undef __FUNCT__ 3719 #define __FUNCT__ "DMPlexRestoreCompressedClosure" 3720 static PetscErrorCode DMPlexRestoreCompressedClosure(DM dm, PetscSection section, PetscInt point, PetscInt *numPoints, PetscInt **points, PetscSection *clSec, IS *clPoints, const PetscInt **clp) 3721 { 3722 PetscErrorCode ierr; 3723 3724 PetscFunctionBeginHot; 3725 if (!*clPoints) { 3726 ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, numPoints, points);CHKERRQ(ierr); 3727 } else { 3728 ierr = ISRestoreIndices(*clPoints, clp);CHKERRQ(ierr); 3729 } 3730 *numPoints = 0; 3731 *points = NULL; 3732 *clSec = NULL; 3733 *clPoints = NULL; 3734 *clp = NULL; 3735 PetscFunctionReturn(0); 3736 } 3737 3738 #undef __FUNCT__ 3739 #define __FUNCT__ "DMPlexVecGetClosure_Static" 3740 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], const PetscInt perm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 3741 { 3742 PetscInt offset = 0, p; 3743 PetscErrorCode ierr; 3744 3745 PetscFunctionBeginHot; 3746 *size = 0; 3747 for (p = 0; p < numPoints*2; p += 2) { 3748 const PetscInt point = points[p]; 3749 const PetscInt o = points[p+1]; 3750 PetscInt dof, off, d; 3751 const PetscScalar *varr; 3752 3753 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 3754 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 3755 varr = &vArray[off]; 3756 if (o >= 0) { 3757 for (d = 0; d < dof; ++d, ++offset) array[perm ? perm[offset] : offset] = varr[d]; 3758 } else { 3759 for (d = dof-1; d >= 0; --d, ++offset) array[perm ? perm[offset] : offset] = varr[d]; 3760 } 3761 } 3762 *size = offset; 3763 PetscFunctionReturn(0); 3764 } 3765 3766 #undef __FUNCT__ 3767 #define __FUNCT__ "DMPlexVecGetClosure_Fields_Static" 3768 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecGetClosure_Fields_Static(PetscSection section, PetscInt numPoints, const PetscInt points[], PetscInt numFields, const PetscInt perm[], const PetscScalar vArray[], PetscInt *size, PetscScalar array[]) 3769 { 3770 PetscInt offset = 0, f; 3771 PetscErrorCode ierr; 3772 3773 PetscFunctionBeginHot; 3774 *size = 0; 3775 for (f = 0; f < numFields; ++f) { 3776 PetscInt fcomp, p; 3777 3778 ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr); 3779 for (p = 0; p < numPoints*2; p += 2) { 3780 const PetscInt point = points[p]; 3781 const PetscInt o = points[p+1]; 3782 PetscInt fdof, foff, d, c; 3783 const PetscScalar *varr; 3784 3785 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 3786 ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr); 3787 varr = &vArray[foff]; 3788 if (o >= 0) { 3789 for (d = 0; d < fdof; ++d, ++offset) array[perm ? perm[offset] : offset] = varr[d]; 3790 } else { 3791 for (d = fdof/fcomp-1; d >= 0; --d) { 3792 for (c = 0; c < fcomp; ++c, ++offset) { 3793 array[perm ? perm[offset] : offset] = varr[d*fcomp+c]; 3794 } 3795 } 3796 } 3797 } 3798 } 3799 *size = offset; 3800 PetscFunctionReturn(0); 3801 } 3802 3803 #undef __FUNCT__ 3804 #define __FUNCT__ "DMPlexVecGetClosure" 3805 /*@C 3806 DMPlexVecGetClosure - Get an array of the values on the closure of 'point' 3807 3808 Not collective 3809 3810 Input Parameters: 3811 + dm - The DM 3812 . section - The section describing the layout in v, or NULL to use the default section 3813 . v - The local vector 3814 - point - The sieve point in the DM 3815 3816 Output Parameters: 3817 + csize - The number of values in the closure, or NULL 3818 - values - The array of values, which is a borrowed array and should not be freed 3819 3820 Fortran Notes: 3821 Since it returns an array, this routine is only available in Fortran 90, and you must 3822 include petsc.h90 in your code. 3823 3824 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 3825 3826 Level: intermediate 3827 3828 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure() 3829 @*/ 3830 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 3831 { 3832 PetscSection clSection; 3833 IS clPoints; 3834 PetscScalar *array, *vArray; 3835 PetscInt *points = NULL; 3836 const PetscInt *clp, *perm; 3837 PetscInt depth, numFields, numPoints, size; 3838 PetscErrorCode ierr; 3839 3840 PetscFunctionBeginHot; 3841 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3842 if (!section) {ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr);} 3843 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 3844 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 3845 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 3846 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 3847 if (depth == 1 && numFields < 2) { 3848 ierr = DMPlexVecGetClosure_Depth1_Static(dm, section, v, point, csize, values);CHKERRQ(ierr); 3849 PetscFunctionReturn(0); 3850 } 3851 /* Get points */ 3852 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 3853 ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);CHKERRQ(ierr); 3854 /* Get array */ 3855 if (!values || !*values) { 3856 PetscInt asize = 0, dof, p; 3857 3858 for (p = 0; p < numPoints*2; p += 2) { 3859 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 3860 asize += dof; 3861 } 3862 if (!values) { 3863 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 3864 if (csize) *csize = asize; 3865 PetscFunctionReturn(0); 3866 } 3867 ierr = DMGetWorkArray(dm, asize, PETSC_SCALAR, &array);CHKERRQ(ierr); 3868 } else { 3869 array = *values; 3870 } 3871 ierr = VecGetArray(v, &vArray);CHKERRQ(ierr); 3872 /* Get values */ 3873 if (numFields > 0) {ierr = DMPlexVecGetClosure_Fields_Static(section, numPoints, points, numFields, perm, vArray, &size, array);CHKERRQ(ierr);} 3874 else {ierr = DMPlexVecGetClosure_Static(section, numPoints, points, perm, vArray, &size, array);CHKERRQ(ierr);} 3875 /* Cleanup points */ 3876 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 3877 /* Cleanup array */ 3878 ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr); 3879 if (!*values) { 3880 if (csize) *csize = size; 3881 *values = array; 3882 } else { 3883 if (size > *csize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Size of input array %D < actual size %D", *csize, size); 3884 *csize = size; 3885 } 3886 PetscFunctionReturn(0); 3887 } 3888 3889 #undef __FUNCT__ 3890 #define __FUNCT__ "DMPlexVecRestoreClosure" 3891 /*@C 3892 DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point' 3893 3894 Not collective 3895 3896 Input Parameters: 3897 + dm - The DM 3898 . section - The section describing the layout in v, or NULL to use the default section 3899 . v - The local vector 3900 . point - The sieve point in the DM 3901 . csize - The number of values in the closure, or NULL 3902 - values - The array of values, which is a borrowed array and should not be freed 3903 3904 Fortran Notes: 3905 Since it returns an array, this routine is only available in Fortran 90, and you must 3906 include petsc.h90 in your code. 3907 3908 The csize argument is not present in the Fortran 90 binding since it is internal to the array. 3909 3910 Level: intermediate 3911 3912 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure() 3913 @*/ 3914 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[]) 3915 { 3916 PetscInt size = 0; 3917 PetscErrorCode ierr; 3918 3919 PetscFunctionBegin; 3920 /* Should work without recalculating size */ 3921 ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr); 3922 PetscFunctionReturn(0); 3923 } 3924 3925 PETSC_STATIC_INLINE void add (PetscScalar *x, PetscScalar y) {*x += y;} 3926 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x = y;} 3927 3928 #undef __FUNCT__ 3929 #define __FUNCT__ "updatePoint_private" 3930 PETSC_STATIC_INLINE PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscInt perm[], const PetscScalar values[], PetscInt offset, PetscScalar array[]) 3931 { 3932 PetscInt cdof; /* The number of constraints on this point */ 3933 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 3934 PetscScalar *a; 3935 PetscInt off, cind = 0, k; 3936 PetscErrorCode ierr; 3937 3938 PetscFunctionBegin; 3939 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 3940 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 3941 a = &array[off]; 3942 if (!cdof || setBC) { 3943 if (orientation >= 0) { 3944 for (k = 0; k < dof; ++k) { 3945 fuse(&a[k], values[perm ? perm[offset+k] : offset+k]); 3946 } 3947 } else { 3948 for (k = 0; k < dof; ++k) { 3949 fuse(&a[k], values[perm ? perm[offset+dof-k-1] : offset+dof-k-1]); 3950 } 3951 } 3952 } else { 3953 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 3954 if (orientation >= 0) { 3955 for (k = 0; k < dof; ++k) { 3956 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 3957 fuse(&a[k], values[perm ? perm[offset+k] : offset+k]); 3958 } 3959 } else { 3960 for (k = 0; k < dof; ++k) { 3961 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 3962 fuse(&a[k], values[perm ? perm[offset+dof-k-1] : offset+dof-k-1]); 3963 } 3964 } 3965 } 3966 PetscFunctionReturn(0); 3967 } 3968 3969 #undef __FUNCT__ 3970 #define __FUNCT__ "updatePointBC_private" 3971 PETSC_STATIC_INLINE PetscErrorCode updatePointBC_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscInt orientation, const PetscInt perm[], const PetscScalar values[], PetscInt offset, PetscScalar array[]) 3972 { 3973 PetscInt cdof; /* The number of constraints on this point */ 3974 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 3975 PetscScalar *a; 3976 PetscInt off, cind = 0, k; 3977 PetscErrorCode ierr; 3978 3979 PetscFunctionBegin; 3980 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 3981 ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr); 3982 a = &array[off]; 3983 if (cdof) { 3984 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 3985 if (orientation >= 0) { 3986 for (k = 0; k < dof; ++k) { 3987 if ((cind < cdof) && (k == cdofs[cind])) { 3988 fuse(&a[k], values[perm ? perm[offset+k] : offset+k]); 3989 ++cind; 3990 } 3991 } 3992 } else { 3993 for (k = 0; k < dof; ++k) { 3994 if ((cind < cdof) && (k == cdofs[cind])) { 3995 fuse(&a[k], values[perm ? perm[offset+dof-k-1] : offset+dof-k-1]); 3996 ++cind; 3997 } 3998 } 3999 } 4000 } 4001 PetscFunctionReturn(0); 4002 } 4003 4004 #undef __FUNCT__ 4005 #define __FUNCT__ "updatePointFields_private" 4006 PETSC_STATIC_INLINE PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt o, PetscInt f, PetscInt fcomp, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, const PetscInt perm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[]) 4007 { 4008 PetscScalar *a; 4009 PetscInt fdof, foff, fcdof, foffset = *offset; 4010 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 4011 PetscInt cind = 0, k, c; 4012 PetscErrorCode ierr; 4013 4014 PetscFunctionBegin; 4015 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 4016 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr); 4017 ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr); 4018 a = &array[foff]; 4019 if (!fcdof || setBC) { 4020 if (o >= 0) { 4021 for (k = 0; k < fdof; ++k) fuse(&a[k], values[perm ? perm[foffset+k] : foffset+k]); 4022 } else { 4023 for (k = fdof/fcomp-1; k >= 0; --k) { 4024 for (c = 0; c < fcomp; ++c) { 4025 fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[perm ? perm[foffset+k*fcomp+c] : foffset+k*fcomp+c]); 4026 } 4027 } 4028 } 4029 } else { 4030 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 4031 if (o >= 0) { 4032 for (k = 0; k < fdof; ++k) { 4033 if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;} 4034 fuse(&a[k], values[perm ? perm[foffset+k] : foffset+k]); 4035 } 4036 } else { 4037 for (k = fdof/fcomp-1; k >= 0; --k) { 4038 for (c = 0; c < fcomp; ++c) { 4039 if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;} 4040 fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[perm ? perm[foffset+k*fcomp+c] : foffset+k*fcomp+c]); 4041 } 4042 } 4043 } 4044 } 4045 *offset += fdof; 4046 PetscFunctionReturn(0); 4047 } 4048 4049 #undef __FUNCT__ 4050 #define __FUNCT__ "updatePointFieldsBC_private" 4051 PETSC_STATIC_INLINE PetscErrorCode updatePointFieldsBC_private(PetscSection section, PetscInt point, PetscInt o, PetscInt f, PetscInt fcomp, void (*fuse)(PetscScalar*, PetscScalar), const PetscInt perm[], const PetscScalar values[], PetscInt *offset, PetscScalar array[]) 4052 { 4053 PetscScalar *a; 4054 PetscInt fdof, foff, fcdof, foffset = *offset; 4055 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 4056 PetscInt cind = 0, k, c; 4057 PetscErrorCode ierr; 4058 4059 PetscFunctionBegin; 4060 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 4061 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr); 4062 ierr = PetscSectionGetFieldOffset(section, point, f, &foff);CHKERRQ(ierr); 4063 a = &array[foff]; 4064 if (fcdof) { 4065 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 4066 if (o >= 0) { 4067 for (k = 0; k < fdof; ++k) { 4068 if ((cind < fcdof) && (k == fcdofs[cind])) { 4069 fuse(&a[k], values[perm ? perm[foffset+k] : foffset+k]); 4070 ++cind; 4071 } 4072 } 4073 } else { 4074 for (k = fdof/fcomp-1; k >= 0; --k) { 4075 for (c = 0; c < fcomp; ++c) { 4076 if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) { 4077 fuse(&a[(fdof/fcomp-1-k)*fcomp+c], values[perm ? perm[foffset+k*fcomp+c] : foffset+k*fcomp+c]); 4078 ++cind; 4079 } 4080 } 4081 } 4082 } 4083 } 4084 *offset += fdof; 4085 PetscFunctionReturn(0); 4086 } 4087 4088 #undef __FUNCT__ 4089 #define __FUNCT__ "DMPlexVecSetClosure_Depth1_Static" 4090 PETSC_STATIC_INLINE PetscErrorCode DMPlexVecSetClosure_Depth1_Static(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 4091 { 4092 PetscScalar *array; 4093 const PetscInt *cone, *coneO; 4094 PetscInt pStart, pEnd, p, numPoints, off, dof; 4095 PetscErrorCode ierr; 4096 4097 PetscFunctionBeginHot; 4098 ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr); 4099 ierr = DMPlexGetConeSize(dm, point, &numPoints);CHKERRQ(ierr); 4100 ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr); 4101 ierr = DMPlexGetConeOrientation(dm, point, &coneO);CHKERRQ(ierr); 4102 ierr = VecGetArray(v, &array);CHKERRQ(ierr); 4103 for (p = 0, off = 0; p <= numPoints; ++p, off += dof) { 4104 const PetscInt cp = !p ? point : cone[p-1]; 4105 const PetscInt o = !p ? 0 : coneO[p-1]; 4106 4107 if ((cp < pStart) || (cp >= pEnd)) {dof = 0; continue;} 4108 ierr = PetscSectionGetDof(section, cp, &dof);CHKERRQ(ierr); 4109 /* ADD_VALUES */ 4110 { 4111 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 4112 PetscScalar *a; 4113 PetscInt cdof, coff, cind = 0, k; 4114 4115 ierr = PetscSectionGetConstraintDof(section, cp, &cdof);CHKERRQ(ierr); 4116 ierr = PetscSectionGetOffset(section, cp, &coff);CHKERRQ(ierr); 4117 a = &array[coff]; 4118 if (!cdof) { 4119 if (o >= 0) { 4120 for (k = 0; k < dof; ++k) { 4121 a[k] += values[off+k]; 4122 } 4123 } else { 4124 for (k = 0; k < dof; ++k) { 4125 a[k] += values[off+dof-k-1]; 4126 } 4127 } 4128 } else { 4129 ierr = PetscSectionGetConstraintIndices(section, cp, &cdofs);CHKERRQ(ierr); 4130 if (o >= 0) { 4131 for (k = 0; k < dof; ++k) { 4132 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 4133 a[k] += values[off+k]; 4134 } 4135 } else { 4136 for (k = 0; k < dof; ++k) { 4137 if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;} 4138 a[k] += values[off+dof-k-1]; 4139 } 4140 } 4141 } 4142 } 4143 } 4144 ierr = VecRestoreArray(v, &array);CHKERRQ(ierr); 4145 PetscFunctionReturn(0); 4146 } 4147 4148 #undef __FUNCT__ 4149 #define __FUNCT__ "DMPlexVecSetClosure" 4150 /*@C 4151 DMPlexVecSetClosure - Set an array of the values on the closure of 'point' 4152 4153 Not collective 4154 4155 Input Parameters: 4156 + dm - The DM 4157 . section - The section describing the layout in v, or NULL to use the default section 4158 . v - The local vector 4159 . point - The sieve point in the DM 4160 . values - The array of values 4161 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 4162 4163 Fortran Notes: 4164 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 4165 4166 Level: intermediate 4167 4168 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure() 4169 @*/ 4170 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) 4171 { 4172 PetscSection clSection; 4173 IS clPoints; 4174 PetscScalar *array; 4175 PetscInt *points = NULL; 4176 const PetscInt *clp, *perm; 4177 PetscInt depth, numFields, numPoints, p; 4178 PetscErrorCode ierr; 4179 4180 PetscFunctionBeginHot; 4181 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4182 if (!section) {ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr);} 4183 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 4184 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 4185 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 4186 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 4187 if (depth == 1 && numFields < 2 && mode == ADD_VALUES) { 4188 ierr = DMPlexVecSetClosure_Depth1_Static(dm, section, v, point, values, mode);CHKERRQ(ierr); 4189 PetscFunctionReturn(0); 4190 } 4191 /* Get points */ 4192 ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);CHKERRQ(ierr); 4193 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 4194 /* Get array */ 4195 ierr = VecGetArray(v, &array);CHKERRQ(ierr); 4196 /* Get values */ 4197 if (numFields > 0) { 4198 PetscInt offset = 0, fcomp, f; 4199 for (f = 0; f < numFields; ++f) { 4200 ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr); 4201 switch (mode) { 4202 case INSERT_VALUES: 4203 for (p = 0; p < numPoints*2; p += 2) { 4204 const PetscInt point = points[p]; 4205 const PetscInt o = points[p+1]; 4206 updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_FALSE, perm, values, &offset, array); 4207 } break; 4208 case INSERT_ALL_VALUES: 4209 for (p = 0; p < numPoints*2; p += 2) { 4210 const PetscInt point = points[p]; 4211 const PetscInt o = points[p+1]; 4212 updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_TRUE, perm, values, &offset, array); 4213 } break; 4214 case INSERT_BC_VALUES: 4215 for (p = 0; p < numPoints*2; p += 2) { 4216 const PetscInt point = points[p]; 4217 const PetscInt o = points[p+1]; 4218 updatePointFieldsBC_private(section, point, o, f, fcomp, insert, perm, values, &offset, array); 4219 } break; 4220 case ADD_VALUES: 4221 for (p = 0; p < numPoints*2; p += 2) { 4222 const PetscInt point = points[p]; 4223 const PetscInt o = points[p+1]; 4224 updatePointFields_private(section, point, o, f, fcomp, add, PETSC_FALSE, perm, values, &offset, array); 4225 } break; 4226 case ADD_ALL_VALUES: 4227 for (p = 0; p < numPoints*2; p += 2) { 4228 const PetscInt point = points[p]; 4229 const PetscInt o = points[p+1]; 4230 updatePointFields_private(section, point, o, f, fcomp, add, PETSC_TRUE, perm, values, &offset, array); 4231 } break; 4232 case ADD_BC_VALUES: 4233 for (p = 0; p < numPoints*2; p += 2) { 4234 const PetscInt point = points[p]; 4235 const PetscInt o = points[p+1]; 4236 updatePointFieldsBC_private(section, point, o, f, fcomp, add, perm, values, &offset, array); 4237 } break; 4238 default: 4239 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 4240 } 4241 } 4242 } else { 4243 PetscInt dof, off; 4244 4245 switch (mode) { 4246 case INSERT_VALUES: 4247 for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) { 4248 PetscInt o = points[p+1]; 4249 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 4250 updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, perm, values, off, array); 4251 } break; 4252 case INSERT_ALL_VALUES: 4253 for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) { 4254 PetscInt o = points[p+1]; 4255 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 4256 updatePoint_private(section, points[p], dof, insert, PETSC_TRUE, o, perm, values, off, array); 4257 } break; 4258 case INSERT_BC_VALUES: 4259 for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) { 4260 PetscInt o = points[p+1]; 4261 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 4262 updatePointBC_private(section, points[p], dof, insert, o, perm, values, off, array); 4263 } break; 4264 case ADD_VALUES: 4265 for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) { 4266 PetscInt o = points[p+1]; 4267 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 4268 updatePoint_private(section, points[p], dof, add, PETSC_FALSE, o, perm, values, off, array); 4269 } break; 4270 case ADD_ALL_VALUES: 4271 for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) { 4272 PetscInt o = points[p+1]; 4273 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 4274 updatePoint_private(section, points[p], dof, add, PETSC_TRUE, o, perm, values, off, array); 4275 } break; 4276 case ADD_BC_VALUES: 4277 for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) { 4278 PetscInt o = points[p+1]; 4279 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 4280 updatePointBC_private(section, points[p], dof, add, o, perm, values, off, array); 4281 } break; 4282 default: 4283 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 4284 } 4285 } 4286 /* Cleanup points */ 4287 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 4288 /* Cleanup array */ 4289 ierr = VecRestoreArray(v, &array);CHKERRQ(ierr); 4290 PetscFunctionReturn(0); 4291 } 4292 4293 #undef __FUNCT__ 4294 #define __FUNCT__ "DMPlexVecSetFieldClosure_Internal" 4295 PetscErrorCode DMPlexVecSetFieldClosure_Internal(DM dm, PetscSection section, Vec v, PetscBool fieldActive[], PetscInt point, const PetscScalar values[], InsertMode mode) 4296 { 4297 PetscSection clSection; 4298 IS clPoints; 4299 PetscScalar *array; 4300 PetscInt *points = NULL; 4301 const PetscInt *clp, *perm; 4302 PetscInt numFields, numPoints, p; 4303 PetscInt offset = 0, fcomp, f; 4304 PetscErrorCode ierr; 4305 4306 PetscFunctionBeginHot; 4307 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4308 if (!section) {ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr);} 4309 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 4310 PetscValidHeaderSpecific(v, VEC_CLASSID, 3); 4311 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 4312 /* Get points */ 4313 ierr = PetscSectionGetClosureInversePermutation_Internal(section, (PetscObject) dm, NULL, &perm);CHKERRQ(ierr); 4314 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 4315 /* Get array */ 4316 ierr = VecGetArray(v, &array);CHKERRQ(ierr); 4317 /* Get values */ 4318 for (f = 0; f < numFields; ++f) { 4319 ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr); 4320 if (!fieldActive[f]) { 4321 for (p = 0; p < numPoints*2; p += 2) { 4322 PetscInt fdof; 4323 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 4324 offset += fdof; 4325 } 4326 continue; 4327 } 4328 switch (mode) { 4329 case INSERT_VALUES: 4330 for (p = 0; p < numPoints*2; p += 2) { 4331 const PetscInt point = points[p]; 4332 const PetscInt o = points[p+1]; 4333 updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_FALSE, perm, values, &offset, array); 4334 } break; 4335 case INSERT_ALL_VALUES: 4336 for (p = 0; p < numPoints*2; p += 2) { 4337 const PetscInt point = points[p]; 4338 const PetscInt o = points[p+1]; 4339 updatePointFields_private(section, point, o, f, fcomp, insert, PETSC_TRUE, perm, values, &offset, array); 4340 } break; 4341 case INSERT_BC_VALUES: 4342 for (p = 0; p < numPoints*2; p += 2) { 4343 const PetscInt point = points[p]; 4344 const PetscInt o = points[p+1]; 4345 updatePointFieldsBC_private(section, point, o, f, fcomp, insert, perm, values, &offset, array); 4346 } break; 4347 case ADD_VALUES: 4348 for (p = 0; p < numPoints*2; p += 2) { 4349 const PetscInt point = points[p]; 4350 const PetscInt o = points[p+1]; 4351 updatePointFields_private(section, point, o, f, fcomp, add, PETSC_FALSE, perm, values, &offset, array); 4352 } break; 4353 case ADD_ALL_VALUES: 4354 for (p = 0; p < numPoints*2; p += 2) { 4355 const PetscInt point = points[p]; 4356 const PetscInt o = points[p+1]; 4357 updatePointFields_private(section, point, o, f, fcomp, add, PETSC_TRUE, perm, values, &offset, array); 4358 } break; 4359 default: 4360 SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %d", mode); 4361 } 4362 } 4363 /* Cleanup points */ 4364 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 4365 /* Cleanup array */ 4366 ierr = VecRestoreArray(v, &array);CHKERRQ(ierr); 4367 PetscFunctionReturn(0); 4368 } 4369 4370 #undef __FUNCT__ 4371 #define __FUNCT__ "DMPlexPrintMatSetValues" 4372 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numRIndices, const PetscInt rindices[], PetscInt numCIndices, const PetscInt cindices[], const PetscScalar values[]) 4373 { 4374 PetscMPIInt rank; 4375 PetscInt i, j; 4376 PetscErrorCode ierr; 4377 4378 PetscFunctionBegin; 4379 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr); 4380 ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat for sieve point %D\n", rank, point);CHKERRQ(ierr); 4381 for (i = 0; i < numRIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat row indices[%D] = %D\n", rank, i, rindices[i]);CHKERRQ(ierr);} 4382 for (i = 0; i < numCIndices; i++) {ierr = PetscViewerASCIIPrintf(viewer, "[%d]mat col indices[%D] = %D\n", rank, i, cindices[i]);CHKERRQ(ierr);} 4383 numCIndices = numCIndices ? numCIndices : numRIndices; 4384 for (i = 0; i < numRIndices; i++) { 4385 ierr = PetscViewerASCIIPrintf(viewer, "[%d]", rank);CHKERRQ(ierr); 4386 for (j = 0; j < numCIndices; j++) { 4387 #if defined(PETSC_USE_COMPLEX) 4388 ierr = PetscViewerASCIIPrintf(viewer, " (%g,%g)", (double)PetscRealPart(values[i*numCIndices+j]), (double)PetscImaginaryPart(values[i*numCIndices+j]));CHKERRQ(ierr); 4389 #else 4390 ierr = PetscViewerASCIIPrintf(viewer, " %g", (double)values[i*numCIndices+j]);CHKERRQ(ierr); 4391 #endif 4392 } 4393 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 4394 } 4395 PetscFunctionReturn(0); 4396 } 4397 4398 #undef __FUNCT__ 4399 #define __FUNCT__ "DMPlexGetIndicesPoint_Internal" 4400 /* . off - The global offset of this point */ 4401 PetscErrorCode DMPlexGetIndicesPoint_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[]) 4402 { 4403 PetscInt dof; /* The number of unknowns on this point */ 4404 PetscInt cdof; /* The number of constraints on this point */ 4405 const PetscInt *cdofs; /* The indices of the constrained dofs on this point */ 4406 PetscInt cind = 0, k; 4407 PetscErrorCode ierr; 4408 4409 PetscFunctionBegin; 4410 ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr); 4411 ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr); 4412 if (!cdof || setBC) { 4413 if (orientation >= 0) { 4414 for (k = 0; k < dof; ++k) indices[*loff+k] = off+k; 4415 } else { 4416 for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k; 4417 } 4418 } else { 4419 ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr); 4420 if (orientation >= 0) { 4421 for (k = 0; k < dof; ++k) { 4422 if ((cind < cdof) && (k == cdofs[cind])) { 4423 /* Insert check for returning constrained indices */ 4424 indices[*loff+k] = -(off+k+1); 4425 ++cind; 4426 } else { 4427 indices[*loff+k] = off+k-cind; 4428 } 4429 } 4430 } else { 4431 for (k = 0; k < dof; ++k) { 4432 if ((cind < cdof) && (k == cdofs[cind])) { 4433 /* Insert check for returning constrained indices */ 4434 indices[*loff+dof-k-1] = -(off+k+1); 4435 ++cind; 4436 } else { 4437 indices[*loff+dof-k-1] = off+k-cind; 4438 } 4439 } 4440 } 4441 } 4442 *loff += dof; 4443 PetscFunctionReturn(0); 4444 } 4445 4446 #undef __FUNCT__ 4447 #define __FUNCT__ "DMPlexGetIndicesPointFields_Internal" 4448 /* . off - The global offset of this point */ 4449 PetscErrorCode DMPlexGetIndicesPointFields_Internal(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[]) 4450 { 4451 PetscInt numFields, foff, f; 4452 PetscErrorCode ierr; 4453 4454 PetscFunctionBegin; 4455 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 4456 for (f = 0, foff = 0; f < numFields; ++f) { 4457 PetscInt fdof, fcomp, cfdof; 4458 const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */ 4459 PetscInt cind = 0, k, c; 4460 4461 ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr); 4462 ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr); 4463 ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr); 4464 if (!cfdof || setBC) { 4465 if (orientation >= 0) { 4466 for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k; 4467 } else { 4468 for (k = fdof/fcomp-1; k >= 0; --k) { 4469 for (c = 0; c < fcomp; ++c) { 4470 indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c; 4471 } 4472 } 4473 } 4474 } else { 4475 ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr); 4476 if (orientation >= 0) { 4477 for (k = 0; k < fdof; ++k) { 4478 if ((cind < cfdof) && (k == fcdofs[cind])) { 4479 indices[foffs[f]+k] = -(off+foff+k+1); 4480 ++cind; 4481 } else { 4482 indices[foffs[f]+k] = off+foff+k-cind; 4483 } 4484 } 4485 } else { 4486 for (k = fdof/fcomp-1; k >= 0; --k) { 4487 for (c = 0; c < fcomp; ++c) { 4488 if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) { 4489 indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1); 4490 ++cind; 4491 } else { 4492 indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind; 4493 } 4494 } 4495 } 4496 } 4497 } 4498 foff += (setBC ? fdof : (fdof - cfdof)); 4499 foffs[f] += fdof; 4500 } 4501 PetscFunctionReturn(0); 4502 } 4503 4504 #undef __FUNCT__ 4505 #define __FUNCT__ "DMPlexAnchorsModifyMat" 4506 PetscErrorCode DMPlexAnchorsModifyMat(DM dm, PetscSection section, PetscInt numPoints, PetscInt numIndices, const PetscInt points[], const PetscScalar values[], PetscInt *outNumPoints, PetscInt *outNumIndices, PetscInt *outPoints[], PetscScalar *outValues[], PetscInt offsets[], PetscBool multiplyLeft) 4507 { 4508 Mat cMat; 4509 PetscSection aSec, cSec; 4510 IS aIS; 4511 PetscInt aStart = -1, aEnd = -1; 4512 const PetscInt *anchors; 4513 PetscInt numFields, f, p, q, newP = 0; 4514 PetscInt newNumPoints = 0, newNumIndices = 0; 4515 PetscInt *newPoints, *indices, *newIndices; 4516 PetscInt maxAnchor, maxDof; 4517 PetscInt newOffsets[32]; 4518 PetscInt *pointMatOffsets[32]; 4519 PetscInt *newPointOffsets[32]; 4520 PetscScalar *pointMat[32]; 4521 PetscScalar *newValues=NULL,*tmpValues; 4522 PetscBool anyConstrained = PETSC_FALSE; 4523 PetscErrorCode ierr; 4524 4525 PetscFunctionBegin; 4526 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4527 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 4528 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 4529 4530 ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr); 4531 /* if there are point-to-point constraints */ 4532 if (aSec) { 4533 ierr = PetscMemzero(newOffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr); 4534 ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr); 4535 ierr = PetscSectionGetChart(aSec,&aStart,&aEnd);CHKERRQ(ierr); 4536 /* figure out how many points are going to be in the new element matrix 4537 * (we allow double counting, because it's all just going to be summed 4538 * into the global matrix anyway) */ 4539 for (p = 0; p < 2*numPoints; p+=2) { 4540 PetscInt b = points[p]; 4541 PetscInt bDof = 0, bSecDof; 4542 4543 ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr); 4544 if (!bSecDof) { 4545 continue; 4546 } 4547 if (b >= aStart && b < aEnd) { 4548 ierr = PetscSectionGetDof(aSec,b,&bDof);CHKERRQ(ierr); 4549 } 4550 if (bDof) { 4551 /* this point is constrained */ 4552 /* it is going to be replaced by its anchors */ 4553 PetscInt bOff, q; 4554 4555 anyConstrained = PETSC_TRUE; 4556 newNumPoints += bDof; 4557 ierr = PetscSectionGetOffset(aSec,b,&bOff);CHKERRQ(ierr); 4558 for (q = 0; q < bDof; q++) { 4559 PetscInt a = anchors[bOff + q]; 4560 PetscInt aDof; 4561 4562 ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr); 4563 newNumIndices += aDof; 4564 for (f = 0; f < numFields; ++f) { 4565 PetscInt fDof; 4566 4567 ierr = PetscSectionGetFieldDof(section, a, f, &fDof);CHKERRQ(ierr); 4568 newOffsets[f+1] += fDof; 4569 } 4570 } 4571 } 4572 else { 4573 /* this point is not constrained */ 4574 newNumPoints++; 4575 newNumIndices += bSecDof; 4576 for (f = 0; f < numFields; ++f) { 4577 PetscInt fDof; 4578 4579 ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr); 4580 newOffsets[f+1] += fDof; 4581 } 4582 } 4583 } 4584 } 4585 if (!anyConstrained) { 4586 if (outNumPoints) *outNumPoints = 0; 4587 if (outNumIndices) *outNumIndices = 0; 4588 if (outPoints) *outPoints = NULL; 4589 if (outValues) *outValues = NULL; 4590 if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);} 4591 PetscFunctionReturn(0); 4592 } 4593 4594 if (outNumPoints) *outNumPoints = newNumPoints; 4595 if (outNumIndices) *outNumIndices = newNumIndices; 4596 4597 for (f = 0; f < numFields; ++f) newOffsets[f+1] += newOffsets[f]; 4598 4599 if (!outPoints && !outValues) { 4600 if (offsets) { 4601 for (f = 0; f <= numFields; f++) { 4602 offsets[f] = newOffsets[f]; 4603 } 4604 } 4605 if (aSec) {ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr);} 4606 PetscFunctionReturn(0); 4607 } 4608 4609 if (numFields && newOffsets[numFields] != newNumIndices) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid size for closure %D should be %D", newOffsets[numFields], newNumIndices); 4610 4611 ierr = DMGetDefaultConstraints(dm, &cSec, &cMat);CHKERRQ(ierr); 4612 4613 /* workspaces */ 4614 if (numFields) { 4615 for (f = 0; f < numFields; f++) { 4616 ierr = DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);CHKERRQ(ierr); 4617 ierr = DMGetWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);CHKERRQ(ierr); 4618 } 4619 } 4620 else { 4621 ierr = DMGetWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);CHKERRQ(ierr); 4622 ierr = DMGetWorkArray(dm,numPoints,PETSC_INT,&newPointOffsets[0]);CHKERRQ(ierr); 4623 } 4624 4625 /* get workspaces for the point-to-point matrices */ 4626 if (numFields) { 4627 PetscInt totalOffset, totalMatOffset; 4628 4629 for (p = 0; p < numPoints; p++) { 4630 PetscInt b = points[2*p]; 4631 PetscInt bDof = 0, bSecDof; 4632 4633 ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr); 4634 if (!bSecDof) { 4635 for (f = 0; f < numFields; f++) { 4636 newPointOffsets[f][p + 1] = 0; 4637 pointMatOffsets[f][p + 1] = 0; 4638 } 4639 continue; 4640 } 4641 if (b >= aStart && b < aEnd) { 4642 ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr); 4643 } 4644 if (bDof) { 4645 for (f = 0; f < numFields; f++) { 4646 PetscInt fDof, q, bOff, allFDof = 0; 4647 4648 ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr); 4649 ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr); 4650 for (q = 0; q < bDof; q++) { 4651 PetscInt a = anchors[bOff + q]; 4652 PetscInt aFDof; 4653 4654 ierr = PetscSectionGetFieldDof(section, a, f, &aFDof);CHKERRQ(ierr); 4655 allFDof += aFDof; 4656 } 4657 newPointOffsets[f][p+1] = allFDof; 4658 pointMatOffsets[f][p+1] = fDof * allFDof; 4659 } 4660 } 4661 else { 4662 for (f = 0; f < numFields; f++) { 4663 PetscInt fDof; 4664 4665 ierr = PetscSectionGetFieldDof(section, b, f, &fDof);CHKERRQ(ierr); 4666 newPointOffsets[f][p+1] = fDof; 4667 pointMatOffsets[f][p+1] = 0; 4668 } 4669 } 4670 } 4671 for (f = 0, totalOffset = 0, totalMatOffset = 0; f < numFields; f++) { 4672 newPointOffsets[f][0] = totalOffset; 4673 pointMatOffsets[f][0] = totalMatOffset; 4674 for (p = 0; p < numPoints; p++) { 4675 newPointOffsets[f][p+1] += newPointOffsets[f][p]; 4676 pointMatOffsets[f][p+1] += pointMatOffsets[f][p]; 4677 } 4678 totalOffset = newPointOffsets[f][numPoints]; 4679 totalMatOffset = pointMatOffsets[f][numPoints]; 4680 ierr = DMGetWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);CHKERRQ(ierr); 4681 } 4682 } 4683 else { 4684 for (p = 0; p < numPoints; p++) { 4685 PetscInt b = points[2*p]; 4686 PetscInt bDof = 0, bSecDof; 4687 4688 ierr = PetscSectionGetDof(section,b,&bSecDof);CHKERRQ(ierr); 4689 if (!bSecDof) { 4690 newPointOffsets[0][p + 1] = 0; 4691 pointMatOffsets[0][p + 1] = 0; 4692 continue; 4693 } 4694 if (b >= aStart && b < aEnd) { 4695 ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr); 4696 } 4697 if (bDof) { 4698 PetscInt bOff, q, allDof = 0; 4699 4700 ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr); 4701 for (q = 0; q < bDof; q++) { 4702 PetscInt a = anchors[bOff + q], aDof; 4703 4704 ierr = PetscSectionGetDof(section, a, &aDof);CHKERRQ(ierr); 4705 allDof += aDof; 4706 } 4707 newPointOffsets[0][p+1] = allDof; 4708 pointMatOffsets[0][p+1] = bSecDof * allDof; 4709 } 4710 else { 4711 newPointOffsets[0][p+1] = bSecDof; 4712 pointMatOffsets[0][p+1] = 0; 4713 } 4714 } 4715 newPointOffsets[0][0] = 0; 4716 pointMatOffsets[0][0] = 0; 4717 for (p = 0; p < numPoints; p++) { 4718 newPointOffsets[0][p+1] += newPointOffsets[0][p]; 4719 pointMatOffsets[0][p+1] += pointMatOffsets[0][p]; 4720 } 4721 ierr = DMGetWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);CHKERRQ(ierr); 4722 } 4723 4724 /* output arrays */ 4725 ierr = DMGetWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);CHKERRQ(ierr); 4726 4727 /* get the point-to-point matrices; construct newPoints */ 4728 ierr = PetscSectionGetMaxDof(aSec, &maxAnchor);CHKERRQ(ierr); 4729 ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr); 4730 ierr = DMGetWorkArray(dm,maxDof,PETSC_INT,&indices);CHKERRQ(ierr); 4731 ierr = DMGetWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);CHKERRQ(ierr); 4732 if (numFields) { 4733 for (p = 0, newP = 0; p < numPoints; p++) { 4734 PetscInt b = points[2*p]; 4735 PetscInt o = points[2*p+1]; 4736 PetscInt bDof = 0, bSecDof; 4737 4738 ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr); 4739 if (!bSecDof) { 4740 continue; 4741 } 4742 if (b >= aStart && b < aEnd) { 4743 ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr); 4744 } 4745 if (bDof) { 4746 PetscInt fStart[32], fEnd[32], fAnchorStart[32], fAnchorEnd[32], bOff, q; 4747 4748 fStart[0] = 0; 4749 fEnd[0] = 0; 4750 for (f = 0; f < numFields; f++) { 4751 PetscInt fDof; 4752 4753 ierr = PetscSectionGetFieldDof(cSec, b, f, &fDof);CHKERRQ(ierr); 4754 fStart[f+1] = fStart[f] + fDof; 4755 fEnd[f+1] = fStart[f+1]; 4756 } 4757 ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr); 4758 ierr = DMPlexGetIndicesPointFields_Internal(cSec, b, bOff, fEnd, PETSC_TRUE, o, indices);CHKERRQ(ierr); 4759 4760 fAnchorStart[0] = 0; 4761 fAnchorEnd[0] = 0; 4762 for (f = 0; f < numFields; f++) { 4763 PetscInt fDof = newPointOffsets[f][p + 1] - newPointOffsets[f][p]; 4764 4765 fAnchorStart[f+1] = fAnchorStart[f] + fDof; 4766 fAnchorEnd[f+1] = fAnchorStart[f + 1]; 4767 } 4768 ierr = PetscSectionGetOffset(aSec, b, &bOff);CHKERRQ(ierr); 4769 for (q = 0; q < bDof; q++) { 4770 PetscInt a = anchors[bOff + q], aOff; 4771 4772 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 4773 newPoints[2*(newP + q)] = a; 4774 newPoints[2*(newP + q) + 1] = 0; 4775 ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr); 4776 ierr = DMPlexGetIndicesPointFields_Internal(section, a, aOff, fAnchorEnd, PETSC_TRUE, 0, newIndices);CHKERRQ(ierr); 4777 } 4778 newP += bDof; 4779 4780 if (outValues) { 4781 /* get the point-to-point submatrix */ 4782 for (f = 0; f < numFields; f++) { 4783 ierr = MatGetValues(cMat,fEnd[f]-fStart[f],indices + fStart[f],fAnchorEnd[f] - fAnchorStart[f],newIndices + fAnchorStart[f],pointMat[f] + pointMatOffsets[f][p]);CHKERRQ(ierr); 4784 } 4785 } 4786 } 4787 else { 4788 newPoints[2 * newP] = b; 4789 newPoints[2 * newP + 1] = o; 4790 newP++; 4791 } 4792 } 4793 } else { 4794 for (p = 0; p < numPoints; p++) { 4795 PetscInt b = points[2*p]; 4796 PetscInt o = points[2*p+1]; 4797 PetscInt bDof = 0, bSecDof; 4798 4799 ierr = PetscSectionGetDof(section, b, &bSecDof);CHKERRQ(ierr); 4800 if (!bSecDof) { 4801 continue; 4802 } 4803 if (b >= aStart && b < aEnd) { 4804 ierr = PetscSectionGetDof(aSec, b, &bDof);CHKERRQ(ierr); 4805 } 4806 if (bDof) { 4807 PetscInt bEnd = 0, bAnchorEnd = 0, bOff; 4808 4809 ierr = PetscSectionGetOffset(cSec, b, &bOff);CHKERRQ(ierr); 4810 ierr = DMPlexGetIndicesPoint_Internal(cSec, b, bOff, &bEnd, PETSC_TRUE, o, indices);CHKERRQ(ierr); 4811 4812 ierr = PetscSectionGetOffset (aSec, b, &bOff);CHKERRQ(ierr); 4813 for (q = 0; q < bDof; q++) { 4814 PetscInt a = anchors[bOff + q], aOff; 4815 4816 /* we take the orientation of ap into account in the order that we constructed the indices above: the newly added points have no orientation */ 4817 4818 newPoints[2*(newP + q)] = a; 4819 newPoints[2*(newP + q) + 1] = 0; 4820 ierr = PetscSectionGetOffset(section, a, &aOff);CHKERRQ(ierr); 4821 ierr = DMPlexGetIndicesPoint_Internal(section, a, aOff, &bAnchorEnd, PETSC_TRUE, 0, newIndices);CHKERRQ(ierr); 4822 } 4823 newP += bDof; 4824 4825 /* get the point-to-point submatrix */ 4826 if (outValues) { 4827 ierr = MatGetValues(cMat,bEnd,indices,bAnchorEnd,newIndices,pointMat[0] + pointMatOffsets[0][p]);CHKERRQ(ierr); 4828 } 4829 } 4830 else { 4831 newPoints[2 * newP] = b; 4832 newPoints[2 * newP + 1] = o; 4833 newP++; 4834 } 4835 } 4836 } 4837 4838 if (outValues) { 4839 ierr = DMGetWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);CHKERRQ(ierr); 4840 ierr = PetscMemzero(tmpValues,newNumIndices*numIndices*sizeof(*tmpValues));CHKERRQ(ierr); 4841 /* multiply constraints on the right */ 4842 if (numFields) { 4843 for (f = 0; f < numFields; f++) { 4844 PetscInt oldOff = offsets[f]; 4845 4846 for (p = 0; p < numPoints; p++) { 4847 PetscInt cStart = newPointOffsets[f][p]; 4848 PetscInt b = points[2 * p]; 4849 PetscInt c, r, k; 4850 PetscInt dof; 4851 4852 ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr); 4853 if (!dof) { 4854 continue; 4855 } 4856 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 4857 PetscInt nCols = newPointOffsets[f][p+1]-cStart; 4858 const PetscScalar *mat = pointMat[f] + pointMatOffsets[f][p]; 4859 4860 for (r = 0; r < numIndices; r++) { 4861 for (c = 0; c < nCols; c++) { 4862 for (k = 0; k < dof; k++) { 4863 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 4864 } 4865 } 4866 } 4867 } 4868 else { 4869 /* copy this column as is */ 4870 for (r = 0; r < numIndices; r++) { 4871 for (c = 0; c < dof; c++) { 4872 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 4873 } 4874 } 4875 } 4876 oldOff += dof; 4877 } 4878 } 4879 } 4880 else { 4881 PetscInt oldOff = 0; 4882 for (p = 0; p < numPoints; p++) { 4883 PetscInt cStart = newPointOffsets[0][p]; 4884 PetscInt b = points[2 * p]; 4885 PetscInt c, r, k; 4886 PetscInt dof; 4887 4888 ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr); 4889 if (!dof) { 4890 continue; 4891 } 4892 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 4893 PetscInt nCols = newPointOffsets[0][p+1]-cStart; 4894 const PetscScalar *mat = pointMat[0] + pointMatOffsets[0][p]; 4895 4896 for (r = 0; r < numIndices; r++) { 4897 for (c = 0; c < nCols; c++) { 4898 for (k = 0; k < dof; k++) { 4899 tmpValues[r * newNumIndices + cStart + c] += mat[k * nCols + c] * values[r * numIndices + oldOff + k]; 4900 } 4901 } 4902 } 4903 } 4904 else { 4905 /* copy this column as is */ 4906 for (r = 0; r < numIndices; r++) { 4907 for (c = 0; c < dof; c++) { 4908 tmpValues[r * newNumIndices + cStart + c] = values[r * numIndices + oldOff + c]; 4909 } 4910 } 4911 } 4912 oldOff += dof; 4913 } 4914 } 4915 4916 if (multiplyLeft) { 4917 ierr = DMGetWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);CHKERRQ(ierr); 4918 ierr = PetscMemzero(newValues,newNumIndices*newNumIndices*sizeof(*newValues));CHKERRQ(ierr); 4919 /* multiply constraints transpose on the left */ 4920 if (numFields) { 4921 for (f = 0; f < numFields; f++) { 4922 PetscInt oldOff = offsets[f]; 4923 4924 for (p = 0; p < numPoints; p++) { 4925 PetscInt rStart = newPointOffsets[f][p]; 4926 PetscInt b = points[2 * p]; 4927 PetscInt c, r, k; 4928 PetscInt dof; 4929 4930 ierr = PetscSectionGetFieldDof(section,b,f,&dof);CHKERRQ(ierr); 4931 if (pointMatOffsets[f][p] < pointMatOffsets[f][p + 1]) { 4932 PetscInt nRows = newPointOffsets[f][p+1]-rStart; 4933 const PetscScalar *PETSC_RESTRICT mat = pointMat[f] + pointMatOffsets[f][p]; 4934 4935 for (r = 0; r < nRows; r++) { 4936 for (c = 0; c < newNumIndices; c++) { 4937 for (k = 0; k < dof; k++) { 4938 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 4939 } 4940 } 4941 } 4942 } 4943 else { 4944 /* copy this row as is */ 4945 for (r = 0; r < dof; r++) { 4946 for (c = 0; c < newNumIndices; c++) { 4947 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 4948 } 4949 } 4950 } 4951 oldOff += dof; 4952 } 4953 } 4954 } 4955 else { 4956 PetscInt oldOff = 0; 4957 4958 for (p = 0; p < numPoints; p++) { 4959 PetscInt rStart = newPointOffsets[0][p]; 4960 PetscInt b = points[2 * p]; 4961 PetscInt c, r, k; 4962 PetscInt dof; 4963 4964 ierr = PetscSectionGetDof(section,b,&dof);CHKERRQ(ierr); 4965 if (pointMatOffsets[0][p] < pointMatOffsets[0][p + 1]) { 4966 PetscInt nRows = newPointOffsets[0][p+1]-rStart; 4967 const PetscScalar *PETSC_RESTRICT mat = pointMat[0] + pointMatOffsets[0][p]; 4968 4969 for (r = 0; r < nRows; r++) { 4970 for (c = 0; c < newNumIndices; c++) { 4971 for (k = 0; k < dof; k++) { 4972 newValues[(rStart + r) * newNumIndices + c] += mat[k * nRows + r] * tmpValues[(oldOff + k) * newNumIndices + c]; 4973 } 4974 } 4975 } 4976 } 4977 else { 4978 /* copy this row as is */ 4979 for (r = 0; r < dof; r++) { 4980 for (c = 0; c < newNumIndices; c++) { 4981 newValues[(rStart + r) * newNumIndices + c] = tmpValues[(oldOff + r) * newNumIndices + c]; 4982 } 4983 } 4984 } 4985 oldOff += dof; 4986 } 4987 } 4988 4989 ierr = DMRestoreWorkArray(dm,newNumIndices*numIndices,PETSC_SCALAR,&tmpValues);CHKERRQ(ierr); 4990 } 4991 else { 4992 newValues = tmpValues; 4993 } 4994 } 4995 4996 /* clean up */ 4997 ierr = DMRestoreWorkArray(dm,maxDof,PETSC_INT,&indices);CHKERRQ(ierr); 4998 ierr = DMRestoreWorkArray(dm,maxAnchor*maxDof,PETSC_INT,&newIndices);CHKERRQ(ierr); 4999 5000 if (numFields) { 5001 for (f = 0; f < numFields; f++) { 5002 ierr = DMRestoreWorkArray(dm,pointMatOffsets[f][numPoints],PETSC_SCALAR,&pointMat[f]);CHKERRQ(ierr); 5003 ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[f]);CHKERRQ(ierr); 5004 ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[f]);CHKERRQ(ierr); 5005 } 5006 } 5007 else { 5008 ierr = DMRestoreWorkArray(dm,pointMatOffsets[0][numPoints],PETSC_SCALAR,&pointMat[0]);CHKERRQ(ierr); 5009 ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&pointMatOffsets[0]);CHKERRQ(ierr); 5010 ierr = DMRestoreWorkArray(dm,numPoints+1,PETSC_INT,&newPointOffsets[0]);CHKERRQ(ierr); 5011 } 5012 ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr); 5013 5014 /* output */ 5015 if (outPoints) { 5016 *outPoints = newPoints; 5017 } 5018 else { 5019 ierr = DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);CHKERRQ(ierr); 5020 } 5021 if (outValues) { 5022 *outValues = newValues; 5023 } 5024 for (f = 0; f <= numFields; f++) { 5025 offsets[f] = newOffsets[f]; 5026 } 5027 PetscFunctionReturn(0); 5028 } 5029 5030 #undef __FUNCT__ 5031 #define __FUNCT__ "DMPlexGetClosureIndices" 5032 PetscErrorCode DMPlexGetClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices, PetscInt *outOffsets) 5033 { 5034 PetscSection clSection; 5035 IS clPoints; 5036 const PetscInt *clp; 5037 PetscInt *points = NULL, *pointsNew; 5038 PetscInt numPoints, numPointsNew; 5039 PetscInt offsets[32]; 5040 PetscInt Nf, Nind, NindNew, off, globalOff, f, p; 5041 PetscErrorCode ierr; 5042 5043 PetscFunctionBegin; 5044 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5045 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5046 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 5047 if (numIndices) PetscValidPointer(numIndices, 4); 5048 PetscValidPointer(indices, 5); 5049 ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr); 5050 if (Nf > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", Nf); 5051 ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr); 5052 /* Get points in closure */ 5053 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5054 /* Get number of indices and indices per field */ 5055 for (p = 0, Nind = 0; p < numPoints*2; p += 2) { 5056 PetscInt dof, fdof; 5057 5058 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 5059 for (f = 0; f < Nf; ++f) { 5060 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 5061 offsets[f+1] += fdof; 5062 } 5063 Nind += dof; 5064 } 5065 for (f = 1; f < Nf; ++f) offsets[f+1] += offsets[f]; 5066 if (Nf && offsets[Nf] != Nind) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[Nf], Nind); 5067 /* Correct for hanging node constraints */ 5068 { 5069 ierr = DMPlexAnchorsModifyMat(dm, section, numPoints, Nind, points, NULL, &numPointsNew, &NindNew, &pointsNew, NULL, offsets, PETSC_TRUE);CHKERRQ(ierr); 5070 if (numPointsNew) { 5071 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5072 numPoints = numPointsNew; 5073 Nind = NindNew; 5074 points = pointsNew; 5075 } 5076 } 5077 /* Calculate indices */ 5078 ierr = DMGetWorkArray(dm, Nind, PETSC_INT, indices);CHKERRQ(ierr); 5079 if (Nf) { 5080 if (outOffsets) { 5081 PetscInt f; 5082 5083 for (f = 0; f <= Nf; f++) { 5084 outOffsets[f] = offsets[f]; 5085 } 5086 } 5087 for (p = 0; p < numPoints*2; p += 2) { 5088 PetscInt o = points[p+1]; 5089 ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr); 5090 DMPlexGetIndicesPointFields_Internal(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, *indices); 5091 } 5092 } else { 5093 for (p = 0, off = 0; p < numPoints*2; p += 2) { 5094 PetscInt o = points[p+1]; 5095 ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr); 5096 DMPlexGetIndicesPoint_Internal(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, *indices); 5097 } 5098 } 5099 /* Cleanup points */ 5100 if (numPointsNew) { 5101 ierr = DMRestoreWorkArray(dm, 2*numPointsNew, PETSC_INT, &pointsNew);CHKERRQ(ierr); 5102 } else { 5103 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5104 } 5105 if (numIndices) *numIndices = Nind; 5106 PetscFunctionReturn(0); 5107 } 5108 5109 #undef __FUNCT__ 5110 #define __FUNCT__ "DMPlexRestoreClosureIndices" 5111 PetscErrorCode DMPlexRestoreClosureIndices(DM dm, PetscSection section, PetscSection globalSection, PetscInt point, PetscInt *numIndices, PetscInt **indices,PetscInt *outOffsets) 5112 { 5113 PetscErrorCode ierr; 5114 5115 PetscFunctionBegin; 5116 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5117 PetscValidPointer(indices, 5); 5118 ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, indices);CHKERRQ(ierr); 5119 PetscFunctionReturn(0); 5120 } 5121 5122 #undef __FUNCT__ 5123 #define __FUNCT__ "DMPlexMatSetClosure" 5124 /*@C 5125 DMPlexMatSetClosure - Set an array of the values on the closure of 'point' 5126 5127 Not collective 5128 5129 Input Parameters: 5130 + dm - The DM 5131 . section - The section describing the layout in v, or NULL to use the default section 5132 . globalSection - The section describing the layout in v, or NULL to use the default global section 5133 . A - The matrix 5134 . point - The sieve point in the DM 5135 . values - The array of values 5136 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions 5137 5138 Fortran Notes: 5139 This routine is only available in Fortran 90, and you must include petsc.h90 in your code. 5140 5141 Level: intermediate 5142 5143 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure() 5144 @*/ 5145 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 5146 { 5147 DM_Plex *mesh = (DM_Plex*) dm->data; 5148 PetscSection clSection; 5149 IS clPoints; 5150 PetscInt *points = NULL, *newPoints; 5151 const PetscInt *clp; 5152 PetscInt *indices; 5153 PetscInt offsets[32]; 5154 PetscInt numFields, numPoints, newNumPoints, numIndices, newNumIndices, dof, off, globalOff, p, f; 5155 PetscScalar *newValues; 5156 PetscErrorCode ierr; 5157 5158 PetscFunctionBegin; 5159 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5160 if (!section) {ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr);} 5161 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 5162 if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);} 5163 PetscValidHeaderSpecific(globalSection, PETSC_SECTION_CLASSID, 3); 5164 PetscValidHeaderSpecific(A, MAT_CLASSID, 4); 5165 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 5166 if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 5167 ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr); 5168 ierr = DMPlexGetCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5169 for (p = 0, numIndices = 0; p < numPoints*2; p += 2) { 5170 PetscInt fdof; 5171 5172 ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr); 5173 for (f = 0; f < numFields; ++f) { 5174 ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr); 5175 offsets[f+1] += fdof; 5176 } 5177 numIndices += dof; 5178 } 5179 for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f]; 5180 5181 if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices); 5182 ierr = DMPlexAnchorsModifyMat(dm,section,numPoints,numIndices,points,values,&newNumPoints,&newNumIndices,&newPoints,&newValues,offsets,PETSC_TRUE);CHKERRQ(ierr); 5183 if (newNumPoints) { 5184 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5185 numPoints = newNumPoints; 5186 numIndices = newNumIndices; 5187 points = newPoints; 5188 values = newValues; 5189 } 5190 ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr); 5191 if (numFields) { 5192 for (p = 0; p < numPoints*2; p += 2) { 5193 PetscInt o = points[p+1]; 5194 ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr); 5195 DMPlexGetIndicesPointFields_Internal(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices); 5196 } 5197 } else { 5198 for (p = 0, off = 0; p < numPoints*2; p += 2) { 5199 PetscInt o = points[p+1]; 5200 ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr); 5201 DMPlexGetIndicesPoint_Internal(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices); 5202 } 5203 } 5204 if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr);} 5205 ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode); 5206 if (mesh->printFEM > 1) { 5207 PetscInt i; 5208 ierr = PetscPrintf(PETSC_COMM_SELF, " Indices:");CHKERRQ(ierr); 5209 for (i = 0; i < numIndices; ++i) {ierr = PetscPrintf(PETSC_COMM_SELF, " %d", indices[i]);CHKERRQ(ierr);} 5210 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 5211 } 5212 if (ierr) { 5213 PetscMPIInt rank; 5214 PetscErrorCode ierr2; 5215 5216 ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2); 5217 ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2); 5218 ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, 0, NULL, values);CHKERRQ(ierr2); 5219 ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2); 5220 CHKERRQ(ierr); 5221 } 5222 if (newNumPoints) { 5223 ierr = DMRestoreWorkArray(dm,newNumIndices*newNumIndices,PETSC_SCALAR,&newValues);CHKERRQ(ierr); 5224 ierr = DMRestoreWorkArray(dm,2*newNumPoints,PETSC_INT,&newPoints);CHKERRQ(ierr); 5225 } 5226 else { 5227 ierr = DMPlexRestoreCompressedClosure(dm,section,point,&numPoints,&points,&clSection,&clPoints,&clp);CHKERRQ(ierr); 5228 } 5229 ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr); 5230 PetscFunctionReturn(0); 5231 } 5232 5233 #undef __FUNCT__ 5234 #define __FUNCT__ "DMPlexMatSetClosureRefined" 5235 PetscErrorCode DMPlexMatSetClosureRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode) 5236 { 5237 DM_Plex *mesh = (DM_Plex*) dmf->data; 5238 PetscInt *fpoints = NULL, *ftotpoints = NULL; 5239 PetscInt *cpoints = NULL; 5240 PetscInt *findices, *cindices; 5241 PetscInt foffsets[32], coffsets[32]; 5242 CellRefiner cellRefiner; 5243 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 5244 PetscErrorCode ierr; 5245 5246 PetscFunctionBegin; 5247 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 5248 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 5249 if (!fsection) {ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);} 5250 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 5251 if (!csection) {ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);} 5252 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 5253 if (!globalFSection) {ierr = DMGetDefaultGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);} 5254 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 5255 if (!globalCSection) {ierr = DMGetDefaultGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);} 5256 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 5257 PetscValidHeaderSpecific(A, MAT_CLASSID, 7); 5258 ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr); 5259 if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 5260 ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr); 5261 ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr); 5262 /* Column indices */ 5263 ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 5264 maxFPoints = numCPoints; 5265 /* Compress out points not in the section */ 5266 /* TODO: Squeeze out points with 0 dof as well */ 5267 ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr); 5268 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 5269 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 5270 cpoints[q*2] = cpoints[p]; 5271 cpoints[q*2+1] = cpoints[p+1]; 5272 ++q; 5273 } 5274 } 5275 numCPoints = q; 5276 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 5277 PetscInt fdof; 5278 5279 ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr); 5280 if (!dof) continue; 5281 for (f = 0; f < numFields; ++f) { 5282 ierr = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr); 5283 coffsets[f+1] += fdof; 5284 } 5285 numCIndices += dof; 5286 } 5287 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 5288 /* Row indices */ 5289 ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr); 5290 ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr); 5291 ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);CHKERRQ(ierr); 5292 for (r = 0, q = 0; r < numSubcells; ++r) { 5293 /* TODO Map from coarse to fine cells */ 5294 ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 5295 /* Compress out points not in the section */ 5296 ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr); 5297 for (p = 0; p < numFPoints*2; p += 2) { 5298 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 5299 ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr); 5300 if (!dof) continue; 5301 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 5302 if (s < q) continue; 5303 ftotpoints[q*2] = fpoints[p]; 5304 ftotpoints[q*2+1] = fpoints[p+1]; 5305 ++q; 5306 } 5307 } 5308 ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 5309 } 5310 numFPoints = q; 5311 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 5312 PetscInt fdof; 5313 5314 ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr); 5315 if (!dof) continue; 5316 for (f = 0; f < numFields; ++f) { 5317 ierr = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr); 5318 foffsets[f+1] += fdof; 5319 } 5320 numFIndices += dof; 5321 } 5322 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 5323 5324 if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", foffsets[numFields], numFIndices); 5325 if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", coffsets[numFields], numCIndices); 5326 ierr = DMGetWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr); 5327 ierr = DMGetWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr); 5328 if (numFields) { 5329 for (p = 0; p < numFPoints*2; p += 2) { 5330 PetscInt o = ftotpoints[p+1]; 5331 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr); 5332 DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, o, findices); 5333 } 5334 for (p = 0; p < numCPoints*2; p += 2) { 5335 PetscInt o = cpoints[p+1]; 5336 ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr); 5337 DMPlexGetIndicesPointFields_Internal(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, o, cindices); 5338 } 5339 } else { 5340 for (p = 0, off = 0; p < numFPoints*2; p += 2) { 5341 PetscInt o = ftotpoints[p+1]; 5342 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr); 5343 DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, findices); 5344 } 5345 for (p = 0, off = 0; p < numCPoints*2; p += 2) { 5346 PetscInt o = cpoints[p+1]; 5347 ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr); 5348 DMPlexGetIndicesPoint_Internal(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, cindices); 5349 } 5350 } 5351 if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr);} 5352 ierr = MatSetValues(A, numFIndices, findices, numCIndices, cindices, values, mode); 5353 if (ierr) { 5354 PetscMPIInt rank; 5355 PetscErrorCode ierr2; 5356 5357 ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2); 5358 ierr2 = (*PetscErrorPrintf)("[%d]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2); 5359 ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numFIndices, findices, numCIndices, cindices, values);CHKERRQ(ierr2); 5360 ierr2 = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr2); 5361 ierr2 = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr2); 5362 CHKERRQ(ierr); 5363 } 5364 ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);CHKERRQ(ierr); 5365 ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 5366 ierr = DMRestoreWorkArray(dmf, numFIndices, PETSC_INT, &findices);CHKERRQ(ierr); 5367 ierr = DMRestoreWorkArray(dmc, numCIndices, PETSC_INT, &cindices);CHKERRQ(ierr); 5368 PetscFunctionReturn(0); 5369 } 5370 5371 #undef __FUNCT__ 5372 #define __FUNCT__ "DMPlexMatGetClosureIndicesRefined" 5373 PetscErrorCode DMPlexMatGetClosureIndicesRefined(DM dmf, PetscSection fsection, PetscSection globalFSection, DM dmc, PetscSection csection, PetscSection globalCSection, PetscInt point, PetscInt cindices[], PetscInt findices[]) 5374 { 5375 PetscInt *fpoints = NULL, *ftotpoints = NULL; 5376 PetscInt *cpoints = NULL; 5377 PetscInt foffsets[32], coffsets[32]; 5378 CellRefiner cellRefiner; 5379 PetscInt numFields, numSubcells, maxFPoints, numFPoints, numCPoints, numFIndices, numCIndices, dof, off, globalOff, pStart, pEnd, p, q, r, s, f; 5380 PetscErrorCode ierr; 5381 5382 PetscFunctionBegin; 5383 PetscValidHeaderSpecific(dmf, DM_CLASSID, 1); 5384 PetscValidHeaderSpecific(dmc, DM_CLASSID, 4); 5385 if (!fsection) {ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr);} 5386 PetscValidHeaderSpecific(fsection, PETSC_SECTION_CLASSID, 2); 5387 if (!csection) {ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr);} 5388 PetscValidHeaderSpecific(csection, PETSC_SECTION_CLASSID, 5); 5389 if (!globalFSection) {ierr = DMGetDefaultGlobalSection(dmf, &globalFSection);CHKERRQ(ierr);} 5390 PetscValidHeaderSpecific(globalFSection, PETSC_SECTION_CLASSID, 3); 5391 if (!globalCSection) {ierr = DMGetDefaultGlobalSection(dmc, &globalCSection);CHKERRQ(ierr);} 5392 PetscValidHeaderSpecific(globalCSection, PETSC_SECTION_CLASSID, 6); 5393 ierr = PetscSectionGetNumFields(fsection, &numFields);CHKERRQ(ierr); 5394 if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dmf), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields); 5395 ierr = PetscMemzero(foffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr); 5396 ierr = PetscMemzero(coffsets, 32 * sizeof(PetscInt));CHKERRQ(ierr); 5397 /* Column indices */ 5398 ierr = DMPlexGetTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 5399 maxFPoints = numCPoints; 5400 /* Compress out points not in the section */ 5401 /* TODO: Squeeze out points with 0 dof as well */ 5402 ierr = PetscSectionGetChart(csection, &pStart, &pEnd);CHKERRQ(ierr); 5403 for (p = 0, q = 0; p < numCPoints*2; p += 2) { 5404 if ((cpoints[p] >= pStart) && (cpoints[p] < pEnd)) { 5405 cpoints[q*2] = cpoints[p]; 5406 cpoints[q*2+1] = cpoints[p+1]; 5407 ++q; 5408 } 5409 } 5410 numCPoints = q; 5411 for (p = 0, numCIndices = 0; p < numCPoints*2; p += 2) { 5412 PetscInt fdof; 5413 5414 ierr = PetscSectionGetDof(csection, cpoints[p], &dof);CHKERRQ(ierr); 5415 if (!dof) continue; 5416 for (f = 0; f < numFields; ++f) { 5417 ierr = PetscSectionGetFieldDof(csection, cpoints[p], f, &fdof);CHKERRQ(ierr); 5418 coffsets[f+1] += fdof; 5419 } 5420 numCIndices += dof; 5421 } 5422 for (f = 1; f < numFields; ++f) coffsets[f+1] += coffsets[f]; 5423 /* Row indices */ 5424 ierr = DMPlexGetCellRefiner_Internal(dmc, &cellRefiner);CHKERRQ(ierr); 5425 ierr = CellRefinerGetAffineTransforms_Internal(cellRefiner, &numSubcells, NULL, NULL, NULL);CHKERRQ(ierr); 5426 ierr = DMGetWorkArray(dmf, maxFPoints*2*numSubcells, PETSC_INT, &ftotpoints);CHKERRQ(ierr); 5427 for (r = 0, q = 0; r < numSubcells; ++r) { 5428 /* TODO Map from coarse to fine cells */ 5429 ierr = DMPlexGetTransitiveClosure(dmf, point*numSubcells + r, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 5430 /* Compress out points not in the section */ 5431 ierr = PetscSectionGetChart(fsection, &pStart, &pEnd);CHKERRQ(ierr); 5432 for (p = 0; p < numFPoints*2; p += 2) { 5433 if ((fpoints[p] >= pStart) && (fpoints[p] < pEnd)) { 5434 ierr = PetscSectionGetDof(fsection, fpoints[p], &dof);CHKERRQ(ierr); 5435 if (!dof) continue; 5436 for (s = 0; s < q; ++s) if (fpoints[p] == ftotpoints[s*2]) break; 5437 if (s < q) continue; 5438 ftotpoints[q*2] = fpoints[p]; 5439 ftotpoints[q*2+1] = fpoints[p+1]; 5440 ++q; 5441 } 5442 } 5443 ierr = DMPlexRestoreTransitiveClosure(dmf, point, PETSC_TRUE, &numFPoints, &fpoints);CHKERRQ(ierr); 5444 } 5445 numFPoints = q; 5446 for (p = 0, numFIndices = 0; p < numFPoints*2; p += 2) { 5447 PetscInt fdof; 5448 5449 ierr = PetscSectionGetDof(fsection, ftotpoints[p], &dof);CHKERRQ(ierr); 5450 if (!dof) continue; 5451 for (f = 0; f < numFields; ++f) { 5452 ierr = PetscSectionGetFieldDof(fsection, ftotpoints[p], f, &fdof);CHKERRQ(ierr); 5453 foffsets[f+1] += fdof; 5454 } 5455 numFIndices += dof; 5456 } 5457 for (f = 1; f < numFields; ++f) foffsets[f+1] += foffsets[f]; 5458 5459 if (numFields && foffsets[numFields] != numFIndices) SETERRQ2(PetscObjectComm((PetscObject)dmf), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", foffsets[numFields], numFIndices); 5460 if (numFields && coffsets[numFields] != numCIndices) SETERRQ2(PetscObjectComm((PetscObject)dmc), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", coffsets[numFields], numCIndices); 5461 if (numFields) { 5462 for (p = 0; p < numFPoints*2; p += 2) { 5463 PetscInt o = ftotpoints[p+1]; 5464 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr); 5465 DMPlexGetIndicesPointFields_Internal(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, foffsets, PETSC_FALSE, o, findices); 5466 } 5467 for (p = 0; p < numCPoints*2; p += 2) { 5468 PetscInt o = cpoints[p+1]; 5469 ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr); 5470 DMPlexGetIndicesPointFields_Internal(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, coffsets, PETSC_FALSE, o, cindices); 5471 } 5472 } else { 5473 for (p = 0, off = 0; p < numFPoints*2; p += 2) { 5474 PetscInt o = ftotpoints[p+1]; 5475 ierr = PetscSectionGetOffset(globalFSection, ftotpoints[p], &globalOff);CHKERRQ(ierr); 5476 DMPlexGetIndicesPoint_Internal(fsection, ftotpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, findices); 5477 } 5478 for (p = 0, off = 0; p < numCPoints*2; p += 2) { 5479 PetscInt o = cpoints[p+1]; 5480 ierr = PetscSectionGetOffset(globalCSection, cpoints[p], &globalOff);CHKERRQ(ierr); 5481 DMPlexGetIndicesPoint_Internal(csection, cpoints[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, cindices); 5482 } 5483 } 5484 ierr = DMRestoreWorkArray(dmf, numCPoints*2*4, PETSC_INT, &ftotpoints);CHKERRQ(ierr); 5485 ierr = DMPlexRestoreTransitiveClosure(dmc, point, PETSC_TRUE, &numCPoints, &cpoints);CHKERRQ(ierr); 5486 PetscFunctionReturn(0); 5487 } 5488 5489 #undef __FUNCT__ 5490 #define __FUNCT__ "DMPlexGetHybridBounds" 5491 /*@ 5492 DMPlexGetHybridBounds - Get the first mesh point of each dimension which is a hybrid 5493 5494 Input Parameter: 5495 . dm - The DMPlex object 5496 5497 Output Parameters: 5498 + cMax - The first hybrid cell 5499 . fMax - The first hybrid face 5500 . eMax - The first hybrid edge 5501 - vMax - The first hybrid vertex 5502 5503 Level: developer 5504 5505 .seealso DMPlexCreateHybridMesh(), DMPlexSetHybridBounds() 5506 @*/ 5507 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax) 5508 { 5509 DM_Plex *mesh = (DM_Plex*) dm->data; 5510 PetscInt dim; 5511 PetscErrorCode ierr; 5512 5513 PetscFunctionBegin; 5514 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5515 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 5516 if (cMax) *cMax = mesh->hybridPointMax[dim]; 5517 if (fMax) *fMax = mesh->hybridPointMax[dim-1]; 5518 if (eMax) *eMax = mesh->hybridPointMax[1]; 5519 if (vMax) *vMax = mesh->hybridPointMax[0]; 5520 PetscFunctionReturn(0); 5521 } 5522 5523 #undef __FUNCT__ 5524 #define __FUNCT__ "DMPlexSetHybridBounds" 5525 /*@ 5526 DMPlexSetHybridBounds - Set the first mesh point of each dimension which is a hybrid 5527 5528 Input Parameters: 5529 . dm - The DMPlex object 5530 . cMax - The first hybrid cell 5531 . fMax - The first hybrid face 5532 . eMax - The first hybrid edge 5533 - vMax - The first hybrid vertex 5534 5535 Level: developer 5536 5537 .seealso DMPlexCreateHybridMesh(), DMPlexGetHybridBounds() 5538 @*/ 5539 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax) 5540 { 5541 DM_Plex *mesh = (DM_Plex*) dm->data; 5542 PetscInt dim; 5543 PetscErrorCode ierr; 5544 5545 PetscFunctionBegin; 5546 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5547 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 5548 if (cMax >= 0) mesh->hybridPointMax[dim] = cMax; 5549 if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax; 5550 if (eMax >= 0) mesh->hybridPointMax[1] = eMax; 5551 if (vMax >= 0) mesh->hybridPointMax[0] = vMax; 5552 PetscFunctionReturn(0); 5553 } 5554 5555 #undef __FUNCT__ 5556 #define __FUNCT__ "DMPlexGetVTKCellHeight" 5557 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight) 5558 { 5559 DM_Plex *mesh = (DM_Plex*) dm->data; 5560 5561 PetscFunctionBegin; 5562 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5563 PetscValidPointer(cellHeight, 2); 5564 *cellHeight = mesh->vtkCellHeight; 5565 PetscFunctionReturn(0); 5566 } 5567 5568 #undef __FUNCT__ 5569 #define __FUNCT__ "DMPlexSetVTKCellHeight" 5570 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight) 5571 { 5572 DM_Plex *mesh = (DM_Plex*) dm->data; 5573 5574 PetscFunctionBegin; 5575 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5576 mesh->vtkCellHeight = cellHeight; 5577 PetscFunctionReturn(0); 5578 } 5579 5580 #undef __FUNCT__ 5581 #define __FUNCT__ "DMPlexCreateNumbering_Private" 5582 /* We can easily have a form that takes an IS instead */ 5583 static PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscInt shift, PetscInt *globalSize, PetscSF sf, IS *numbering) 5584 { 5585 PetscSection section, globalSection; 5586 PetscInt *numbers, p; 5587 PetscErrorCode ierr; 5588 5589 PetscFunctionBegin; 5590 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion);CHKERRQ(ierr); 5591 ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr); 5592 for (p = pStart; p < pEnd; ++p) { 5593 ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr); 5594 } 5595 ierr = PetscSectionSetUp(section);CHKERRQ(ierr); 5596 ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, PETSC_FALSE, &globalSection);CHKERRQ(ierr); 5597 ierr = PetscMalloc1(pEnd - pStart, &numbers);CHKERRQ(ierr); 5598 for (p = pStart; p < pEnd; ++p) { 5599 ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr); 5600 if (numbers[p-pStart] < 0) numbers[p-pStart] -= shift; 5601 else numbers[p-pStart] += shift; 5602 } 5603 ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr); 5604 if (globalSize) { 5605 PetscLayout layout; 5606 ierr = PetscSectionGetPointLayout(PetscObjectComm((PetscObject) dm), globalSection, &layout);CHKERRQ(ierr); 5607 ierr = PetscLayoutGetSize(layout, globalSize);CHKERRQ(ierr); 5608 ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr); 5609 } 5610 ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); 5611 ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr); 5612 PetscFunctionReturn(0); 5613 } 5614 5615 #undef __FUNCT__ 5616 #define __FUNCT__ "DMPlexCreateCellNumbering_Internal" 5617 PetscErrorCode DMPlexCreateCellNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalCellNumbers) 5618 { 5619 PetscInt cellHeight, cStart, cEnd, cMax; 5620 PetscErrorCode ierr; 5621 5622 PetscFunctionBegin; 5623 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 5624 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 5625 ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr); 5626 if (cMax >= 0 && !includeHybrid) cEnd = PetscMin(cEnd, cMax); 5627 ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, 0, NULL, dm->sf, globalCellNumbers);CHKERRQ(ierr); 5628 PetscFunctionReturn(0); 5629 } 5630 5631 #undef __FUNCT__ 5632 #define __FUNCT__ "DMPlexGetCellNumbering" 5633 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers) 5634 { 5635 DM_Plex *mesh = (DM_Plex*) dm->data; 5636 PetscErrorCode ierr; 5637 5638 PetscFunctionBegin; 5639 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5640 if (!mesh->globalCellNumbers) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_FALSE, &mesh->globalCellNumbers);CHKERRQ(ierr);} 5641 *globalCellNumbers = mesh->globalCellNumbers; 5642 PetscFunctionReturn(0); 5643 } 5644 5645 #undef __FUNCT__ 5646 #define __FUNCT__ "DMPlexCreateVertexNumbering_Internal" 5647 PetscErrorCode DMPlexCreateVertexNumbering_Internal(DM dm, PetscBool includeHybrid, IS *globalVertexNumbers) 5648 { 5649 PetscInt vStart, vEnd, vMax; 5650 PetscErrorCode ierr; 5651 5652 PetscFunctionBegin; 5653 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5654 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 5655 ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr); 5656 if (vMax >= 0 && !includeHybrid) vEnd = PetscMin(vEnd, vMax); 5657 ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, 0, NULL, dm->sf, globalVertexNumbers);CHKERRQ(ierr); 5658 PetscFunctionReturn(0); 5659 } 5660 5661 #undef __FUNCT__ 5662 #define __FUNCT__ "DMPlexGetVertexNumbering" 5663 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers) 5664 { 5665 DM_Plex *mesh = (DM_Plex*) dm->data; 5666 PetscErrorCode ierr; 5667 5668 PetscFunctionBegin; 5669 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5670 if (!mesh->globalVertexNumbers) {ierr = DMPlexCreateVertexNumbering_Internal(dm, PETSC_FALSE, &mesh->globalVertexNumbers);CHKERRQ(ierr);} 5671 *globalVertexNumbers = mesh->globalVertexNumbers; 5672 PetscFunctionReturn(0); 5673 } 5674 5675 #undef __FUNCT__ 5676 #define __FUNCT__ "DMPlexCreatePointNumbering" 5677 PetscErrorCode DMPlexCreatePointNumbering(DM dm, IS *globalPointNumbers) 5678 { 5679 IS nums[4]; 5680 PetscInt depths[4]; 5681 PetscInt depth, d, shift = 0; 5682 PetscErrorCode ierr; 5683 5684 PetscFunctionBegin; 5685 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5686 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 5687 /* For unstratified meshes use dim instead of depth */ 5688 if (depth < 0) {ierr = DMGetDimension(dm, &depth);CHKERRQ(ierr);} 5689 depths[0] = depth; depths[1] = 0; 5690 for (d = 2; d <= depth; ++d) depths[d] = depth-d+1; 5691 for (d = 0; d <= depth; ++d) { 5692 PetscInt pStart, pEnd, gsize; 5693 5694 ierr = DMPlexGetDepthStratum(dm, depths[d], &pStart, &pEnd);CHKERRQ(ierr); 5695 ierr = DMPlexCreateNumbering_Private(dm, pStart, pEnd, shift, &gsize, dm->sf, &nums[d]);CHKERRQ(ierr); 5696 shift += gsize; 5697 } 5698 ierr = ISConcatenate(PetscObjectComm((PetscObject) dm), depth+1, nums, globalPointNumbers);CHKERRQ(ierr); 5699 for (d = 0; d <= depth; ++d) {ierr = ISDestroy(&nums[d]);CHKERRQ(ierr);} 5700 PetscFunctionReturn(0); 5701 } 5702 5703 #undef __FUNCT__ 5704 #define __FUNCT__ "DMPlexCheckSymmetry" 5705 /*@ 5706 DMPlexCheckSymmetry - Check that the adjacency information in the mesh is symmetric. 5707 5708 Input Parameters: 5709 + dm - The DMPlex object 5710 5711 Note: This is a useful diagnostic when creating meshes programmatically. 5712 5713 Level: developer 5714 5715 .seealso: DMCreate(), DMCheckSkeleton(), DMCheckFaces() 5716 @*/ 5717 PetscErrorCode DMPlexCheckSymmetry(DM dm) 5718 { 5719 PetscSection coneSection, supportSection; 5720 const PetscInt *cone, *support; 5721 PetscInt coneSize, c, supportSize, s; 5722 PetscInt pStart, pEnd, p, csize, ssize; 5723 PetscErrorCode ierr; 5724 5725 PetscFunctionBegin; 5726 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5727 ierr = DMPlexGetConeSection(dm, &coneSection);CHKERRQ(ierr); 5728 ierr = DMPlexGetSupportSection(dm, &supportSection);CHKERRQ(ierr); 5729 /* Check that point p is found in the support of its cone points, and vice versa */ 5730 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 5731 for (p = pStart; p < pEnd; ++p) { 5732 ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr); 5733 ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr); 5734 for (c = 0; c < coneSize; ++c) { 5735 PetscBool dup = PETSC_FALSE; 5736 PetscInt d; 5737 for (d = c-1; d >= 0; --d) { 5738 if (cone[c] == cone[d]) {dup = PETSC_TRUE; break;} 5739 } 5740 ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr); 5741 ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr); 5742 for (s = 0; s < supportSize; ++s) { 5743 if (support[s] == p) break; 5744 } 5745 if ((s >= supportSize) || (dup && (support[s+1] != p))) { 5746 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", p);CHKERRQ(ierr); 5747 for (s = 0; s < coneSize; ++s) { 5748 ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[s]);CHKERRQ(ierr); 5749 } 5750 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 5751 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", cone[c]);CHKERRQ(ierr); 5752 for (s = 0; s < supportSize; ++s) { 5753 ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[s]);CHKERRQ(ierr); 5754 } 5755 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 5756 if (dup) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not repeatedly found in support of repeated cone point %d", p, cone[c]); 5757 else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in support of cone point %d", p, cone[c]); 5758 } 5759 } 5760 ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr); 5761 ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr); 5762 for (s = 0; s < supportSize; ++s) { 5763 ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr); 5764 ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr); 5765 for (c = 0; c < coneSize; ++c) { 5766 if (cone[c] == p) break; 5767 } 5768 if (c >= coneSize) { 5769 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d support: ", p);CHKERRQ(ierr); 5770 for (c = 0; c < supportSize; ++c) { 5771 ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", support[c]);CHKERRQ(ierr); 5772 } 5773 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 5774 ierr = PetscPrintf(PETSC_COMM_SELF, "p: %d cone: ", support[s]);CHKERRQ(ierr); 5775 for (c = 0; c < coneSize; ++c) { 5776 ierr = PetscPrintf(PETSC_COMM_SELF, "%d, ", cone[c]);CHKERRQ(ierr); 5777 } 5778 ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr); 5779 SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d not found in cone of support point %d", p, support[s]); 5780 } 5781 } 5782 } 5783 ierr = PetscSectionGetStorageSize(coneSection, &csize);CHKERRQ(ierr); 5784 ierr = PetscSectionGetStorageSize(supportSection, &ssize);CHKERRQ(ierr); 5785 if (csize != ssize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Total cone size %d != Total support size %d", csize, ssize); 5786 PetscFunctionReturn(0); 5787 } 5788 5789 #undef __FUNCT__ 5790 #define __FUNCT__ "DMPlexCheckSkeleton" 5791 /*@ 5792 DMPlexCheckSkeleton - Check that each cell has the correct number of vertices 5793 5794 Input Parameters: 5795 + dm - The DMPlex object 5796 . isSimplex - Are the cells simplices or tensor products 5797 - cellHeight - Normally 0 5798 5799 Note: This is a useful diagnostic when creating meshes programmatically. 5800 5801 Level: developer 5802 5803 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckFaces() 5804 @*/ 5805 PetscErrorCode DMPlexCheckSkeleton(DM dm, PetscBool isSimplex, PetscInt cellHeight) 5806 { 5807 PetscInt dim, numCorners, numHybridCorners, vStart, vEnd, cStart, cEnd, cMax, c; 5808 PetscErrorCode ierr; 5809 5810 PetscFunctionBegin; 5811 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5812 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 5813 switch (dim) { 5814 case 1: numCorners = isSimplex ? 2 : 2; numHybridCorners = isSimplex ? 2 : 2; break; 5815 case 2: numCorners = isSimplex ? 3 : 4; numHybridCorners = isSimplex ? 4 : 4; break; 5816 case 3: numCorners = isSimplex ? 4 : 8; numHybridCorners = isSimplex ? 6 : 8; break; 5817 default: 5818 SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle meshes of dimension %d", dim); 5819 } 5820 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 5821 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 5822 ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr); 5823 cMax = cMax >= 0 ? cMax : cEnd; 5824 for (c = cStart; c < cMax; ++c) { 5825 PetscInt *closure = NULL, closureSize, cl, coneSize = 0; 5826 5827 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 5828 for (cl = 0; cl < closureSize*2; cl += 2) { 5829 const PetscInt p = closure[cl]; 5830 if ((p >= vStart) && (p < vEnd)) ++coneSize; 5831 } 5832 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 5833 if (coneSize != numCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has %d vertices != %d", c, coneSize, numCorners); 5834 } 5835 for (c = cMax; c < cEnd; ++c) { 5836 PetscInt *closure = NULL, closureSize, cl, coneSize = 0; 5837 5838 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 5839 for (cl = 0; cl < closureSize*2; cl += 2) { 5840 const PetscInt p = closure[cl]; 5841 if ((p >= vStart) && (p < vEnd)) ++coneSize; 5842 } 5843 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 5844 if (coneSize > numHybridCorners) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Hybrid cell %d has %d vertices > %d", c, coneSize, numHybridCorners); 5845 } 5846 PetscFunctionReturn(0); 5847 } 5848 5849 #undef __FUNCT__ 5850 #define __FUNCT__ "DMPlexCheckFaces" 5851 /*@ 5852 DMPlexCheckFaces - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type 5853 5854 Input Parameters: 5855 + dm - The DMPlex object 5856 . isSimplex - Are the cells simplices or tensor products 5857 - cellHeight - Normally 0 5858 5859 Note: This is a useful diagnostic when creating meshes programmatically. 5860 5861 Level: developer 5862 5863 .seealso: DMCreate(), DMCheckSymmetry(), DMCheckSkeleton() 5864 @*/ 5865 PetscErrorCode DMPlexCheckFaces(DM dm, PetscBool isSimplex, PetscInt cellHeight) 5866 { 5867 PetscInt pMax[4]; 5868 PetscInt dim, vStart, vEnd, cStart, cEnd, c, h; 5869 PetscErrorCode ierr; 5870 5871 PetscFunctionBegin; 5872 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5873 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 5874 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 5875 ierr = DMPlexGetHybridBounds(dm, &pMax[dim], &pMax[dim-1], &pMax[1], &pMax[0]);CHKERRQ(ierr); 5876 for (h = cellHeight; h < dim; ++h) { 5877 ierr = DMPlexGetHeightStratum(dm, h, &cStart, &cEnd);CHKERRQ(ierr); 5878 for (c = cStart; c < cEnd; ++c) { 5879 const PetscInt *cone, *ornt, *faces; 5880 PetscInt numFaces, faceSize, coneSize,f; 5881 PetscInt *closure = NULL, closureSize, cl, numCorners = 0; 5882 5883 if (pMax[dim-h] >= 0 && c >= pMax[dim-h]) continue; 5884 ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr); 5885 ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr); 5886 ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr); 5887 ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 5888 for (cl = 0; cl < closureSize*2; cl += 2) { 5889 const PetscInt p = closure[cl]; 5890 if ((p >= vStart) && (p < vEnd)) closure[numCorners++] = p; 5891 } 5892 ierr = DMPlexGetRawFaces_Internal(dm, dim-h, numCorners, closure, &numFaces, &faceSize, &faces);CHKERRQ(ierr); 5893 if (coneSize != numFaces) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cell %d has %d faces but should have %d", c, coneSize, numFaces); 5894 for (f = 0; f < numFaces; ++f) { 5895 PetscInt *fclosure = NULL, fclosureSize, cl, fnumCorners = 0, v; 5896 5897 ierr = DMPlexGetTransitiveClosure_Internal(dm, cone[f], ornt[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr); 5898 for (cl = 0; cl < fclosureSize*2; cl += 2) { 5899 const PetscInt p = fclosure[cl]; 5900 if ((p >= vStart) && (p < vEnd)) fclosure[fnumCorners++] = p; 5901 } 5902 if (fnumCorners != faceSize) SETERRQ5(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d (%d) of cell %d has %d vertices but should have %d", cone[f], f, c, fnumCorners, faceSize); 5903 for (v = 0; v < fnumCorners; ++v) { 5904 if (fclosure[v] != faces[f*faceSize+v]) SETERRQ6(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %d (%d) of cell %d vertex %d, %d != %d", cone[f], f, c, v, fclosure[v], faces[f*faceSize+v]); 5905 } 5906 ierr = DMPlexRestoreTransitiveClosure(dm, cone[f], PETSC_TRUE, &fclosureSize, &fclosure);CHKERRQ(ierr); 5907 } 5908 ierr = DMPlexRestoreFaces_Internal(dm, dim, c, &numFaces, &faceSize, &faces);CHKERRQ(ierr); 5909 ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 5910 } 5911 } 5912 PetscFunctionReturn(0); 5913 } 5914 5915 #undef __FUNCT__ 5916 #define __FUNCT__ "DMCreateInterpolation_Plex" 5917 /* Pointwise interpolation 5918 Just code FEM for now 5919 u^f = I u^c 5920 sum_k u^f_k phi^f_k = I sum_j u^c_j phi^c_j 5921 u^f_i = sum_j psi^f_i I phi^c_j u^c_j 5922 I_{ij} = psi^f_i phi^c_j 5923 */ 5924 PetscErrorCode DMCreateInterpolation_Plex(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 5925 { 5926 PetscSection gsc, gsf; 5927 PetscInt m, n; 5928 void *ctx; 5929 DM cdm; 5930 PetscBool regular; 5931 PetscErrorCode ierr; 5932 5933 PetscFunctionBegin; 5934 ierr = DMGetDefaultGlobalSection(dmFine, &gsf);CHKERRQ(ierr); 5935 ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr); 5936 ierr = DMGetDefaultGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr); 5937 ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr); 5938 5939 ierr = MatCreate(PetscObjectComm((PetscObject) dmCoarse), interpolation);CHKERRQ(ierr); 5940 ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 5941 ierr = MatSetType(*interpolation, dmCoarse->mattype);CHKERRQ(ierr); 5942 ierr = DMGetApplicationContext(dmFine, &ctx);CHKERRQ(ierr); 5943 5944 ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr); 5945 ierr = DMPlexGetRegularRefinement(dmFine, ®ular);CHKERRQ(ierr); 5946 if (regular && cdm == dmCoarse) {ierr = DMPlexComputeInterpolatorNested(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);} 5947 else {ierr = DMPlexComputeInterpolatorGeneral(dmCoarse, dmFine, *interpolation, ctx);CHKERRQ(ierr);} 5948 ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr); 5949 /* Use naive scaling */ 5950 ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr); 5951 PetscFunctionReturn(0); 5952 } 5953 5954 #undef __FUNCT__ 5955 #define __FUNCT__ "DMCreateInjection_Plex" 5956 PetscErrorCode DMCreateInjection_Plex(DM dmCoarse, DM dmFine, Mat *mat) 5957 { 5958 PetscErrorCode ierr; 5959 VecScatter ctx; 5960 5961 PetscFunctionBegin; 5962 ierr = DMPlexComputeInjectorFEM(dmCoarse, dmFine, &ctx, NULL);CHKERRQ(ierr); 5963 ierr = MatCreateScatter(PetscObjectComm((PetscObject)ctx), ctx, mat);CHKERRQ(ierr); 5964 ierr = VecScatterDestroy(&ctx);CHKERRQ(ierr); 5965 PetscFunctionReturn(0); 5966 } 5967 5968 #undef __FUNCT__ 5969 #define __FUNCT__ "DMCreateDefaultSection_Plex" 5970 PetscErrorCode DMCreateDefaultSection_Plex(DM dm) 5971 { 5972 PetscSection section; 5973 IS *bcPoints, *bcComps; 5974 PetscBool *isFE; 5975 PetscInt *bcFields, *numComp, *numDof; 5976 PetscInt depth, dim, numBd, numBC = 0, numFields, bd, bc = 0, f; 5977 PetscInt cStart, cEnd, cEndInterior; 5978 PetscErrorCode ierr; 5979 5980 PetscFunctionBegin; 5981 ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr); 5982 if (!numFields) PetscFunctionReturn(0); 5983 /* FE and FV boundary conditions are handled slightly differently */ 5984 ierr = PetscMalloc1(numFields, &isFE);CHKERRQ(ierr); 5985 for (f = 0; f < numFields; ++f) { 5986 PetscObject obj; 5987 PetscClassId id; 5988 5989 ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr); 5990 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 5991 if (id == PETSCFE_CLASSID) {isFE[f] = PETSC_TRUE;} 5992 else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;} 5993 else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f); 5994 } 5995 /* Allocate boundary point storage for FEM boundaries */ 5996 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 5997 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 5998 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 5999 ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr); 6000 ierr = PetscDSGetNumBoundary(dm->prob, &numBd);CHKERRQ(ierr); 6001 for (bd = 0; bd < numBd; ++bd) { 6002 PetscInt field; 6003 PetscBool isEssential; 6004 const char *labelName; 6005 DMLabel label; 6006 6007 ierr = PetscDSGetBoundary(dm->prob, bd, &isEssential, NULL, &labelName, &field, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr); 6008 ierr = DMGetLabel(dm,labelName,&label);CHKERRQ(ierr); 6009 if (label && isFE[field] && isEssential) ++numBC; 6010 } 6011 /* Add ghost cell boundaries for FVM */ 6012 for (f = 0; f < numFields; ++f) if (!isFE[f] && cEndInterior >= 0) ++numBC; 6013 ierr = PetscCalloc3(numBC,&bcFields,numBC,&bcPoints,numBC,&bcComps);CHKERRQ(ierr); 6014 /* Constrain ghost cells for FV */ 6015 for (f = 0; f < numFields; ++f) { 6016 PetscInt *newidx, c; 6017 6018 if (isFE[f] || cEndInterior < 0) continue; 6019 ierr = PetscMalloc1(cEnd-cEndInterior,&newidx);CHKERRQ(ierr); 6020 for (c = cEndInterior; c < cEnd; ++c) newidx[c-cEndInterior] = c; 6021 bcFields[bc] = f; 6022 ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), cEnd-cEndInterior, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr); 6023 } 6024 /* Handle FEM Dirichlet boundaries */ 6025 for (bd = 0; bd < numBd; ++bd) { 6026 const char *bdLabel; 6027 DMLabel label; 6028 const PetscInt *comps; 6029 const PetscInt *values; 6030 PetscInt bd2, field, numComps, numValues; 6031 PetscBool isEssential, duplicate = PETSC_FALSE; 6032 6033 ierr = PetscDSGetBoundary(dm->prob, bd, &isEssential, NULL, &bdLabel, &field, &numComps, &comps, NULL, &numValues, &values, NULL);CHKERRQ(ierr); 6034 ierr = DMGetLabel(dm, bdLabel, &label);CHKERRQ(ierr); 6035 if (!isFE[field] || !label) continue; 6036 /* Only want to modify label once */ 6037 for (bd2 = 0; bd2 < bd; ++bd2) { 6038 const char *bdname; 6039 ierr = PetscDSGetBoundary(dm->prob, bd2, NULL, NULL, &bdname, NULL, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr); 6040 ierr = PetscStrcmp(bdname, bdLabel, &duplicate);CHKERRQ(ierr); 6041 if (duplicate) break; 6042 } 6043 if (!duplicate && (isFE[field])) { 6044 /* don't complete cells, which are just present to give orientation to the boundary */ 6045 ierr = DMPlexLabelComplete(dm, label);CHKERRQ(ierr); 6046 } 6047 /* Filter out cells, if you actually want to constrain cells you need to do things by hand right now */ 6048 if (isEssential) { 6049 PetscInt *newidx; 6050 PetscInt n, newn = 0, p, v; 6051 6052 bcFields[bc] = field; 6053 if (numComps) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), numComps, comps, PETSC_COPY_VALUES, &bcComps[bc]);CHKERRQ(ierr);} 6054 for (v = 0; v < numValues; ++v) { 6055 IS tmp; 6056 const PetscInt *idx; 6057 6058 ierr = DMGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr); 6059 if (!tmp) continue; 6060 ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr); 6061 ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr); 6062 if (isFE[field]) { 6063 for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) ++newn; 6064 } else { 6065 for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) ++newn; 6066 } 6067 ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr); 6068 ierr = ISDestroy(&tmp);CHKERRQ(ierr); 6069 } 6070 ierr = PetscMalloc1(newn,&newidx);CHKERRQ(ierr); 6071 newn = 0; 6072 for (v = 0; v < numValues; ++v) { 6073 IS tmp; 6074 const PetscInt *idx; 6075 6076 ierr = DMGetStratumIS(dm, bdLabel, values[v], &tmp);CHKERRQ(ierr); 6077 if (!tmp) continue; 6078 ierr = ISGetLocalSize(tmp, &n);CHKERRQ(ierr); 6079 ierr = ISGetIndices(tmp, &idx);CHKERRQ(ierr); 6080 if (isFE[field]) { 6081 for (p = 0; p < n; ++p) if ((idx[p] < cStart) || (idx[p] >= cEnd)) newidx[newn++] = idx[p]; 6082 } else { 6083 for (p = 0; p < n; ++p) if ((idx[p] >= cStart) || (idx[p] < cEnd)) newidx[newn++] = idx[p]; 6084 } 6085 ierr = ISRestoreIndices(tmp, &idx);CHKERRQ(ierr); 6086 ierr = ISDestroy(&tmp);CHKERRQ(ierr); 6087 } 6088 ierr = ISCreateGeneral(PetscObjectComm((PetscObject) dm), newn, newidx, PETSC_OWN_POINTER, &bcPoints[bc++]);CHKERRQ(ierr); 6089 } 6090 } 6091 /* Handle discretization */ 6092 ierr = PetscCalloc2(numFields,&numComp,numFields*(dim+1),&numDof);CHKERRQ(ierr); 6093 for (f = 0; f < numFields; ++f) { 6094 PetscObject obj; 6095 6096 ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr); 6097 if (isFE[f]) { 6098 PetscFE fe = (PetscFE) obj; 6099 const PetscInt *numFieldDof; 6100 PetscInt d; 6101 6102 ierr = PetscFEGetNumComponents(fe, &numComp[f]);CHKERRQ(ierr); 6103 ierr = PetscFEGetNumDof(fe, &numFieldDof);CHKERRQ(ierr); 6104 for (d = 0; d < dim+1; ++d) numDof[f*(dim+1)+d] = numFieldDof[d]; 6105 } else { 6106 PetscFV fv = (PetscFV) obj; 6107 6108 ierr = PetscFVGetNumComponents(fv, &numComp[f]);CHKERRQ(ierr); 6109 numDof[f*(dim+1)+dim] = numComp[f]; 6110 } 6111 } 6112 for (f = 0; f < numFields; ++f) { 6113 PetscInt d; 6114 for (d = 1; d < dim; ++d) { 6115 if ((numDof[f*(dim+1)+d] > 0) && (depth < dim)) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated when unknowns are specified on edges or faces."); 6116 } 6117 } 6118 ierr = DMPlexCreateSection(dm, dim, numFields, numComp, numDof, numBC, bcFields, bcComps, bcPoints, NULL, §ion);CHKERRQ(ierr); 6119 for (f = 0; f < numFields; ++f) { 6120 PetscFE fe; 6121 const char *name; 6122 6123 ierr = DMGetField(dm, f, (PetscObject *) &fe);CHKERRQ(ierr); 6124 ierr = PetscObjectGetName((PetscObject) fe, &name);CHKERRQ(ierr); 6125 ierr = PetscSectionSetFieldName(section, f, name);CHKERRQ(ierr); 6126 } 6127 ierr = DMSetDefaultSection(dm, section);CHKERRQ(ierr); 6128 ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); 6129 for (bc = 0; bc < numBC; ++bc) {ierr = ISDestroy(&bcPoints[bc]);CHKERRQ(ierr);ierr = ISDestroy(&bcComps[bc]);CHKERRQ(ierr);} 6130 ierr = PetscFree3(bcFields,bcPoints,bcComps);CHKERRQ(ierr); 6131 ierr = PetscFree2(numComp,numDof);CHKERRQ(ierr); 6132 ierr = PetscFree(isFE);CHKERRQ(ierr); 6133 PetscFunctionReturn(0); 6134 } 6135 6136 #undef __FUNCT__ 6137 #define __FUNCT__ "DMPlexGetRegularRefinement" 6138 /*@ 6139 DMPlexGetRegularRefinement - Get the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 6140 6141 Input Parameter: 6142 . dm - The DMPlex object 6143 6144 Output Parameter: 6145 . regular - The flag 6146 6147 Level: intermediate 6148 6149 .seealso: DMPlexSetRegularRefinement() 6150 @*/ 6151 PetscErrorCode DMPlexGetRegularRefinement(DM dm, PetscBool *regular) 6152 { 6153 PetscFunctionBegin; 6154 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6155 PetscValidPointer(regular, 2); 6156 *regular = ((DM_Plex *) dm->data)->regularRefinement; 6157 PetscFunctionReturn(0); 6158 } 6159 6160 #undef __FUNCT__ 6161 #define __FUNCT__ "DMPlexSetRegularRefinement" 6162 /*@ 6163 DMPlexSetRegularRefinement - Set the flag indicating that this mesh was obtained by regular refinement from its coarse mesh 6164 6165 Input Parameters: 6166 + dm - The DMPlex object 6167 - regular - The flag 6168 6169 Level: intermediate 6170 6171 .seealso: DMPlexGetRegularRefinement() 6172 @*/ 6173 PetscErrorCode DMPlexSetRegularRefinement(DM dm, PetscBool regular) 6174 { 6175 PetscFunctionBegin; 6176 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6177 ((DM_Plex *) dm->data)->regularRefinement = regular; 6178 PetscFunctionReturn(0); 6179 } 6180 6181 /* anchors */ 6182 #undef __FUNCT__ 6183 #define __FUNCT__ "DMPlexGetAnchors" 6184 /*@ 6185 DMPlexGetAnchors - Get the layout of the anchor (point-to-point) constraints. Typically, the user will not have to 6186 call DMPlexGetAnchors() directly: if there are anchors, then DMPlexGetAnchors() is called during DMGetConstraints(). 6187 6188 not collective 6189 6190 Input Parameters: 6191 . dm - The DMPlex object 6192 6193 Output Parameters: 6194 + anchorSection - If not NULL, set to the section describing which points anchor the constrained points. 6195 - anchorIS - If not NULL, set to the list of anchors indexed by anchorSection 6196 6197 6198 Level: intermediate 6199 6200 .seealso: DMPlexSetAnchors(), DMGetConstraints(), DMSetConstraints() 6201 @*/ 6202 PetscErrorCode DMPlexGetAnchors(DM dm, PetscSection *anchorSection, IS *anchorIS) 6203 { 6204 DM_Plex *plex = (DM_Plex *)dm->data; 6205 PetscErrorCode ierr; 6206 6207 PetscFunctionBegin; 6208 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6209 if (!plex->anchorSection && !plex->anchorIS && plex->createanchors) {ierr = (*plex->createanchors)(dm);CHKERRQ(ierr);} 6210 if (anchorSection) *anchorSection = plex->anchorSection; 6211 if (anchorIS) *anchorIS = plex->anchorIS; 6212 PetscFunctionReturn(0); 6213 } 6214 6215 #undef __FUNCT__ 6216 #define __FUNCT__ "DMPlexSetAnchors" 6217 /*@ 6218 DMPlexSetAnchors - Set the layout of the local anchor (point-to-point) constraints. Unlike boundary conditions, 6219 when a point's degrees of freedom in a section are constrained to an outside value, the anchor constraints set a 6220 point's degrees of freedom to be a linear combination of other points' degrees of freedom. 6221 6222 After specifying the layout of constraints with DMPlexSetAnchors(), one specifies the constraints by calling 6223 DMGetConstraints() and filling in the entries in the constraint matrix. 6224 6225 collective on dm 6226 6227 Input Parameters: 6228 + dm - The DMPlex object 6229 . anchorSection - The section that describes the mapping from constrained points to the anchor points listed in anchorIS. Must have a local communicator (PETSC_COMM_SELF or derivative). 6230 - anchorIS - The list of all anchor points. Must have a local communicator (PETSC_COMM_SELF or derivative). 6231 6232 The reference counts of anchorSection and anchorIS are incremented. 6233 6234 Level: intermediate 6235 6236 .seealso: DMPlexGetAnchors(), DMGetConstraints(), DMSetConstraints() 6237 @*/ 6238 PetscErrorCode DMPlexSetAnchors(DM dm, PetscSection anchorSection, IS anchorIS) 6239 { 6240 DM_Plex *plex = (DM_Plex *)dm->data; 6241 PetscMPIInt result; 6242 PetscErrorCode ierr; 6243 6244 PetscFunctionBegin; 6245 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6246 if (anchorSection) { 6247 PetscValidHeaderSpecific(anchorSection,PETSC_SECTION_CLASSID,2); 6248 ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorSection),&result);CHKERRQ(ierr); 6249 if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor section must have local communicator"); 6250 } 6251 if (anchorIS) { 6252 PetscValidHeaderSpecific(anchorIS,IS_CLASSID,3); 6253 ierr = MPI_Comm_compare(PETSC_COMM_SELF,PetscObjectComm((PetscObject)anchorIS),&result);CHKERRQ(ierr); 6254 if (result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NOTSAMECOMM,"anchor IS must have local communicator"); 6255 } 6256 6257 ierr = PetscObjectReference((PetscObject)anchorSection);CHKERRQ(ierr); 6258 ierr = PetscSectionDestroy(&plex->anchorSection);CHKERRQ(ierr); 6259 plex->anchorSection = anchorSection; 6260 6261 ierr = PetscObjectReference((PetscObject)anchorIS);CHKERRQ(ierr); 6262 ierr = ISDestroy(&plex->anchorIS);CHKERRQ(ierr); 6263 plex->anchorIS = anchorIS; 6264 6265 #if defined(PETSC_USE_DEBUG) 6266 if (anchorIS && anchorSection) { 6267 PetscInt size, a, pStart, pEnd; 6268 const PetscInt *anchors; 6269 6270 ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr); 6271 ierr = ISGetLocalSize(anchorIS,&size);CHKERRQ(ierr); 6272 ierr = ISGetIndices(anchorIS,&anchors);CHKERRQ(ierr); 6273 for (a = 0; a < size; a++) { 6274 PetscInt p; 6275 6276 p = anchors[a]; 6277 if (p >= pStart && p < pEnd) { 6278 PetscInt dof; 6279 6280 ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr); 6281 if (dof) { 6282 PetscErrorCode ierr2; 6283 6284 ierr2 = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr2); 6285 SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Point %d cannot be constrained and an anchor",p); 6286 } 6287 } 6288 } 6289 ierr = ISRestoreIndices(anchorIS,&anchors);CHKERRQ(ierr); 6290 } 6291 #endif 6292 /* reset the generic constraints */ 6293 ierr = DMSetDefaultConstraints(dm,NULL,NULL);CHKERRQ(ierr); 6294 PetscFunctionReturn(0); 6295 } 6296 6297 #undef __FUNCT__ 6298 #define __FUNCT__ "DMPlexCreateConstraintSection_Anchors" 6299 static PetscErrorCode DMPlexCreateConstraintSection_Anchors(DM dm, PetscSection section, PetscSection *cSec) 6300 { 6301 PetscSection anchorSection; 6302 PetscInt pStart, pEnd, sStart, sEnd, p, dof, numFields, f; 6303 PetscErrorCode ierr; 6304 6305 PetscFunctionBegin; 6306 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6307 ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr); 6308 ierr = PetscSectionCreate(PETSC_COMM_SELF,cSec);CHKERRQ(ierr); 6309 ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr); 6310 if (numFields) { 6311 PetscInt f; 6312 ierr = PetscSectionSetNumFields(*cSec,numFields);CHKERRQ(ierr); 6313 6314 for (f = 0; f < numFields; f++) { 6315 PetscInt numComp; 6316 6317 ierr = PetscSectionGetFieldComponents(section,f,&numComp);CHKERRQ(ierr); 6318 ierr = PetscSectionSetFieldComponents(*cSec,f,numComp);CHKERRQ(ierr); 6319 } 6320 } 6321 ierr = PetscSectionGetChart(anchorSection,&pStart,&pEnd);CHKERRQ(ierr); 6322 ierr = PetscSectionGetChart(section,&sStart,&sEnd);CHKERRQ(ierr); 6323 pStart = PetscMax(pStart,sStart); 6324 pEnd = PetscMin(pEnd,sEnd); 6325 pEnd = PetscMax(pStart,pEnd); 6326 ierr = PetscSectionSetChart(*cSec,pStart,pEnd);CHKERRQ(ierr); 6327 for (p = pStart; p < pEnd; p++) { 6328 ierr = PetscSectionGetDof(anchorSection,p,&dof);CHKERRQ(ierr); 6329 if (dof) { 6330 ierr = PetscSectionGetDof(section,p,&dof);CHKERRQ(ierr); 6331 ierr = PetscSectionSetDof(*cSec,p,dof);CHKERRQ(ierr); 6332 for (f = 0; f < numFields; f++) { 6333 ierr = PetscSectionGetFieldDof(section,p,f,&dof);CHKERRQ(ierr); 6334 ierr = PetscSectionSetFieldDof(*cSec,p,f,dof);CHKERRQ(ierr); 6335 } 6336 } 6337 } 6338 ierr = PetscSectionSetUp(*cSec);CHKERRQ(ierr); 6339 PetscFunctionReturn(0); 6340 } 6341 6342 #undef __FUNCT__ 6343 #define __FUNCT__ "DMPlexCreateConstraintMatrix_Anchors" 6344 static PetscErrorCode DMPlexCreateConstraintMatrix_Anchors(DM dm, PetscSection section, PetscSection cSec, Mat *cMat) 6345 { 6346 PetscSection aSec; 6347 PetscInt pStart, pEnd, p, dof, aDof, aOff, off, nnz, annz, m, n, q, a, offset, *i, *j; 6348 const PetscInt *anchors; 6349 PetscInt numFields, f; 6350 IS aIS; 6351 PetscErrorCode ierr; 6352 6353 PetscFunctionBegin; 6354 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6355 ierr = PetscSectionGetStorageSize(cSec, &m);CHKERRQ(ierr); 6356 ierr = PetscSectionGetStorageSize(section, &n);CHKERRQ(ierr); 6357 ierr = MatCreate(PETSC_COMM_SELF,cMat);CHKERRQ(ierr); 6358 ierr = MatSetSizes(*cMat,m,n,m,n);CHKERRQ(ierr); 6359 ierr = MatSetType(*cMat,MATSEQAIJ);CHKERRQ(ierr); 6360 ierr = DMPlexGetAnchors(dm,&aSec,&aIS);CHKERRQ(ierr); 6361 ierr = ISGetIndices(aIS,&anchors);CHKERRQ(ierr); 6362 /* cSec will be a subset of aSec and section */ 6363 ierr = PetscSectionGetChart(cSec,&pStart,&pEnd);CHKERRQ(ierr); 6364 ierr = PetscMalloc1(m+1,&i);CHKERRQ(ierr); 6365 i[0] = 0; 6366 ierr = PetscSectionGetNumFields(section,&numFields);CHKERRQ(ierr); 6367 for (p = pStart; p < pEnd; p++) { 6368 PetscInt rDof, rOff, r; 6369 6370 ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr); 6371 if (!rDof) continue; 6372 ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr); 6373 if (numFields) { 6374 for (f = 0; f < numFields; f++) { 6375 annz = 0; 6376 for (r = 0; r < rDof; r++) { 6377 a = anchors[rOff + r]; 6378 ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr); 6379 annz += aDof; 6380 } 6381 ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr); 6382 ierr = PetscSectionGetFieldOffset(cSec,p,f,&off);CHKERRQ(ierr); 6383 for (q = 0; q < dof; q++) { 6384 i[off + q + 1] = i[off + q] + annz; 6385 } 6386 } 6387 } 6388 else { 6389 annz = 0; 6390 for (q = 0; q < dof; q++) { 6391 a = anchors[off + q]; 6392 ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr); 6393 annz += aDof; 6394 } 6395 ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr); 6396 ierr = PetscSectionGetOffset(cSec,p,&off);CHKERRQ(ierr); 6397 for (q = 0; q < dof; q++) { 6398 i[off + q + 1] = i[off + q] + annz; 6399 } 6400 } 6401 } 6402 nnz = i[m]; 6403 ierr = PetscMalloc1(nnz,&j);CHKERRQ(ierr); 6404 offset = 0; 6405 for (p = pStart; p < pEnd; p++) { 6406 if (numFields) { 6407 for (f = 0; f < numFields; f++) { 6408 ierr = PetscSectionGetFieldDof(cSec,p,f,&dof);CHKERRQ(ierr); 6409 for (q = 0; q < dof; q++) { 6410 PetscInt rDof, rOff, r; 6411 ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr); 6412 ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr); 6413 for (r = 0; r < rDof; r++) { 6414 PetscInt s; 6415 6416 a = anchors[rOff + r]; 6417 ierr = PetscSectionGetFieldDof(section,a,f,&aDof);CHKERRQ(ierr); 6418 ierr = PetscSectionGetFieldOffset(section,a,f,&aOff);CHKERRQ(ierr); 6419 for (s = 0; s < aDof; s++) { 6420 j[offset++] = aOff + s; 6421 } 6422 } 6423 } 6424 } 6425 } 6426 else { 6427 ierr = PetscSectionGetDof(cSec,p,&dof);CHKERRQ(ierr); 6428 for (q = 0; q < dof; q++) { 6429 PetscInt rDof, rOff, r; 6430 ierr = PetscSectionGetDof(aSec,p,&rDof);CHKERRQ(ierr); 6431 ierr = PetscSectionGetOffset(aSec,p,&rOff);CHKERRQ(ierr); 6432 for (r = 0; r < rDof; r++) { 6433 PetscInt s; 6434 6435 a = anchors[rOff + r]; 6436 ierr = PetscSectionGetDof(section,a,&aDof);CHKERRQ(ierr); 6437 ierr = PetscSectionGetOffset(section,a,&aOff);CHKERRQ(ierr); 6438 for (s = 0; s < aDof; s++) { 6439 j[offset++] = aOff + s; 6440 } 6441 } 6442 } 6443 } 6444 } 6445 ierr = MatSeqAIJSetPreallocationCSR(*cMat,i,j,NULL);CHKERRQ(ierr); 6446 ierr = PetscFree(i);CHKERRQ(ierr); 6447 ierr = PetscFree(j);CHKERRQ(ierr); 6448 ierr = ISRestoreIndices(aIS,&anchors);CHKERRQ(ierr); 6449 PetscFunctionReturn(0); 6450 } 6451 6452 #undef __FUNCT__ 6453 #define __FUNCT__ "DMCreateDefaultConstraints_Plex" 6454 PetscErrorCode DMCreateDefaultConstraints_Plex(DM dm) 6455 { 6456 DM_Plex *plex = (DM_Plex *)dm->data; 6457 PetscSection anchorSection, section, cSec; 6458 Mat cMat; 6459 PetscErrorCode ierr; 6460 6461 PetscFunctionBegin; 6462 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6463 ierr = DMPlexGetAnchors(dm,&anchorSection,NULL);CHKERRQ(ierr); 6464 if (anchorSection) { 6465 PetscDS ds; 6466 PetscInt nf; 6467 6468 ierr = DMGetDefaultSection(dm,§ion);CHKERRQ(ierr); 6469 ierr = DMPlexCreateConstraintSection_Anchors(dm,section,&cSec);CHKERRQ(ierr); 6470 ierr = DMPlexCreateConstraintMatrix_Anchors(dm,section,cSec,&cMat);CHKERRQ(ierr); 6471 ierr = DMGetDS(dm,&ds);CHKERRQ(ierr); 6472 ierr = PetscDSGetNumFields(ds,&nf);CHKERRQ(ierr); 6473 if (nf && plex->computeanchormatrix) {ierr = (*plex->computeanchormatrix)(dm,section,cSec,cMat);CHKERRQ(ierr);} 6474 ierr = DMSetDefaultConstraints(dm,cSec,cMat);CHKERRQ(ierr); 6475 ierr = PetscSectionDestroy(&cSec);CHKERRQ(ierr); 6476 ierr = MatDestroy(&cMat);CHKERRQ(ierr); 6477 } 6478 PetscFunctionReturn(0); 6479 } 6480