1 #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/ 2 #include <petscdmplex.h> 3 4 static PetscErrorCode PetscDualSpaceDestroy_Lagrange(PetscDualSpace sp) 5 { 6 PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; 7 PetscInt i; 8 PetscErrorCode ierr; 9 10 PetscFunctionBegin; 11 if (lag->symmetries) { 12 PetscInt **selfSyms = lag->symmetries[0]; 13 14 if (selfSyms) { 15 PetscInt i, **allocated = &selfSyms[-lag->selfSymOff]; 16 17 for (i = 0; i < lag->numSelfSym; i++) { 18 ierr = PetscFree(allocated[i]);CHKERRQ(ierr); 19 } 20 ierr = PetscFree(allocated);CHKERRQ(ierr); 21 } 22 ierr = PetscFree(lag->symmetries);CHKERRQ(ierr); 23 } 24 for (i = 0; i < lag->height; i++) { 25 ierr = PetscDualSpaceDestroy(&lag->subspaces[i]);CHKERRQ(ierr); 26 } 27 ierr = PetscFree(lag->subspaces);CHKERRQ(ierr); 28 ierr = PetscFree(lag->numDof);CHKERRQ(ierr); 29 ierr = PetscFree(lag);CHKERRQ(ierr); 30 ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetContinuity_C", NULL);CHKERRQ(ierr); 31 ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetContinuity_C", NULL);CHKERRQ(ierr); 32 ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetTensor_C", NULL);CHKERRQ(ierr); 33 ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetTensor_C", NULL);CHKERRQ(ierr); 34 PetscFunctionReturn(0); 35 } 36 37 static PetscErrorCode PetscDualSpaceLagrangeView_Ascii(PetscDualSpace sp, PetscViewer viewer) 38 { 39 PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; 40 PetscErrorCode ierr; 41 42 PetscFunctionBegin; 43 ierr = PetscViewerASCIIPrintf(viewer, "%s %sLagrange dual space\n", lag->continuous ? "Continuous" : "Discontinuous", lag->tensorSpace ? "tensor " : "");CHKERRQ(ierr); 44 PetscFunctionReturn(0); 45 } 46 47 static PetscErrorCode PetscDualSpaceView_Lagrange(PetscDualSpace sp, PetscViewer viewer) 48 { 49 PetscBool iascii; 50 PetscErrorCode ierr; 51 52 PetscFunctionBegin; 53 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 54 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 55 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 56 if (iascii) {ierr = PetscDualSpaceLagrangeView_Ascii(sp, viewer);CHKERRQ(ierr);} 57 PetscFunctionReturn(0); 58 } 59 60 static PetscErrorCode PetscDualSpaceSetFromOptions_Lagrange(PetscOptionItems *PetscOptionsObject,PetscDualSpace sp) 61 { 62 PetscBool continuous, tensor, flg; 63 PetscErrorCode ierr; 64 65 PetscFunctionBegin; 66 ierr = PetscDualSpaceLagrangeGetContinuity(sp, &continuous);CHKERRQ(ierr); 67 ierr = PetscDualSpaceLagrangeGetTensor(sp, &tensor);CHKERRQ(ierr); 68 ierr = PetscOptionsHead(PetscOptionsObject,"PetscDualSpace Lagrange Options");CHKERRQ(ierr); 69 ierr = PetscOptionsBool("-petscdualspace_lagrange_continuity", "Flag for continuous element", "PetscDualSpaceLagrangeSetContinuity", continuous, &continuous, &flg);CHKERRQ(ierr); 70 if (flg) {ierr = PetscDualSpaceLagrangeSetContinuity(sp, continuous);CHKERRQ(ierr);} 71 ierr = PetscOptionsBool("-petscdualspace_lagrange_tensor", "Flag for tensor dual space", "PetscDualSpaceLagrangeSetContinuity", tensor, &tensor, &flg);CHKERRQ(ierr); 72 if (flg) {ierr = PetscDualSpaceLagrangeSetTensor(sp, tensor);CHKERRQ(ierr);} 73 ierr = PetscOptionsTail();CHKERRQ(ierr); 74 PetscFunctionReturn(0); 75 } 76 77 static PetscErrorCode PetscDualSpaceDuplicate_Lagrange(PetscDualSpace sp, PetscDualSpace *spNew) 78 { 79 PetscInt order, Nc; 80 PetscBool cont, tensor; 81 const char *name; 82 PetscErrorCode ierr; 83 84 PetscFunctionBegin; 85 ierr = PetscDualSpaceCreate(PetscObjectComm((PetscObject) sp), spNew);CHKERRQ(ierr); 86 ierr = PetscObjectGetName((PetscObject) sp, &name);CHKERRQ(ierr); 87 ierr = PetscObjectSetName((PetscObject) *spNew, name);CHKERRQ(ierr); 88 ierr = PetscDualSpaceSetType(*spNew, PETSCDUALSPACELAGRANGE);CHKERRQ(ierr); 89 ierr = PetscDualSpaceGetOrder(sp, &order);CHKERRQ(ierr); 90 ierr = PetscDualSpaceSetOrder(*spNew, order);CHKERRQ(ierr); 91 ierr = PetscDualSpaceGetNumComponents(sp, &Nc);CHKERRQ(ierr); 92 ierr = PetscDualSpaceSetNumComponents(*spNew, Nc);CHKERRQ(ierr); 93 ierr = PetscDualSpaceLagrangeGetContinuity(sp, &cont);CHKERRQ(ierr); 94 ierr = PetscDualSpaceLagrangeSetContinuity(*spNew, cont);CHKERRQ(ierr); 95 ierr = PetscDualSpaceLagrangeGetTensor(sp, &tensor);CHKERRQ(ierr); 96 ierr = PetscDualSpaceLagrangeSetTensor(*spNew, tensor);CHKERRQ(ierr); 97 PetscFunctionReturn(0); 98 } 99 100 static PetscErrorCode PetscDualSpaceGetDimension_SingleCell_Lagrange(PetscDualSpace sp, PetscInt order, PetscInt *dim) 101 { 102 PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; 103 PetscReal D = 1.0; 104 PetscInt n, d; 105 PetscErrorCode ierr; 106 107 PetscFunctionBegin; 108 *dim = -1; 109 ierr = DMGetDimension(sp->dm, &n);CHKERRQ(ierr); 110 if (!lag->tensorSpace) { 111 for (d = 1; d <= n; ++d) { 112 D *= ((PetscReal) (order+d))/d; 113 } 114 *dim = (PetscInt) (D + 0.5); 115 } else { 116 *dim = 1; 117 for (d = 0; d < n; ++d) *dim *= (order+1); 118 } 119 *dim *= sp->Nc; 120 PetscFunctionReturn(0); 121 } 122 123 static PetscErrorCode PetscDualSpaceCreateHeightSubspace_Lagrange(PetscDualSpace sp, PetscInt height, PetscDualSpace *bdsp) 124 { 125 PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; 126 PetscBool continuous, tensor; 127 PetscInt order; 128 PetscErrorCode ierr; 129 130 PetscFunctionBegin; 131 ierr = PetscDualSpaceLagrangeGetContinuity(sp,&continuous);CHKERRQ(ierr); 132 ierr = PetscDualSpaceGetOrder(sp,&order);CHKERRQ(ierr); 133 if (height == 0) { 134 ierr = PetscObjectReference((PetscObject)sp);CHKERRQ(ierr); 135 *bdsp = sp; 136 } else if (continuous == PETSC_FALSE || !order) { 137 *bdsp = NULL; 138 } else { 139 DM dm, K; 140 PetscInt dim; 141 142 ierr = PetscDualSpaceGetDM(sp,&dm);CHKERRQ(ierr); 143 ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr); 144 if (height > dim || height < 0) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Asked for dual space at height %d for dimension %d reference element\n",height,dim); 145 ierr = PetscDualSpaceDuplicate(sp,bdsp);CHKERRQ(ierr); 146 ierr = PetscDualSpaceCreateReferenceCell(*bdsp, dim-height, lag->simplexCell, &K);CHKERRQ(ierr); 147 ierr = PetscDualSpaceSetDM(*bdsp, K);CHKERRQ(ierr); 148 ierr = DMDestroy(&K);CHKERRQ(ierr); 149 ierr = PetscDualSpaceLagrangeGetTensor(sp,&tensor);CHKERRQ(ierr); 150 ierr = PetscDualSpaceLagrangeSetTensor(*bdsp,tensor);CHKERRQ(ierr); 151 ierr = PetscDualSpaceSetUp(*bdsp);CHKERRQ(ierr); 152 } 153 PetscFunctionReturn(0); 154 } 155 156 static PetscErrorCode PetscDualSpaceSetUp_Lagrange(PetscDualSpace sp) 157 { 158 PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; 159 DM dm = sp->dm; 160 PetscInt order = sp->order; 161 PetscInt Nc = sp->Nc; 162 MPI_Comm comm; 163 PetscBool continuous; 164 PetscSection csection; 165 Vec coordinates; 166 PetscReal *qpoints, *qweights; 167 PetscInt depth, dim, pdimMax, pStart, pEnd, p, *pStratStart, *pStratEnd, coneSize, d, f = 0, c; 168 PetscBool simplex, tensorSpace; 169 PetscErrorCode ierr; 170 171 PetscFunctionBegin; 172 ierr = PetscObjectGetComm((PetscObject) sp, &comm);CHKERRQ(ierr); 173 if (!order) lag->continuous = PETSC_FALSE; 174 continuous = lag->continuous; 175 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 176 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 177 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 178 ierr = PetscCalloc1(dim+1, &lag->numDof);CHKERRQ(ierr); 179 ierr = PetscMalloc2(depth+1,&pStratStart,depth+1,&pStratEnd);CHKERRQ(ierr); 180 for (d = 0; d <= depth; ++d) {ierr = DMPlexGetDepthStratum(dm, d, &pStratStart[d], &pStratEnd[d]);CHKERRQ(ierr);} 181 ierr = DMPlexGetConeSize(dm, pStratStart[depth], &coneSize);CHKERRQ(ierr); 182 ierr = DMGetCoordinateSection(dm, &csection);CHKERRQ(ierr); 183 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 184 if (depth == 1) { 185 if (coneSize == dim+1) simplex = PETSC_TRUE; 186 else if (coneSize == 1 << dim) simplex = PETSC_FALSE; 187 else SETERRQ(comm, PETSC_ERR_SUP, "Only support simplices and tensor product cells"); 188 } else if (depth == dim) { 189 if (coneSize == dim+1) simplex = PETSC_TRUE; 190 else if (coneSize == 2 * dim) simplex = PETSC_FALSE; 191 else SETERRQ(comm, PETSC_ERR_SUP, "Only support simplices and tensor product cells"); 192 } else SETERRQ(comm, PETSC_ERR_SUP, "Only support cell-vertex meshes or fully interpolated meshes"); 193 lag->simplexCell = simplex; 194 if (dim > 1 && continuous && lag->simplexCell == lag->tensorSpace) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP, "Mismatching simplex/tensor cells and spaces only allowed for discontinuous elements"); 195 tensorSpace = lag->tensorSpace; 196 lag->height = 0; 197 lag->subspaces = NULL; 198 if (continuous && order > 0 && dim > 0) { 199 PetscInt i; 200 201 lag->height = dim; 202 ierr = PetscMalloc1(dim,&lag->subspaces);CHKERRQ(ierr); 203 ierr = PetscDualSpaceCreateHeightSubspace_Lagrange(sp,1,&lag->subspaces[0]);CHKERRQ(ierr); 204 ierr = PetscDualSpaceSetUp(lag->subspaces[0]);CHKERRQ(ierr); 205 for (i = 1; i < dim; i++) { 206 ierr = PetscDualSpaceGetHeightSubspace(lag->subspaces[i-1],1,&lag->subspaces[i]);CHKERRQ(ierr); 207 ierr = PetscObjectReference((PetscObject)(lag->subspaces[i]));CHKERRQ(ierr); 208 } 209 } 210 ierr = PetscDualSpaceGetDimension_SingleCell_Lagrange(sp, sp->order, &pdimMax);CHKERRQ(ierr); 211 pdimMax *= (pStratEnd[depth] - pStratStart[depth]); 212 ierr = PetscMalloc1(pdimMax, &sp->functional);CHKERRQ(ierr); 213 if (!dim) { 214 for (c = 0; c < Nc; ++c) { 215 ierr = PetscQuadratureCreate(PETSC_COMM_SELF, &sp->functional[f]);CHKERRQ(ierr); 216 ierr = PetscCalloc1(Nc, &qweights);CHKERRQ(ierr); 217 ierr = PetscQuadratureSetOrder(sp->functional[f], 0);CHKERRQ(ierr); 218 ierr = PetscQuadratureSetData(sp->functional[f], 0, Nc, 1, NULL, qweights);CHKERRQ(ierr); 219 qweights[c] = 1.0; 220 ++f; 221 lag->numDof[0]++; 222 } 223 } else { 224 PetscSection section; 225 PetscReal *v0, *hv0, *J, *invJ, detJ, hdetJ; 226 PetscInt *tup; 227 228 ierr = PetscSectionCreate(PETSC_COMM_SELF,§ion);CHKERRQ(ierr); 229 ierr = PetscSectionSetChart(section,pStart,pEnd);CHKERRQ(ierr); 230 ierr = PetscCalloc5(dim+1,&tup,dim,&v0,dim,&hv0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr); 231 for (p = pStart; p < pEnd; p++) { 232 PetscInt pointDim, d, nFunc = 0; 233 PetscDualSpace hsp; 234 235 ierr = DMPlexComputeCellGeometryFEM(dm, p, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 236 for (d = 0; d < depth; d++) {if (p >= pStratStart[d] && p < pStratEnd[d]) break;} 237 pointDim = (depth == 1 && d == 1) ? dim : d; 238 hsp = ((pointDim < dim) && lag->subspaces) ? lag->subspaces[dim - pointDim - 1] : NULL; 239 if (hsp) { 240 PetscDualSpace_Lag *hlag = (PetscDualSpace_Lag *) hsp->data; 241 DM hdm; 242 243 ierr = PetscDualSpaceGetDM(hsp,&hdm);CHKERRQ(ierr); 244 ierr = DMPlexComputeCellGeometryFEM(hdm, 0, NULL, hv0, NULL, NULL, &hdetJ);CHKERRQ(ierr); 245 nFunc = lag->numDof[pointDim] = hlag->numDof[pointDim]; 246 } 247 if (pointDim == dim) { 248 /* Cells, create for self */ 249 PetscInt orderEff = continuous ? (!tensorSpace ? order-1-dim : order-2) : order; 250 PetscReal denom = continuous ? order : (!tensorSpace ? order+1+dim : order+2); 251 PetscReal numer = (!simplex || !tensorSpace) ? 2. : (2./dim); 252 PetscReal dx = numer/denom; 253 PetscInt cdim, d, d2; 254 255 if (orderEff < 0) continue; 256 ierr = PetscDualSpaceGetDimension_SingleCell_Lagrange(sp, orderEff, &cdim);CHKERRQ(ierr); 257 ierr = PetscArrayzero(tup,dim+1);CHKERRQ(ierr); 258 if (!tensorSpace) { 259 while (!tup[dim]) { 260 for (c = 0; c < Nc; ++c) { 261 ierr = PetscQuadratureCreate(PETSC_COMM_SELF, &sp->functional[f]);CHKERRQ(ierr); 262 ierr = PetscMalloc1(dim, &qpoints);CHKERRQ(ierr); 263 ierr = PetscCalloc1(Nc, &qweights);CHKERRQ(ierr); 264 ierr = PetscQuadratureSetOrder(sp->functional[f], 0);CHKERRQ(ierr); 265 ierr = PetscQuadratureSetData(sp->functional[f], dim, Nc, 1, qpoints, qweights);CHKERRQ(ierr); 266 for (d = 0; d < dim; ++d) { 267 qpoints[d] = v0[d]; 268 for (d2 = 0; d2 < dim; ++d2) qpoints[d] += J[d*dim+d2]*((tup[d2]+1)*dx); 269 } 270 qweights[c] = 1.0; 271 ++f; 272 } 273 ierr = PetscDualSpaceLatticePointLexicographic_Internal(dim, orderEff, tup);CHKERRQ(ierr); 274 } 275 } else { 276 while (!tup[dim]) { 277 for (c = 0; c < Nc; ++c) { 278 ierr = PetscQuadratureCreate(PETSC_COMM_SELF, &sp->functional[f]);CHKERRQ(ierr); 279 ierr = PetscMalloc1(dim, &qpoints);CHKERRQ(ierr); 280 ierr = PetscCalloc1(Nc, &qweights);CHKERRQ(ierr); 281 ierr = PetscQuadratureSetOrder(sp->functional[f], 0);CHKERRQ(ierr); 282 ierr = PetscQuadratureSetData(sp->functional[f], dim, Nc, 1, qpoints, qweights);CHKERRQ(ierr); 283 for (d = 0; d < dim; ++d) { 284 qpoints[d] = v0[d]; 285 for (d2 = 0; d2 < dim; ++d2) qpoints[d] += J[d*dim+d2]*((tup[d2]+1)*dx); 286 } 287 qweights[c] = 1.0; 288 ++f; 289 } 290 ierr = PetscDualSpaceTensorPointLexicographic_Internal(dim, orderEff, tup);CHKERRQ(ierr); 291 } 292 } 293 lag->numDof[dim] = cdim; 294 } else { /* transform functionals from subspaces */ 295 PetscInt q; 296 297 for (q = 0; q < nFunc; q++, f++) { 298 PetscQuadrature fn; 299 PetscInt fdim, Nc, c, nPoints, i; 300 const PetscReal *points; 301 const PetscReal *weights; 302 PetscReal *qpoints; 303 PetscReal *qweights; 304 305 ierr = PetscDualSpaceGetFunctional(hsp, q, &fn);CHKERRQ(ierr); 306 ierr = PetscQuadratureGetData(fn,&fdim,&Nc,&nPoints,&points,&weights);CHKERRQ(ierr); 307 if (fdim != pointDim) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected height dual space dim %D, got %D",pointDim,fdim); 308 ierr = PetscMalloc1(nPoints * dim, &qpoints);CHKERRQ(ierr); 309 ierr = PetscCalloc1(nPoints * Nc, &qweights);CHKERRQ(ierr); 310 for (i = 0; i < nPoints; i++) { 311 PetscInt j, k; 312 PetscReal *qp = &qpoints[i * dim]; 313 314 for (c = 0; c < Nc; ++c) qweights[i*Nc+c] = weights[i*Nc+c]; 315 for (j = 0; j < dim; ++j) qp[j] = v0[j]; 316 for (j = 0; j < dim; ++j) { 317 for (k = 0; k < pointDim; k++) qp[j] += J[dim * j + k] * (points[pointDim * i + k] - hv0[k]); 318 } 319 } 320 ierr = PetscQuadratureCreate(PETSC_COMM_SELF, &sp->functional[f]);CHKERRQ(ierr); 321 ierr = PetscQuadratureSetOrder(sp->functional[f],0);CHKERRQ(ierr); 322 ierr = PetscQuadratureSetData(sp->functional[f],dim,Nc,nPoints,qpoints,qweights);CHKERRQ(ierr); 323 } 324 } 325 ierr = PetscSectionSetDof(section,p,lag->numDof[pointDim]);CHKERRQ(ierr); 326 } 327 ierr = PetscFree5(tup,v0,hv0,J,invJ);CHKERRQ(ierr); 328 ierr = PetscSectionSetUp(section);CHKERRQ(ierr); 329 { /* reorder to closure order */ 330 PetscInt *key, count; 331 PetscQuadrature *reorder = NULL; 332 333 ierr = PetscCalloc1(f,&key);CHKERRQ(ierr); 334 ierr = PetscMalloc1(f*sp->Nc,&reorder);CHKERRQ(ierr); 335 336 for (p = pStratStart[depth], count = 0; p < pStratEnd[depth]; p++) { 337 PetscInt *closure = NULL, closureSize, c; 338 339 ierr = DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); 340 for (c = 0; c < closureSize; c++) { 341 PetscInt point = closure[2 * c], dof, off, i; 342 343 ierr = PetscSectionGetDof(section,point,&dof);CHKERRQ(ierr); 344 ierr = PetscSectionGetOffset(section,point,&off);CHKERRQ(ierr); 345 for (i = 0; i < dof; i++) { 346 PetscInt fi = i + off; 347 if (!key[fi]) { 348 key[fi] = 1; 349 reorder[count++] = sp->functional[fi]; 350 } 351 } 352 } 353 ierr = DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); 354 } 355 ierr = PetscFree(sp->functional);CHKERRQ(ierr); 356 sp->functional = reorder; 357 ierr = PetscFree(key);CHKERRQ(ierr); 358 } 359 ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); 360 } 361 if (pStratEnd[depth] == 1 && f != pdimMax) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of dual basis vectors %D not equal to dimension %D", f, pdimMax); 362 if (f > pdimMax) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of dual basis vectors %D is greater than max size %D", f, pdimMax); 363 ierr = PetscFree2(pStratStart, pStratEnd);CHKERRQ(ierr); 364 PetscFunctionReturn(0); 365 } 366 367 static PetscErrorCode PetscDualSpaceGetDimension_Lagrange(PetscDualSpace sp, PetscInt *dim) 368 { 369 DM K; 370 const PetscInt *numDof; 371 PetscInt spatialDim, Nc, size = 0, d; 372 PetscErrorCode ierr; 373 374 PetscFunctionBegin; 375 ierr = PetscDualSpaceGetDM(sp, &K);CHKERRQ(ierr); 376 ierr = PetscDualSpaceGetNumDof(sp, &numDof);CHKERRQ(ierr); 377 ierr = DMGetDimension(K, &spatialDim);CHKERRQ(ierr); 378 ierr = DMPlexGetHeightStratum(K, 0, NULL, &Nc);CHKERRQ(ierr); 379 if (Nc == 1) {ierr = PetscDualSpaceGetDimension_SingleCell_Lagrange(sp, sp->order, dim);CHKERRQ(ierr); PetscFunctionReturn(0);} 380 for (d = 0; d <= spatialDim; ++d) { 381 PetscInt pStart, pEnd; 382 383 ierr = DMPlexGetDepthStratum(K, d, &pStart, &pEnd);CHKERRQ(ierr); 384 size += (pEnd-pStart)*numDof[d]; 385 } 386 *dim = size; 387 PetscFunctionReturn(0); 388 } 389 390 static PetscErrorCode PetscDualSpaceGetNumDof_Lagrange(PetscDualSpace sp, const PetscInt **numDof) 391 { 392 PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; 393 394 PetscFunctionBegin; 395 *numDof = lag->numDof; 396 PetscFunctionReturn(0); 397 } 398 399 static PetscErrorCode PetscDualSpaceGetHeightSubspace_Lagrange(PetscDualSpace sp, PetscInt height, PetscDualSpace *bdsp) 400 { 401 PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; 402 PetscErrorCode ierr; 403 404 PetscFunctionBegin; 405 if (height == 0) { 406 *bdsp = sp; 407 } else { 408 DM dm; 409 PetscInt dim; 410 411 ierr = PetscDualSpaceGetDM(sp,&dm);CHKERRQ(ierr); 412 ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr); 413 if (height > dim || height < 0) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Asked for dual space at height %D for dimension %D reference element\n",height,dim); 414 if (height <= lag->height) {*bdsp = lag->subspaces[height-1];} 415 else {*bdsp = NULL;} 416 } 417 PetscFunctionReturn(0); 418 } 419 420 #define BaryIndex(perEdge,a,b,c) (((b)*(2*perEdge+1-(b)))/2)+(c) 421 422 #define CartIndex(perEdge,a,b) (perEdge*(a)+b) 423 424 static PetscErrorCode PetscDualSpaceGetSymmetries_Lagrange(PetscDualSpace sp, const PetscInt ****perms, const PetscScalar ****flips) 425 { 426 427 PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; 428 PetscInt dim, order, p, Nc; 429 PetscErrorCode ierr; 430 431 PetscFunctionBegin; 432 ierr = PetscDualSpaceGetOrder(sp,&order);CHKERRQ(ierr); 433 ierr = PetscDualSpaceGetNumComponents(sp,&Nc);CHKERRQ(ierr); 434 ierr = DMGetDimension(sp->dm,&dim);CHKERRQ(ierr); 435 if (!dim || !lag->continuous || order < 3) PetscFunctionReturn(0); 436 if (dim > 3) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Lagrange symmetries not implemented for dim = %D > 3",dim); 437 if (!lag->symmetries) { /* store symmetries */ 438 PetscDualSpace hsp; 439 DM K; 440 PetscInt numPoints = 1, d; 441 PetscInt numFaces; 442 PetscInt ***symmetries; 443 const PetscInt ***hsymmetries; 444 445 if (lag->simplexCell) { 446 numFaces = 1 + dim; 447 for (d = 0; d < dim; d++) numPoints = numPoints * 2 + 1; 448 } else { 449 numPoints = PetscPowInt(3,dim); 450 numFaces = 2 * dim; 451 } 452 ierr = PetscCalloc1(numPoints,&symmetries);CHKERRQ(ierr); 453 if (0 < dim && dim < 3) { /* compute self symmetries */ 454 PetscInt **cellSymmetries; 455 456 lag->numSelfSym = 2 * numFaces; 457 lag->selfSymOff = numFaces; 458 ierr = PetscCalloc1(2*numFaces,&cellSymmetries);CHKERRQ(ierr); 459 /* we want to be able to index symmetries directly with the orientations, which range from [-numFaces,numFaces) */ 460 symmetries[0] = &cellSymmetries[numFaces]; 461 if (dim == 1) { 462 PetscInt dofPerEdge = order - 1; 463 464 if (dofPerEdge > 1) { 465 PetscInt i, j, *reverse; 466 467 ierr = PetscMalloc1(dofPerEdge*Nc,&reverse);CHKERRQ(ierr); 468 for (i = 0; i < dofPerEdge; i++) { 469 for (j = 0; j < Nc; j++) { 470 reverse[i*Nc + j] = Nc * (dofPerEdge - 1 - i) + j; 471 } 472 } 473 symmetries[0][-2] = reverse; 474 475 /* yes, this is redundant, but it makes it easier to cleanup if I don't have to worry about what not to free */ 476 ierr = PetscMalloc1(dofPerEdge*Nc,&reverse);CHKERRQ(ierr); 477 for (i = 0; i < dofPerEdge; i++) { 478 for (j = 0; j < Nc; j++) { 479 reverse[i*Nc + j] = Nc * (dofPerEdge - 1 - i) + j; 480 } 481 } 482 symmetries[0][1] = reverse; 483 } 484 } else { 485 PetscInt dofPerEdge = lag->simplexCell ? (order - 2) : (order - 1), s; 486 PetscInt dofPerFace; 487 488 if (dofPerEdge > 1) { 489 for (s = -numFaces; s < numFaces; s++) { 490 PetscInt *sym, i, j, k, l; 491 492 if (!s) continue; 493 if (lag->simplexCell) { 494 dofPerFace = (dofPerEdge * (dofPerEdge + 1))/2; 495 ierr = PetscMalloc1(Nc*dofPerFace,&sym);CHKERRQ(ierr); 496 for (j = 0, l = 0; j < dofPerEdge; j++) { 497 for (k = 0; k < dofPerEdge - j; k++, l++) { 498 i = dofPerEdge - 1 - j - k; 499 switch (s) { 500 case -3: 501 sym[Nc*l] = BaryIndex(dofPerEdge,i,k,j); 502 break; 503 case -2: 504 sym[Nc*l] = BaryIndex(dofPerEdge,j,i,k); 505 break; 506 case -1: 507 sym[Nc*l] = BaryIndex(dofPerEdge,k,j,i); 508 break; 509 case 1: 510 sym[Nc*l] = BaryIndex(dofPerEdge,k,i,j); 511 break; 512 case 2: 513 sym[Nc*l] = BaryIndex(dofPerEdge,j,k,i); 514 break; 515 } 516 } 517 } 518 } else { 519 dofPerFace = dofPerEdge * dofPerEdge; 520 ierr = PetscMalloc1(Nc*dofPerFace,&sym);CHKERRQ(ierr); 521 for (j = 0, l = 0; j < dofPerEdge; j++) { 522 for (k = 0; k < dofPerEdge; k++, l++) { 523 switch (s) { 524 case -4: 525 sym[Nc*l] = CartIndex(dofPerEdge,k,j); 526 break; 527 case -3: 528 sym[Nc*l] = CartIndex(dofPerEdge,(dofPerEdge - 1 - j),k); 529 break; 530 case -2: 531 sym[Nc*l] = CartIndex(dofPerEdge,(dofPerEdge - 1 - k),(dofPerEdge - 1 - j)); 532 break; 533 case -1: 534 sym[Nc*l] = CartIndex(dofPerEdge,j,(dofPerEdge - 1 - k)); 535 break; 536 case 1: 537 sym[Nc*l] = CartIndex(dofPerEdge,(dofPerEdge - 1 - k),j); 538 break; 539 case 2: 540 sym[Nc*l] = CartIndex(dofPerEdge,(dofPerEdge - 1 - j),(dofPerEdge - 1 - k)); 541 break; 542 case 3: 543 sym[Nc*l] = CartIndex(dofPerEdge,k,(dofPerEdge - 1 - j)); 544 break; 545 } 546 } 547 } 548 } 549 for (i = 0; i < dofPerFace; i++) { 550 sym[Nc*i] *= Nc; 551 for (j = 1; j < Nc; j++) { 552 sym[Nc*i+j] = sym[Nc*i] + j; 553 } 554 } 555 symmetries[0][s] = sym; 556 } 557 } 558 } 559 } 560 ierr = PetscDualSpaceGetHeightSubspace(sp,1,&hsp);CHKERRQ(ierr); 561 ierr = PetscDualSpaceGetSymmetries(hsp,&hsymmetries,NULL);CHKERRQ(ierr); 562 if (hsymmetries) { 563 PetscBool *seen; 564 const PetscInt *cone; 565 PetscInt KclosureSize, *Kclosure = NULL; 566 567 ierr = PetscDualSpaceGetDM(sp,&K);CHKERRQ(ierr); 568 ierr = PetscCalloc1(numPoints,&seen);CHKERRQ(ierr); 569 ierr = DMPlexGetCone(K,0,&cone);CHKERRQ(ierr); 570 ierr = DMPlexGetTransitiveClosure(K,0,PETSC_TRUE,&KclosureSize,&Kclosure);CHKERRQ(ierr); 571 for (p = 0; p < numFaces; p++) { 572 PetscInt closureSize, *closure = NULL, q; 573 574 ierr = DMPlexGetTransitiveClosure(K,cone[p],PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); 575 for (q = 0; q < closureSize; q++) { 576 PetscInt point = closure[2*q], r; 577 578 if(!seen[point]) { 579 for (r = 0; r < KclosureSize; r++) { 580 if (Kclosure[2 * r] == point) break; 581 } 582 seen[point] = PETSC_TRUE; 583 symmetries[r] = (PetscInt **) hsymmetries[q]; 584 } 585 } 586 ierr = DMPlexRestoreTransitiveClosure(K,cone[p],PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); 587 } 588 ierr = DMPlexRestoreTransitiveClosure(K,0,PETSC_TRUE,&KclosureSize,&Kclosure);CHKERRQ(ierr); 589 ierr = PetscFree(seen);CHKERRQ(ierr); 590 } 591 lag->symmetries = symmetries; 592 } 593 if (perms) *perms = (const PetscInt ***) lag->symmetries; 594 PetscFunctionReturn(0); 595 } 596 597 static PetscErrorCode PetscDualSpaceLagrangeGetContinuity_Lagrange(PetscDualSpace sp, PetscBool *continuous) 598 { 599 PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; 600 601 PetscFunctionBegin; 602 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 603 PetscValidPointer(continuous, 2); 604 *continuous = lag->continuous; 605 PetscFunctionReturn(0); 606 } 607 608 static PetscErrorCode PetscDualSpaceLagrangeSetContinuity_Lagrange(PetscDualSpace sp, PetscBool continuous) 609 { 610 PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; 611 612 PetscFunctionBegin; 613 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 614 lag->continuous = continuous; 615 PetscFunctionReturn(0); 616 } 617 618 /*@ 619 PetscDualSpaceLagrangeGetContinuity - Retrieves the flag for element continuity 620 621 Not Collective 622 623 Input Parameter: 624 . sp - the PetscDualSpace 625 626 Output Parameter: 627 . continuous - flag for element continuity 628 629 Level: intermediate 630 631 .seealso: PetscDualSpaceLagrangeSetContinuity() 632 @*/ 633 PetscErrorCode PetscDualSpaceLagrangeGetContinuity(PetscDualSpace sp, PetscBool *continuous) 634 { 635 PetscErrorCode ierr; 636 637 PetscFunctionBegin; 638 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 639 PetscValidPointer(continuous, 2); 640 ierr = PetscTryMethod(sp, "PetscDualSpaceLagrangeGetContinuity_C", (PetscDualSpace,PetscBool*),(sp,continuous));CHKERRQ(ierr); 641 PetscFunctionReturn(0); 642 } 643 644 /*@ 645 PetscDualSpaceLagrangeSetContinuity - Indicate whether the element is continuous 646 647 Logically Collective on sp 648 649 Input Parameters: 650 + sp - the PetscDualSpace 651 - continuous - flag for element continuity 652 653 Options Database: 654 . -petscdualspace_lagrange_continuity <bool> 655 656 Level: intermediate 657 658 .seealso: PetscDualSpaceLagrangeGetContinuity() 659 @*/ 660 PetscErrorCode PetscDualSpaceLagrangeSetContinuity(PetscDualSpace sp, PetscBool continuous) 661 { 662 PetscErrorCode ierr; 663 664 PetscFunctionBegin; 665 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 666 PetscValidLogicalCollectiveBool(sp, continuous, 2); 667 ierr = PetscTryMethod(sp, "PetscDualSpaceLagrangeSetContinuity_C", (PetscDualSpace,PetscBool),(sp,continuous));CHKERRQ(ierr); 668 PetscFunctionReturn(0); 669 } 670 671 static PetscErrorCode PetscDualSpaceLagrangeGetTensor_Lagrange(PetscDualSpace sp, PetscBool *tensor) 672 { 673 PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *)sp->data; 674 675 PetscFunctionBegin; 676 *tensor = lag->tensorSpace; 677 PetscFunctionReturn(0); 678 } 679 680 static PetscErrorCode PetscDualSpaceLagrangeSetTensor_Lagrange(PetscDualSpace sp, PetscBool tensor) 681 { 682 PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *)sp->data; 683 684 PetscFunctionBegin; 685 lag->tensorSpace = tensor; 686 PetscFunctionReturn(0); 687 } 688 689 /*@ 690 PetscDualSpaceLagrangeGetTensor - Get the tensor nature of the dual space 691 692 Not collective 693 694 Input Parameter: 695 . sp - The PetscDualSpace 696 697 Output Parameter: 698 . tensor - Whether the dual space has tensor layout (vs. simplicial) 699 700 Level: intermediate 701 702 .seealso: PetscDualSpaceLagrangeSetTensor(), PetscDualSpaceCreate() 703 @*/ 704 PetscErrorCode PetscDualSpaceLagrangeGetTensor(PetscDualSpace sp, PetscBool *tensor) 705 { 706 PetscErrorCode ierr; 707 708 PetscFunctionBegin; 709 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 710 PetscValidPointer(tensor, 2); 711 ierr = PetscTryMethod(sp,"PetscDualSpaceLagrangeGetTensor_C",(PetscDualSpace,PetscBool *),(sp,tensor));CHKERRQ(ierr); 712 PetscFunctionReturn(0); 713 } 714 715 /*@ 716 PetscDualSpaceLagrangeSetTensor - Set the tensor nature of the dual space 717 718 Not collective 719 720 Input Parameters: 721 + sp - The PetscDualSpace 722 - tensor - Whether the dual space has tensor layout (vs. simplicial) 723 724 Level: intermediate 725 726 .seealso: PetscDualSpaceLagrangeGetTensor(), PetscDualSpaceCreate() 727 @*/ 728 PetscErrorCode PetscDualSpaceLagrangeSetTensor(PetscDualSpace sp, PetscBool tensor) 729 { 730 PetscErrorCode ierr; 731 732 PetscFunctionBegin; 733 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 734 ierr = PetscTryMethod(sp,"PetscDualSpaceLagrangeSetTensor_C",(PetscDualSpace,PetscBool),(sp,tensor));CHKERRQ(ierr); 735 PetscFunctionReturn(0); 736 } 737 738 static PetscErrorCode PetscDualSpaceInitialize_Lagrange(PetscDualSpace sp) 739 { 740 PetscFunctionBegin; 741 sp->ops->destroy = PetscDualSpaceDestroy_Lagrange; 742 sp->ops->view = PetscDualSpaceView_Lagrange; 743 sp->ops->setfromoptions = PetscDualSpaceSetFromOptions_Lagrange; 744 sp->ops->duplicate = PetscDualSpaceDuplicate_Lagrange; 745 sp->ops->setup = PetscDualSpaceSetUp_Lagrange; 746 sp->ops->getdimension = PetscDualSpaceGetDimension_Lagrange; 747 sp->ops->getnumdof = PetscDualSpaceGetNumDof_Lagrange; 748 sp->ops->getheightsubspace = PetscDualSpaceGetHeightSubspace_Lagrange; 749 sp->ops->getsymmetries = PetscDualSpaceGetSymmetries_Lagrange; 750 sp->ops->apply = PetscDualSpaceApplyDefault; 751 sp->ops->applyall = PetscDualSpaceApplyAllDefault; 752 sp->ops->createallpoints = PetscDualSpaceCreateAllPointsDefault; 753 PetscFunctionReturn(0); 754 } 755 756 /*MC 757 PETSCDUALSPACELAGRANGE = "lagrange" - A PetscDualSpace object that encapsulates a dual space of pointwise evaluation functionals 758 759 Level: intermediate 760 761 .seealso: PetscDualSpaceType, PetscDualSpaceCreate(), PetscDualSpaceSetType() 762 M*/ 763 764 PETSC_EXTERN PetscErrorCode PetscDualSpaceCreate_Lagrange(PetscDualSpace sp) 765 { 766 PetscDualSpace_Lag *lag; 767 PetscErrorCode ierr; 768 769 PetscFunctionBegin; 770 PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); 771 ierr = PetscNewLog(sp,&lag);CHKERRQ(ierr); 772 sp->data = lag; 773 774 lag->numDof = NULL; 775 lag->simplexCell = PETSC_TRUE; 776 lag->tensorSpace = PETSC_FALSE; 777 lag->continuous = PETSC_TRUE; 778 779 ierr = PetscDualSpaceInitialize_Lagrange(sp);CHKERRQ(ierr); 780 ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetContinuity_C", PetscDualSpaceLagrangeGetContinuity_Lagrange);CHKERRQ(ierr); 781 ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetContinuity_C", PetscDualSpaceLagrangeSetContinuity_Lagrange);CHKERRQ(ierr); 782 ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeGetTensor_C", PetscDualSpaceLagrangeGetTensor_Lagrange);CHKERRQ(ierr); 783 ierr = PetscObjectComposeFunction((PetscObject) sp, "PetscDualSpaceLagrangeSetTensor_C", PetscDualSpaceLagrangeSetTensor_Lagrange);CHKERRQ(ierr); 784 PetscFunctionReturn(0); 785 } 786 787