Actual source code: spacepoly.c
petsc-3.10.5 2019-03-28
Report Typos and Errors

      1:  #include <petsc/private/petscfeimpl.h>

      3: PetscErrorCode PetscSpaceSetFromOptions_Polynomial(PetscOptionItems *PetscOptionsObject,PetscSpace sp)
      4: {
      5:   PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data;
      6:   PetscErrorCode   ierr;

      9:   PetscOptionsHead(PetscOptionsObject,"PetscSpace polynomial options");
     10:   PetscOptionsBool("-petscspace_poly_sym", "Use only symmetric polynomials", "PetscSpacePolynomialSetSymmetric", poly->symmetric, &poly->symmetric, NULL);
     11:   PetscOptionsBool("-petscspace_poly_tensor", "Use the tensor product polynomials", "PetscSpacePolynomialSetTensor", poly->tensor, &poly->tensor, NULL);
     12:   PetscOptionsTail();
     13:   return(0);
     14: }

     16: static PetscErrorCode PetscSpacePolynomialView_Ascii(PetscSpace sp, PetscViewer viewer)
     17: {
     18:   PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data;
     19:   PetscErrorCode   ierr;

     22:   if (poly->tensor) {PetscViewerASCIIPrintf(viewer, "Tensor polynomial space of degree %D\n", sp->degree);}
     23:   else              {PetscViewerASCIIPrintf(viewer, "Polynomial space of degree %D\n", sp->degree);}
     24:   return(0);
     25: }

     27: PetscErrorCode PetscSpaceView_Polynomial(PetscSpace sp, PetscViewer viewer)
     28: {
     29:   PetscBool      iascii;

     35:   PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
     36:   if (iascii) {PetscSpacePolynomialView_Ascii(sp, viewer);}
     37:   return(0);
     38: }

     40: PetscErrorCode PetscSpaceSetUp_Polynomial(PetscSpace sp)
     41: {
     42:   PetscSpace_Poly *poly    = (PetscSpace_Poly *) sp->data;
     43:   PetscInt         ndegree = sp->degree+1;
     44:   PetscInt         deg;
     45:   PetscErrorCode   ierr;

     48:   if (poly->setupCalled) return(0);
     49:   PetscMalloc1(ndegree, &poly->degrees);
     50:   for (deg = 0; deg < ndegree; ++deg) poly->degrees[deg] = deg;
     51:   if (poly->tensor) {
     52:     sp->maxDegree = sp->degree + PetscMax(sp->Nv - 1,0);
     53:   } else {
     54:     sp->maxDegree = sp->degree;
     55:   }
     56:   poly->setupCalled = PETSC_TRUE;
     57:   return(0);
     58: }

     60: PetscErrorCode PetscSpaceDestroy_Polynomial(PetscSpace sp)
     61: {
     62:   PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data;
     63:   PetscErrorCode   ierr;

     66:   PetscObjectComposeFunction((PetscObject) sp, "PetscSpacePolynomialGetTensor_C", NULL);
     67:   PetscObjectComposeFunction((PetscObject) sp, "PetscSpacePolynomialSetTensor_C", NULL);
     68:   PetscFree(poly->degrees);
     69:   if (poly->subspaces) {
     70:     PetscInt d;

     72:     for (d = 0; d < sp->Nv; ++d) {
     73:       PetscSpaceDestroy(&poly->subspaces[d]);
     74:     }
     75:   }
     76:   PetscFree(poly->subspaces);
     77:   PetscFree(poly);
     78:   return(0);
     79: }

     81: /* We treat the space as a tensor product of scalar polynomial spaces, so the dimension is multiplied by Nc */
     82: PetscErrorCode PetscSpaceGetDimension_Polynomial(PetscSpace sp, PetscInt *dim)
     83: {
     84:   PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data;
     85:   PetscInt         deg  = sp->degree;
     86:   PetscInt         n    = sp->Nv, i;
     87:   PetscReal        D    = 1.0;

     90:   if (poly->tensor) {
     91:     *dim = 1;
     92:     for (i = 0; i < n; ++i) *dim *= (deg+1);
     93:   } else {
     94:     for (i = 1; i <= n; ++i) {
     95:       D *= ((PetscReal) (deg+i))/i;
     96:     }
     97:     *dim = (PetscInt) (D + 0.5);
     98:   }
     99:   *dim *= sp->Nc;
    100:   return(0);
    101: }

    103: /*
    104:   LatticePoint_Internal - Returns all tuples of size 'len' with nonnegative integers that sum up to 'sum'.

    106:   Input Parameters:
    107: + len - The length of the tuple
    108: . sum - The sum of all entries in the tuple
    109: - ind - The current multi-index of the tuple, initialized to the 0 tuple

    111:   Output Parameter:
    112: + ind - The multi-index of the tuple, -1 indicates the iteration has terminated
    113: . tup - A tuple of len integers addig to sum

    115:   Level: developer

    117: .seealso:
    118: */
    119: static PetscErrorCode LatticePoint_Internal(PetscInt len, PetscInt sum, PetscInt ind[], PetscInt tup[])
    120: {
    121:   PetscInt       i;

    125:   if (len == 1) {
    126:     ind[0] = -1;
    127:     tup[0] = sum;
    128:   } else if (sum == 0) {
    129:     for (i = 0; i < len; ++i) {ind[0] = -1; tup[i] = 0;}
    130:   } else {
    131:     tup[0] = sum - ind[0];
    132:     LatticePoint_Internal(len-1, ind[0], &ind[1], &tup[1]);
    133:     if (ind[1] < 0) {
    134:       if (ind[0] == sum) {ind[0] = -1;}
    135:       else               {ind[1] = 0; ++ind[0];}
    136:     }
    137:   }
    138:   return(0);
    139: }

    141: /*
    142:   TensorPoint_Internal - Returns all tuples of size 'len' with nonnegative integers that are less than 'max'.

    144:   Input Parameters:
    145: + len - The length of the tuple
    146: . max - The max for all entries in the tuple
    147: - ind - The current multi-index of the tuple, initialized to the 0 tuple

    149:   Output Parameter:
    150: + ind - The multi-index of the tuple, -1 indicates the iteration has terminated
    151: . tup - A tuple of len integers less than max

    153:   Level: developer

    155: .seealso:
    156: */
    157: static PetscErrorCode TensorPoint_Internal(PetscInt len, PetscInt max, PetscInt ind[], PetscInt tup[])
    158: {
    159:   PetscInt       i;

    163:   if (len == 1) {
    164:     tup[0] = ind[0]++;
    165:     ind[0] = ind[0] >= max ? -1 : ind[0];
    166:   } else if (max == 0) {
    167:     for (i = 0; i < len; ++i) {ind[0] = -1; tup[i] = 0;}
    168:   } else {
    169:     tup[0] = ind[0];
    170:     TensorPoint_Internal(len-1, max, &ind[1], &tup[1]);
    171:     if (ind[1] < 0) {
    172:       ind[1] = 0;
    173:       if (ind[0] == max-1) {ind[0] = -1;}
    174:       else                 {++ind[0];}
    175:     }
    176:   }
    177:   return(0);
    178: }

    180: /*
    181:   p in [0, npoints), i in [0, pdim), c in [0, Nc)

    183:   B[p][i][c] = B[p][i_scalar][c][c]
    184: */
    185: PetscErrorCode PetscSpaceEvaluate_Polynomial(PetscSpace sp, PetscInt npoints, const PetscReal points[], PetscReal B[], PetscReal D[], PetscReal H[])
    186: {
    187:   PetscSpace_Poly *poly    = (PetscSpace_Poly *) sp->data;
    188:   DM               dm      = sp->dm;
    189:   PetscInt         Nc      = sp->Nc;
    190:   PetscInt         ndegree = sp->degree+1;
    191:   PetscInt        *degrees = poly->degrees;
    192:   PetscInt         dim     = sp->Nv;
    193:   PetscReal       *lpoints, *tmp, *LB, *LD, *LH;
    194:   PetscInt        *ind, *tup;
    195:   PetscInt         c, pdim, d, e, der, der2, i, p, deg, o;
    196:   PetscErrorCode   ierr;

    199:   PetscSpaceGetDimension(sp, &pdim);
    200:   pdim /= Nc;
    201:   DMGetWorkArray(dm, npoints, MPIU_REAL, &lpoints);
    202:   DMGetWorkArray(dm, npoints*ndegree*3, MPIU_REAL, &tmp);
    203:   if (B || D || H) {DMGetWorkArray(dm, npoints*dim*ndegree, MPIU_REAL, &LB);}
    204:   if (D || H)      {DMGetWorkArray(dm, npoints*dim*ndegree, MPIU_REAL, &LD);}
    205:   if (H)           {DMGetWorkArray(dm, npoints*dim*ndegree, MPIU_REAL, &LH);}
    206:   for (d = 0; d < dim; ++d) {
    207:     for (p = 0; p < npoints; ++p) {
    208:       lpoints[p] = points[p*dim+d];
    209:     }
    210:     PetscDTLegendreEval(npoints, lpoints, ndegree, degrees, tmp, &tmp[1*npoints*ndegree], &tmp[2*npoints*ndegree]);
    211:     /* LB, LD, LH (ndegree * dim x npoints) */
    212:     for (deg = 0; deg < ndegree; ++deg) {
    213:       for (p = 0; p < npoints; ++p) {
    214:         if (B || D || H) LB[(deg*dim + d)*npoints + p] = tmp[(0*npoints + p)*ndegree+deg];
    215:         if (D || H)      LD[(deg*dim + d)*npoints + p] = tmp[(1*npoints + p)*ndegree+deg];
    216:         if (H)           LH[(deg*dim + d)*npoints + p] = tmp[(2*npoints + p)*ndegree+deg];
    217:       }
    218:     }
    219:   }
    220:   /* Multiply by A (pdim x ndegree * dim) */
    221:   PetscMalloc2(dim,&ind,dim,&tup);
    222:   if (B) {
    223:     /* B (npoints x pdim x Nc) */
    224:     PetscMemzero(B, npoints*pdim*Nc*Nc * sizeof(PetscReal));
    225:     if (poly->tensor) {
    226:       i = 0;
    227:       PetscMemzero(ind, dim * sizeof(PetscInt));
    228:       while (ind[0] >= 0) {
    229:         TensorPoint_Internal(dim, sp->degree+1, ind, tup);
    230:         for (p = 0; p < npoints; ++p) {
    231:           B[(p*pdim + i)*Nc*Nc] = 1.0;
    232:           for (d = 0; d < dim; ++d) {
    233:             B[(p*pdim + i)*Nc*Nc] *= LB[(tup[d]*dim + d)*npoints + p];
    234:           }
    235:         }
    236:         ++i;
    237:       }
    238:     } else {
    239:       i = 0;
    240:       for (o = 0; o <= sp->degree; ++o) {
    241:         PetscMemzero(ind, dim * sizeof(PetscInt));
    242:         while (ind[0] >= 0) {
    243:           LatticePoint_Internal(dim, o, ind, tup);
    244:           for (p = 0; p < npoints; ++p) {
    245:             B[(p*pdim + i)*Nc*Nc] = 1.0;
    246:             for (d = 0; d < dim; ++d) {
    247:               B[(p*pdim + i)*Nc*Nc] *= LB[(tup[d]*dim + d)*npoints + p];
    248:             }
    249:           }
    250:           ++i;
    251:         }
    252:       }
    253:     }
    254:     /* Make direct sum basis for multicomponent space */
    255:     for (p = 0; p < npoints; ++p) {
    256:       for (i = 0; i < pdim; ++i) {
    257:         for (c = 1; c < Nc; ++c) {
    258:           B[(p*pdim*Nc + i*Nc + c)*Nc + c] = B[(p*pdim + i)*Nc*Nc];
    259:         }
    260:       }
    261:     }
    262:   }
    263:   if (D) {
    264:     /* D (npoints x pdim x Nc x dim) */
    265:     PetscMemzero(D, npoints*pdim*Nc*Nc*dim * sizeof(PetscReal));
    266:     if (poly->tensor) {
    267:       i = 0;
    268:       PetscMemzero(ind, dim * sizeof(PetscInt));
    269:       while (ind[0] >= 0) {
    270:         TensorPoint_Internal(dim, sp->degree+1, ind, tup);
    271:         for (p = 0; p < npoints; ++p) {
    272:           for (der = 0; der < dim; ++der) {
    273:             D[(p*pdim + i)*Nc*Nc*dim + der] = 1.0;
    274:             for (d = 0; d < dim; ++d) {
    275:               if (d == der) {
    276:                 D[(p*pdim + i)*Nc*Nc*dim + der] *= LD[(tup[d]*dim + d)*npoints + p];
    277:               } else {
    278:                 D[(p*pdim + i)*Nc*Nc*dim + der] *= LB[(tup[d]*dim + d)*npoints + p];
    279:               }
    280:             }
    281:           }
    282:         }
    283:         ++i;
    284:       }
    285:     } else {
    286:       i = 0;
    287:       for (o = 0; o <= sp->degree; ++o) {
    288:         PetscMemzero(ind, dim * sizeof(PetscInt));
    289:         while (ind[0] >= 0) {
    290:           LatticePoint_Internal(dim, o, ind, tup);
    291:           for (p = 0; p < npoints; ++p) {
    292:             for (der = 0; der < dim; ++der) {
    293:               D[(p*pdim + i)*Nc*Nc*dim + der] = 1.0;
    294:               for (d = 0; d < dim; ++d) {
    295:                 if (d == der) {
    296:                   D[(p*pdim + i)*Nc*Nc*dim + der] *= LD[(tup[d]*dim + d)*npoints + p];
    297:                 } else {
    298:                   D[(p*pdim + i)*Nc*Nc*dim + der] *= LB[(tup[d]*dim + d)*npoints + p];
    299:                 }
    300:               }
    301:             }
    302:           }
    303:           ++i;
    304:         }
    305:       }
    306:     }
    307:     /* Make direct sum basis for multicomponent space */
    308:     for (p = 0; p < npoints; ++p) {
    309:       for (i = 0; i < pdim; ++i) {
    310:         for (c = 1; c < Nc; ++c) {
    311:           for (d = 0; d < dim; ++d) {
    312:             D[((p*pdim*Nc + i*Nc + c)*Nc + c)*dim + d] = D[(p*pdim + i)*Nc*Nc*dim + d];
    313:           }
    314:         }
    315:       }
    316:     }
    317:   }
    318:   if (H) {
    319:     /* H (npoints x pdim x Nc x Nc x dim x dim) */
    320:     PetscMemzero(H, npoints*pdim*Nc*Nc*dim*dim * sizeof(PetscReal));
    321:     if (poly->tensor) {
    322:       i = 0;
    323:       PetscMemzero(ind, dim * sizeof(PetscInt));
    324:       while (ind[0] >= 0) {
    325:         TensorPoint_Internal(dim, sp->degree+1, ind, tup);
    326:         for (p = 0; p < npoints; ++p) {
    327:           for (der = 0; der < dim; ++der) {
    328:             H[((p*pdim + i)*Nc*Nc*dim + der) * dim + der] = 1.0;
    329:             for (d = 0; d < dim; ++d) {
    330:               if (d == der) {
    331:                 H[((p*pdim + i)*Nc*Nc*dim + der) * dim + der] *= LH[(tup[d]*dim + d)*npoints + p];
    332:               } else {
    333:                 H[((p*pdim + i)*Nc*Nc*dim + der) * dim + der] *= LB[(tup[d]*dim + d)*npoints + p];
    334:               }
    335:             }
    336:             for (der2 = der + 1; der2 < dim; ++der2) {
    337:               H[((p*pdim + i)*Nc*Nc*dim + der) * dim + der2] = 1.0;
    338:               for (d = 0; d < dim; ++d) {
    339:                 if (d == der || d == der2) {
    340:                   H[((p*pdim + i)*Nc*Nc*dim + der) * dim + der2] *= LD[(tup[d]*dim + d)*npoints + p];
    341:                 } else {
    342:                   H[((p*pdim + i)*Nc*Nc*dim + der) * dim + der2] *= LB[(tup[d]*dim + d)*npoints + p];
    343:                 }
    344:               }
    345:               H[((p*pdim + i)*Nc*Nc*dim + der2) * dim + der] = H[((p*pdim + i)*Nc*Nc*dim + der) * dim + der2];
    346:             }
    347:           }
    348:         }
    349:         ++i;
    350:       }
    351:     } else {
    352:       i = 0;
    353:       for (o = 0; o <= sp->degree; ++o) {
    354:         PetscMemzero(ind, dim * sizeof(PetscInt));
    355:         while (ind[0] >= 0) {
    356:           LatticePoint_Internal(dim, o, ind, tup);
    357:           for (p = 0; p < npoints; ++p) {
    358:             for (der = 0; der < dim; ++der) {
    359:               H[((p*pdim + i)*Nc*Nc*dim + der)*dim + der] = 1.0;
    360:               for (d = 0; d < dim; ++d) {
    361:                 if (d == der) {
    362:                   H[((p*pdim + i)*Nc*Nc*dim + der)*dim + der] *= LH[(tup[d]*dim + d)*npoints + p];
    363:                 } else {
    364:                   H[((p*pdim + i)*Nc*Nc*dim + der)*dim + der] *= LB[(tup[d]*dim + d)*npoints + p];
    365:                 }
    366:               }
    367:               for (der2 = der + 1; der2 < dim; ++der2) {
    368:                 H[((p*pdim + i)*Nc*Nc*dim + der) * dim + der2] = 1.0;
    369:                 for (d = 0; d < dim; ++d) {
    370:                   if (d == der || d == der2) {
    371:                     H[((p*pdim + i)*Nc*Nc*dim + der) * dim + der2] *= LD[(tup[d]*dim + d)*npoints + p];
    372:                   } else {
    373:                     H[((p*pdim + i)*Nc*Nc*dim + der) * dim + der2] *= LB[(tup[d]*dim + d)*npoints + p];
    374:                   }
    375:                 }
    376:                 H[((p*pdim + i)*Nc*Nc*dim + der2) * dim + der] = H[((p*pdim + i)*Nc*Nc*dim + der) * dim + der2];
    377:               }
    378:             }
    379:           }
    380:           ++i;
    381:         }
    382:       }
    383:     }
    384:     /* Make direct sum basis for multicomponent space */
    385:     for (p = 0; p < npoints; ++p) {
    386:       for (i = 0; i < pdim; ++i) {
    387:         for (c = 1; c < Nc; ++c) {
    388:           for (d = 0; d < dim; ++d) {
    389:             for (e = 0; e < dim; ++e) {
    390:               H[(((p*pdim*Nc + i*Nc + c)*Nc + c)*dim + d)*dim + e] = H[((p*pdim + i)*Nc*Nc*dim + d)*dim + e];
    391:             }
    392:           }
    393:         }
    394:       }
    395:     }
    396:   }
    397:   PetscFree2(ind,tup);
    398:   if (H)           {DMRestoreWorkArray(dm, npoints*dim*ndegree, MPIU_REAL, &LH);}
    399:   if (D || H)      {DMRestoreWorkArray(dm, npoints*dim*ndegree, MPIU_REAL, &LD);}
    400:   if (B || D || H) {DMRestoreWorkArray(dm, npoints*dim*ndegree, MPIU_REAL, &LB);}
    401:   DMRestoreWorkArray(dm, npoints*ndegree*3, MPIU_REAL, &tmp);
    402:   DMRestoreWorkArray(dm, npoints, MPIU_REAL, &lpoints);
    403:   return(0);
    404: }

    406: /*@
    407:   PetscSpacePolynomialSetTensor - Set whether a function space is a space of tensor polynomials (the space is spanned
    408:   by polynomials whose degree in each variabl is bounded by the given order), as opposed to polynomials (the space is
    409:   spanned by polynomials whose total degree---summing over all variables---is bounded by the given order).

    411:   Input Parameters:
    412: + sp     - the function space object
    413: - tensor - PETSC_TRUE for a tensor polynomial space, PETSC_FALSE for a polynomial space

    415:   Level: beginner

    417: .seealso: PetscSpacePolynomialGetTensor(), PetscSpaceSetDegree(), PetscSpaceSetNumVariables()
    418: @*/
    419: PetscErrorCode PetscSpacePolynomialSetTensor(PetscSpace sp, PetscBool tensor)
    420: {

    425:   PetscTryMethod(sp,"PetscSpacePolynomialSetTensor_C",(PetscSpace,PetscBool),(sp,tensor));
    426:   return(0);
    427: }

    429: /*@
    430:   PetscSpacePolynomialGetTensor - Get whether a function space is a space of tensor polynomials (the space is spanned
    431:   by polynomials whose degree in each variabl is bounded by the given order), as opposed to polynomials (the space is
    432:   spanned by polynomials whose total degree---summing over all variables---is bounded by the given order).

    434:   Input Parameters:
    435: . sp     - the function space object

    437:   Output Parameters:
    438: . tensor - PETSC_TRUE for a tensor polynomial space, PETSC_FALSE for a polynomial space

    440:   Level: beginner

    442: .seealso: PetscSpacePolynomialSetTensor(), PetscSpaceSetDegree(), PetscSpaceSetNumVariables()
    443: @*/
    444: PetscErrorCode PetscSpacePolynomialGetTensor(PetscSpace sp, PetscBool *tensor)
    445: {

    451:   PetscTryMethod(sp,"PetscSpacePolynomialGetTensor_C",(PetscSpace,PetscBool*),(sp,tensor));
    452:   return(0);
    453: }

    455: static PetscErrorCode PetscSpacePolynomialSetTensor_Polynomial(PetscSpace sp, PetscBool tensor)
    456: {
    457:   PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data;

    460:   poly->tensor = tensor;
    461:   return(0);
    462: }

    464: static PetscErrorCode PetscSpacePolynomialGetTensor_Polynomial(PetscSpace sp, PetscBool *tensor)
    465: {
    466:   PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data;

    471:   *tensor = poly->tensor;
    472:   return(0);
    473: }

    475: static PetscErrorCode PetscSpaceGetHeightSubspace_Polynomial(PetscSpace sp, PetscInt height, PetscSpace *subsp)
    476: {
    477:   PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data;
    478:   PetscInt         Nc, dim, order;
    479:   PetscBool        tensor;
    480:   PetscErrorCode   ierr;

    483:   PetscSpaceGetNumComponents(sp, &Nc);
    484:   PetscSpaceGetNumVariables(sp, &dim);
    485:   PetscSpaceGetDegree(sp, &order, NULL);
    486:   PetscSpacePolynomialGetTensor(sp, &tensor);
    487:   if (height > dim || height < 0) {SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Asked for space at height %D for dimension %D space", height, dim);}
    488:   if (!poly->subspaces) {PetscCalloc1(dim, &poly->subspaces);}
    489:   if (height <= dim) {
    490:     if (!poly->subspaces[height-1]) {
    491:       PetscSpace sub;

    493:       PetscSpaceCreate(PetscObjectComm((PetscObject) sp), &sub);
    494:       PetscSpaceSetType(sub, PETSCSPACEPOLYNOMIAL);
    495:       PetscSpaceSetNumComponents(sub, Nc);
    496:       PetscSpaceSetDegree(sub, order, PETSC_DETERMINE);
    497:       PetscSpaceSetNumVariables(sub, dim-height);
    498:       PetscSpacePolynomialSetTensor(sub, tensor);
    499:       PetscSpaceSetUp(sub);
    500:       poly->subspaces[height-1] = sub;
    501:     }
    502:     *subsp = poly->subspaces[height-1];
    503:   } else {
    504:     *subsp = NULL;
    505:   }
    506:   return(0);
    507: }

    509: PetscErrorCode PetscSpaceInitialize_Polynomial(PetscSpace sp)
    510: {

    514:   sp->ops->setfromoptions    = PetscSpaceSetFromOptions_Polynomial;
    515:   sp->ops->setup             = PetscSpaceSetUp_Polynomial;
    516:   sp->ops->view              = PetscSpaceView_Polynomial;
    517:   sp->ops->destroy           = PetscSpaceDestroy_Polynomial;
    518:   sp->ops->getdimension      = PetscSpaceGetDimension_Polynomial;
    519:   sp->ops->evaluate          = PetscSpaceEvaluate_Polynomial;
    520:   sp->ops->getheightsubspace = PetscSpaceGetHeightSubspace_Polynomial;
    521:   PetscObjectComposeFunction((PetscObject) sp, "PetscSpacePolynomialGetTensor_C", PetscSpacePolynomialGetTensor_Polynomial);
    522:   PetscObjectComposeFunction((PetscObject) sp, "PetscSpacePolynomialSetTensor_C", PetscSpacePolynomialSetTensor_Polynomial);
    523:   return(0);
    524: }

    526: /*MC
    527:   PETSCSPACEPOLYNOMIAL = "poly" - A PetscSpace object that encapsulates a polynomial space, e.g. P1 is the space of
    528:   linear polynomials. The space is replicated for each component.

    530:   Level: intermediate

    532: .seealso: PetscSpaceType, PetscSpaceCreate(), PetscSpaceSetType()
    533: M*/

    535: PETSC_EXTERN PetscErrorCode PetscSpaceCreate_Polynomial(PetscSpace sp)
    536: {
    537:   PetscSpace_Poly *poly;
    538:   PetscErrorCode   ierr;

    542:   PetscNewLog(sp,&poly);
    543:   sp->data = poly;

    545:   poly->symmetric    = PETSC_FALSE;
    546:   poly->tensor       = PETSC_FALSE;
    547:   poly->degrees      = NULL;
    548:   poly->subspaces    = NULL;

    550:   PetscSpaceInitialize_Polynomial(sp);
    551:   return(0);
    552: }

    554: PetscErrorCode PetscSpacePolynomialSetSymmetric(PetscSpace sp, PetscBool sym)
    555: {
    556:   PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data;

    560:   poly->symmetric = sym;
    561:   return(0);
    562: }

    564: PetscErrorCode PetscSpacePolynomialGetSymmetric(PetscSpace sp, PetscBool *sym)
    565: {
    566:   PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data;

    571:   *sym = poly->symmetric;
    572:   return(0);
    573: }