/* Discretization tools */ #include #if defined(PETSC_HAVE_MATHIMF_H) #include /* this needs to be included before math.h */ #endif #include /*I "petscdt.h" I*/ /*I "petscfe.h" I*/ #include #include #include #include #include #undef __FUNCT__ #define __FUNCT__ "PetscQuadratureDestroy" PetscErrorCode PetscQuadratureDestroy(PetscQuadrature *q) { PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscFree(q->quadPoints);CHKERRQ(ierr); ierr = PetscFree(q->quadWeights);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDTLegendreEval" /*@ PetscDTLegendreEval - evaluate Legendre polynomial at points Not Collective Input Arguments: + npoints - number of spatial points to evaluate at . points - array of locations to evaluate at . ndegree - number of basis degrees to evaluate - degrees - sorted array of degrees to evaluate Output Arguments: + B - row-oriented basis evaluation matrix B[point*ndegree + degree] (dimension npoints*ndegrees, allocated by caller) (or NULL) . D - row-oriented derivative evaluation matrix (or NULL) - D2 - row-oriented second derivative evaluation matrix (or NULL) Level: intermediate .seealso: PetscDTGaussQuadrature() @*/ PetscErrorCode PetscDTLegendreEval(PetscInt npoints,const PetscReal *points,PetscInt ndegree,const PetscInt *degrees,PetscReal *B,PetscReal *D,PetscReal *D2) { PetscInt i,maxdegree; PetscFunctionBegin; if (!npoints || !ndegree) PetscFunctionReturn(0); maxdegree = degrees[ndegree-1]; for (i=0; i 0) r = 0.5 * (r + x[k-1]); for (j = 0; j < maxIter; ++j) { PetscReal s = 0.0, delta, f, fp; PetscInt i; for (i = 0; i < k; ++i) s = s + 1.0 / (r - x[i]); ierr = PetscDTComputeJacobi(a, b, npoints, r, &f);CHKERRQ(ierr); ierr = PetscDTComputeJacobiDerivative(a, b, npoints, r, &fp);CHKERRQ(ierr); delta = f / (fp - f * s); r = r - delta; if (fabs(delta) < eps) break; } x[k] = r; ierr = PetscDTComputeJacobiDerivative(a, b, npoints, x[k], &dP);CHKERRQ(ierr); w[k] = a6 / (1.0 - PetscSqr(x[k])) / PetscSqr(dP); } PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDTGaussJacobiQuadrature" /*@C PetscDTGaussJacobiQuadrature - create Gauss-Jacobi quadrature for a simplex Not Collective Input Arguments: + dim - The simplex dimension . npoints - number of points . a - left end of interval (often-1) - b - right end of interval (often +1) Output Arguments: + points - quadrature points - weights - quadrature weights Level: intermediate References: Karniadakis and Sherwin. FIAT .seealso: PetscDTGaussQuadrature() @*/ PetscErrorCode PetscDTGaussJacobiQuadrature(PetscInt dim, PetscInt npoints, PetscReal a, PetscReal b, PetscReal *points[], PetscReal *weights[]) { PetscReal *px, *wx, *py, *wy, *pz, *wz, *x, *w; PetscInt i, j, k; PetscErrorCode ierr; PetscFunctionBegin; if ((a != -1.0) || (b != 1.0)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must use default internal right now"); switch (dim) { case 1: ierr = PetscMalloc(npoints * sizeof(PetscReal), &x);CHKERRQ(ierr); ierr = PetscMalloc(npoints * sizeof(PetscReal), &w);CHKERRQ(ierr); ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 0.0, 0.0, x, w);CHKERRQ(ierr); break; case 2: ierr = PetscMalloc(npoints*npoints*2 * sizeof(PetscReal), &x);CHKERRQ(ierr); ierr = PetscMalloc(npoints*npoints * sizeof(PetscReal), &w);CHKERRQ(ierr); ierr = PetscMalloc4(npoints,PetscReal,&px,npoints,PetscReal,&wx,npoints,PetscReal,&py,npoints,PetscReal,&wy);CHKERRQ(ierr); ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 0.0, 0.0, px, wx);CHKERRQ(ierr); ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 1.0, 0.0, py, wy);CHKERRQ(ierr); for (i = 0; i < npoints; ++i) { for (j = 0; j < npoints; ++j) { ierr = PetscDTMapSquareToTriangle_Internal(px[i], py[j], &x[(i*npoints+j)*2+0], &x[(i*npoints+j)*2+1]);CHKERRQ(ierr); w[i*npoints+j] = 0.5 * wx[i] * wy[j]; } } ierr = PetscFree4(px,wx,py,wy);CHKERRQ(ierr); break; case 3: ierr = PetscMalloc(npoints*npoints*3 * sizeof(PetscReal), &x);CHKERRQ(ierr); ierr = PetscMalloc(npoints*npoints * sizeof(PetscReal), &w);CHKERRQ(ierr); ierr = PetscMalloc6(npoints,PetscReal,&px,npoints,PetscReal,&wx,npoints,PetscReal,&py,npoints,PetscReal,&wy,npoints,PetscReal,&pz,npoints,PetscReal,&wz);CHKERRQ(ierr); ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 0.0, 0.0, px, wx);CHKERRQ(ierr); ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 1.0, 0.0, py, wy);CHKERRQ(ierr); ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 2.0, 0.0, pz, wz);CHKERRQ(ierr); for (i = 0; i < npoints; ++i) { for (j = 0; j < npoints; ++j) { for (k = 0; k < npoints; ++k) { ierr = PetscDTMapCubeToTetrahedron_Internal(px[i], py[j], pz[k], &x[((i*npoints+j)*npoints+k)*3+0], &x[((i*npoints+j)*npoints+k)*3+1], &x[((i*npoints+j)*npoints+k)*3+2]);CHKERRQ(ierr); w[(i*npoints+j)*npoints+k] = 0.125 * wx[i] * wy[j] * wz[k]; } } } ierr = PetscFree6(px,wx,py,wy,pz,wz);CHKERRQ(ierr); break; default: SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct quadrature rule for dimension %d", dim); } if (points) *points = x; if (weights) *weights = w; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDTPseudoInverseQR" /* Overwrites A. Can only handle full-rank problems with m>=n * A in column-major format * Ainv in row-major format * tau has length m * worksize must be >= max(1,n) */ static PetscErrorCode PetscDTPseudoInverseQR(PetscInt m,PetscInt mstride,PetscInt n,PetscReal *A_in,PetscReal *Ainv_out,PetscScalar *tau,PetscInt worksize,PetscScalar *work) { PetscErrorCode ierr; PetscBLASInt M,N,K,lda,ldb,ldwork,info; PetscScalar *A,*Ainv,*R,*Q,Alpha; PetscFunctionBegin; #if defined(PETSC_USE_COMPLEX) { PetscInt i,j; ierr = PetscMalloc2(m*n,PetscScalar,&A,m*n,PetscScalar,&Ainv);CHKERRQ(ierr); for (j=0; j= nsource) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Reconstruction degree %D must be less than number of source intervals %D",degree,nsource); #if defined(PETSC_USE_DEBUG) for (i=0; i= sourcex[i+1]) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"Source interval %D has negative orientation (%G,%G)",i,sourcex[i],sourcex[i+1]); } for (i=0; i= targetx[i+1]) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"Target interval %D has negative orientation (%G,%G)",i,targetx[i],targetx[i+1]); } #endif xmin = PetscMin(sourcex[0],targetx[0]); xmax = PetscMax(sourcex[nsource],targetx[ntarget]); center = (xmin + xmax)/2; hscale = (xmax - xmin)/2; worksize = nsource; ierr = PetscMalloc4(degree+1,PetscInt,&bdegrees,nsource+1,PetscReal,&sourcey,nsource*(degree+1),PetscReal,&Bsource,worksize,PetscScalar,&work);CHKERRQ(ierr); ierr = PetscMalloc4(nsource,PetscScalar,&tau,nsource*(degree+1),PetscReal,&Bsinv,ntarget+1,PetscReal,&targety,ntarget*(degree+1),PetscReal,&Btarget);CHKERRQ(ierr); for (i=0; i<=nsource; i++) sourcey[i] = (sourcex[i]-center)/hscale; for (i=0; i<=degree; i++) bdegrees[i] = i+1; ierr = PetscDTLegendreIntegrate(nsource,sourcey,degree+1,bdegrees,PETSC_TRUE,Bsource);CHKERRQ(ierr); ierr = PetscDTPseudoInverseQR(nsource,nsource,degree+1,Bsource,Bsinv,tau,nsource,work);CHKERRQ(ierr); for (i=0; i<=ntarget; i++) targety[i] = (targetx[i]-center)/hscale; ierr = PetscDTLegendreIntegrate(ntarget,targety,degree+1,bdegrees,PETSC_FALSE,Btarget);CHKERRQ(ierr); for (i=0; i PetscInt PETSCSPACE_CLASSID = 0; PetscFunctionList PetscSpaceList = NULL; PetscBool PetscSpaceRegisterAllCalled = PETSC_FALSE; #undef __FUNCT__ #define __FUNCT__ "PetscSpaceRegister" /*@C PetscSpaceRegister - Adds a new PetscSpace implementation Not Collective Input Parameters: + name - The name of a new user-defined creation routine - create_func - The creation routine itself Notes: PetscSpaceRegister() may be called multiple times to add several user-defined PetscSpaces Sample usage: .vb PetscSpaceRegister("my_space", MyPetscSpaceCreate); .ve Then, your PetscSpace type can be chosen with the procedural interface via .vb PetscSpaceCreate(MPI_Comm, PetscSpace *); PetscSpaceSetType(PetscSpace, "my_space"); .ve or at runtime via the option .vb -petscspace_type my_space .ve Level: advanced .keywords: PetscSpace, register .seealso: PetscSpaceRegisterAll(), PetscSpaceRegisterDestroy() @*/ PetscErrorCode PetscSpaceRegister(const char sname[], PetscErrorCode (*function)(PetscSpace)) { PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscFunctionListAdd(&PetscSpaceList, sname, function);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceSetType" /*@C PetscSpaceSetType - Builds a particular PetscSpace Collective on PetscSpace Input Parameters: + sp - The PetscSpace object - name - The kind of space Options Database Key: . -petscspace_type - Sets the PetscSpace type; use -help for a list of available types Level: intermediate .keywords: PetscSpace, set, type .seealso: PetscSpaceGetType(), PetscSpaceCreate() @*/ PetscErrorCode PetscSpaceSetType(PetscSpace sp, PetscSpaceType name) { PetscErrorCode (*r)(PetscSpace); PetscBool match; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1); ierr = PetscObjectTypeCompare((PetscObject) sp, name, &match);CHKERRQ(ierr); if (match) PetscFunctionReturn(0); if (!PetscSpaceRegisterAllCalled) {ierr = PetscSpaceRegisterAll();CHKERRQ(ierr);} ierr = PetscFunctionListFind(PetscSpaceList, name, &r);CHKERRQ(ierr); if (!r) SETERRQ1(PetscObjectComm((PetscObject) sp), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscSpace type: %s", name); if (sp->ops->destroy) { ierr = (*sp->ops->destroy)(sp);CHKERRQ(ierr); sp->ops->destroy = NULL; } ierr = (*r)(sp);CHKERRQ(ierr); ierr = PetscObjectChangeTypeName((PetscObject) sp, name);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceGetType" /*@C PetscSpaceGetType - Gets the PetscSpace type name (as a string) from the object. Not Collective Input Parameter: . dm - The PetscSpace Output Parameter: . name - The PetscSpace type name Level: intermediate .keywords: PetscSpace, get, type, name .seealso: PetscSpaceSetType(), PetscSpaceCreate() @*/ PetscErrorCode PetscSpaceGetType(PetscSpace sp, PetscSpaceType *name) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1); PetscValidCharPointer(name, 2); if (!PetscSpaceRegisterAllCalled) { ierr = PetscSpaceRegisterAll();CHKERRQ(ierr); } *name = ((PetscObject) sp)->type_name; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceView" /*@C PetscSpaceView - Views a PetscSpace Collective on PetscSpace Input Parameter: + sp - the PetscSpace object to view - v - the viewer Level: developer .seealso PetscSpaceDestroy() @*/ PetscErrorCode PetscSpaceView(PetscSpace sp, PetscViewer v) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1); if (!v) { ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) sp), &v);CHKERRQ(ierr); } if (sp->ops->view) { ierr = (*sp->ops->view)(sp, v);CHKERRQ(ierr); } PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceViewFromOptions" /* PetscSpaceViewFromOptions - Processes command line options to determine if/how a PetscSpace is to be viewed. Collective on PetscSpace Input Parameters: + sp - the PetscSpace . prefix - prefix to use for viewing, or NULL to use prefix of 'rnd' - optionname - option to activate viewing Level: intermediate .keywords: PetscSpace, view, options, database .seealso: VecViewFromOptions(), MatViewFromOptions() */ PetscErrorCode PetscSpaceViewFromOptions(PetscSpace sp, const char prefix[], const char optionname[]) { PetscViewer viewer; PetscViewerFormat format; PetscBool flg; PetscErrorCode ierr; PetscFunctionBegin; if (prefix) { ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) sp), prefix, optionname, &viewer, &format, &flg);CHKERRQ(ierr); } else { ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) sp), ((PetscObject) sp)->prefix, optionname, &viewer, &format, &flg);CHKERRQ(ierr); } if (flg) { ierr = PetscViewerPushFormat(viewer, format);CHKERRQ(ierr); ierr = PetscSpaceView(sp, viewer);CHKERRQ(ierr); ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); } PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceSetFromOptions" /*@ PetscSpaceSetFromOptions - sets parameters in a PetscSpace from the options database Collective on PetscSpace Input Parameter: . sp - the PetscSpace object to set options for Options Database: . -petscspace_order the approximation order of the space Level: developer .seealso PetscSpaceView() @*/ PetscErrorCode PetscSpaceSetFromOptions(PetscSpace sp) { const char *defaultType; char typename[256]; PetscBool flg; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1); if (!((PetscObject) sp)->type_name) { defaultType = PETSCSPACEPOLYNOMIAL; } else { defaultType = ((PetscObject) sp)->type_name; } if (!PetscSpaceRegisterAllCalled) {ierr = PetscSpaceRegisterAll();CHKERRQ(ierr);} ierr = PetscObjectOptionsBegin((PetscObject) sp);CHKERRQ(ierr); ierr = PetscOptionsList("-petscspace_type", "Linear space", "PetscSpaceSetType", PetscSpaceList, defaultType, typename, 256, &flg);CHKERRQ(ierr); if (flg) { ierr = PetscSpaceSetType(sp, typename);CHKERRQ(ierr); } else if (!((PetscObject) sp)->type_name) { ierr = PetscSpaceSetType(sp, defaultType);CHKERRQ(ierr); } ierr = PetscOptionsInt("-petscspace_order", "The approximation order", "PetscSpaceSetOrder", sp->order, &sp->order, NULL);CHKERRQ(ierr); if (sp->ops->setfromoptions) { ierr = (*sp->ops->setfromoptions)(sp);CHKERRQ(ierr); } /* process any options handlers added with PetscObjectAddOptionsHandler() */ ierr = PetscObjectProcessOptionsHandlers((PetscObject) sp);CHKERRQ(ierr); ierr = PetscOptionsEnd();CHKERRQ(ierr); ierr = PetscSpaceViewFromOptions(sp, NULL, "-petscspace_view");CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceSetUp" /*@C PetscSpaceSetUp - Construct data structures for the PetscSpace Collective on PetscSpace Input Parameter: . sp - the PetscSpace object to setup Level: developer .seealso PetscSpaceView(), PetscSpaceDestroy() @*/ PetscErrorCode PetscSpaceSetUp(PetscSpace sp) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1); if (sp->ops->setup) {ierr = (*sp->ops->setup)(sp);CHKERRQ(ierr);} PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceDestroy" /*@ PetscSpaceDestroy - Destroys a PetscSpace object Collective on PetscSpace Input Parameter: . sp - the PetscSpace object to destroy Level: developer .seealso PetscSpaceView() @*/ PetscErrorCode PetscSpaceDestroy(PetscSpace *sp) { PetscErrorCode ierr; PetscFunctionBegin; if (!*sp) PetscFunctionReturn(0); PetscValidHeaderSpecific((*sp), PETSCSPACE_CLASSID, 1); if (--((PetscObject)(*sp))->refct > 0) {*sp = 0; PetscFunctionReturn(0);} ((PetscObject) (*sp))->refct = 0; /* if memory was published with AMS then destroy it */ ierr = PetscObjectAMSViewOff((PetscObject) *sp);CHKERRQ(ierr); ierr = DMDestroy(&(*sp)->dm);CHKERRQ(ierr); ierr = (*(*sp)->ops->destroy)(*sp);CHKERRQ(ierr); ierr = PetscHeaderDestroy(sp);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceCreate" /*@ PetscSpaceCreate - Creates an empty PetscSpace object. The type can then be set with PetscSpaceSetType(). Collective on MPI_Comm Input Parameter: . comm - The communicator for the PetscSpace object Output Parameter: . sp - The PetscSpace object Level: beginner .seealso: PetscSpaceSetType(), PETSCSPACEPOLYNOMIAL @*/ PetscErrorCode PetscSpaceCreate(MPI_Comm comm, PetscSpace *sp) { PetscSpace s; PetscErrorCode ierr; PetscFunctionBegin; PetscValidPointer(sp, 2); *sp = NULL; #if !defined(PETSC_USE_DYNAMIC_LIBRARIES) ierr = PetscFEInitializePackage();CHKERRQ(ierr); #endif ierr = PetscHeaderCreate(s, _p_PetscSpace, struct _PetscSpaceOps, PETSCSPACE_CLASSID, "PetscSpace", "Linear Space", "PetscSpace", comm, PetscSpaceDestroy, PetscSpaceView);CHKERRQ(ierr); ierr = PetscMemzero(s->ops, sizeof(struct _PetscSpaceOps));CHKERRQ(ierr); s->order = 0; ierr = DMShellCreate(comm, &s->dm);CHKERRQ(ierr); *sp = s; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceGetDimension" /* Dimension of the space, i.e. number of basis vectors */ PetscErrorCode PetscSpaceGetDimension(PetscSpace sp, PetscInt *dim) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1); PetscValidPointer(dim, 2); *dim = 0; if (sp->ops->getdimension) {ierr = (*sp->ops->getdimension)(sp, dim);CHKERRQ(ierr);} PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceGetOrder" PetscErrorCode PetscSpaceGetOrder(PetscSpace sp, PetscInt *order) { PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1); PetscValidPointer(order, 2); *order = sp->order; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceSetOrder" PetscErrorCode PetscSpaceSetOrder(PetscSpace sp, PetscInt order) { PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1); sp->order = order; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceEvaluate" PetscErrorCode PetscSpaceEvaluate(PetscSpace sp, PetscInt npoints, const PetscReal points[], PetscReal B[], PetscReal D[], PetscReal H[]) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1); PetscValidPointer(points, 3); if (B) PetscValidPointer(B, 4); if (D) PetscValidPointer(D, 5); if (H) PetscValidPointer(H, 6); if (sp->ops->evaluate) {ierr = (*sp->ops->evaluate)(sp, npoints, points, B, D, H);CHKERRQ(ierr);} PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceSetFromOptions_Polynomial" PetscErrorCode PetscSpaceSetFromOptions_Polynomial(PetscSpace sp) { PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscObjectOptionsBegin((PetscObject) sp);CHKERRQ(ierr); ierr = PetscOptionsInt("-petscspace_num_variables", "The number of different variables, e.g. x and y", "PetscSpacePolynomialSetNumVariables", poly->numVariables, &poly->numVariables, NULL);CHKERRQ(ierr); ierr = PetscOptionsBool("-petscspace_poly_sym", "Use only symmetric polynomials", "PetscSpacePolynomialSetSymmetric", poly->symmetric, &poly->symmetric, NULL);CHKERRQ(ierr); ierr = PetscOptionsEnd();CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpacePolynomialView_Ascii" PetscErrorCode PetscSpacePolynomialView_Ascii(PetscSpace sp, PetscViewer viewer) { PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data; PetscViewerFormat format; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) { ierr = PetscViewerASCIIPrintf(viewer, "Polynomial space in %d variables of order %d", poly->numVariables, sp->order);CHKERRQ(ierr); } else { ierr = PetscViewerASCIIPrintf(viewer, "Polynomial space in %d variables of order %d", poly->numVariables, sp->order);CHKERRQ(ierr); } PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceView_Polynomial" PetscErrorCode PetscSpaceView_Polynomial(PetscSpace sp, PetscViewer viewer) { PetscBool iascii; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1); PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); if (iascii) {ierr = PetscSpacePolynomialView_Ascii(sp, viewer);CHKERRQ(ierr);} PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceSetUp_Polynomial" PetscErrorCode PetscSpaceSetUp_Polynomial(PetscSpace sp) { PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data; PetscInt ndegree = sp->order+1; PetscInt deg; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscMalloc(ndegree * sizeof(PetscInt), &poly->degrees);CHKERRQ(ierr); for (deg = 0; deg < ndegree; ++deg) poly->degrees[deg] = deg; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceDestroy_Polynomial" PetscErrorCode PetscSpaceDestroy_Polynomial(PetscSpace sp) { PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscFree(poly->degrees);CHKERRQ(ierr); ierr = PetscFree(poly);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceGetDimension_Polynomial" PetscErrorCode PetscSpaceGetDimension_Polynomial(PetscSpace sp, PetscInt *dim) { PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data; PetscInt deg = sp->order; PetscInt n = poly->numVariables, i; PetscReal D = 1.0; PetscFunctionBegin; for (i = 1; i <= n; ++i) { D *= ((PetscReal) (deg+i))/i; } *dim = (PetscInt) (D + 0.5); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "LatticePoint_Internal" /* LatticePoint_Internal - Returns all tuples of size 'len' with nonnegative integers that sum up to 'sum'. Input Parameters: + len - The length of the tuple . sum - The sum of all entries in the tuple - ind - The current multi-index of the tuple, initialized to the 0 tuple Output Parameter: + ind - The multi-index of the tuple, -1 indicates the iteration has terminated . tup - A tuple of len integers addig to sum Level: developer .seealso: */ static PetscErrorCode LatticePoint_Internal(PetscInt len, PetscInt sum, PetscInt ind[], PetscInt tup[]) { PetscInt i; PetscErrorCode ierr; PetscFunctionBegin; if (len == 1) { ind[0] = -1; tup[0] = sum; } else if (sum == 0) { for (i = 0; i < len; ++i) {ind[0] = -1; tup[i] = 0;} } else { tup[0] = sum - ind[0]; ierr = LatticePoint_Internal(len-1, ind[0], &ind[1], &tup[1]);CHKERRQ(ierr); if (ind[1] < 0) { if (ind[0] == sum) {ind[0] = -1;} else {ind[1] = 0; ++ind[0];} } } PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceEvaluate_Polynomial" PetscErrorCode PetscSpaceEvaluate_Polynomial(PetscSpace sp, PetscInt npoints, const PetscReal points[], PetscReal B[], PetscReal D[], PetscReal H[]) { PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data; DM dm = sp->dm; PetscInt ndegree = sp->order+1; PetscInt *degrees = poly->degrees; PetscInt dim = poly->numVariables; PetscReal *lpoints, *tmp, *LB, *LD, *LH; PetscInt *ind, *tup; PetscInt pdim, d, der, i, p, deg, o; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscSpaceGetDimension(sp, &pdim);CHKERRQ(ierr); ierr = DMGetWorkArray(dm, npoints, PETSC_REAL, &lpoints);CHKERRQ(ierr); ierr = DMGetWorkArray(dm, npoints*ndegree*3, PETSC_REAL, &tmp);CHKERRQ(ierr); if (B) {ierr = DMGetWorkArray(dm, npoints*dim*ndegree, PETSC_REAL, &LB);CHKERRQ(ierr);} if (D) {ierr = DMGetWorkArray(dm, npoints*dim*ndegree, PETSC_REAL, &LD);CHKERRQ(ierr);} if (H) {ierr = DMGetWorkArray(dm, npoints*dim*ndegree, PETSC_REAL, &LH);CHKERRQ(ierr);} for (d = 0; d < dim; ++d) { for (p = 0; p < npoints; ++p) { lpoints[p] = points[p*dim+d]; } ierr = PetscDTLegendreEval(npoints, lpoints, ndegree, degrees, tmp, &tmp[1*npoints*ndegree], &tmp[2*npoints*ndegree]);CHKERRQ(ierr); /* LB, LD, LH (ndegree * dim x npoints) */ for (deg = 0; deg < ndegree; ++deg) { for (p = 0; p < npoints; ++p) { if (B) LB[(deg*dim + d)*npoints + p] = tmp[(0*npoints + p)*ndegree+deg]; if (D) LD[(deg*dim + d)*npoints + p] = tmp[(1*npoints + p)*ndegree+deg]; if (H) LH[(deg*dim + d)*npoints + p] = tmp[(2*npoints + p)*ndegree+deg]; } } } /* Multiply by A (pdim x ndegree * dim) */ ierr = PetscMalloc2(dim,PetscInt,&ind,dim,PetscInt,&tup);CHKERRQ(ierr); if (B) { /* B (npoints x pdim) */ i = 0; for (o = 0; o <= sp->order; ++o) { ierr = PetscMemzero(ind, dim * sizeof(PetscInt));CHKERRQ(ierr); while (ind[0] >= 0) { ierr = LatticePoint_Internal(dim, o, ind, tup);CHKERRQ(ierr); for (p = 0; p < npoints; ++p) { B[p*pdim + i] = 1.0; for (d = 0; d < dim; ++d) { B[p*pdim + i] *= LB[(tup[d]*dim + d)*npoints + p]; } } ++i; } } } if (D) { /* D (npoints x pdim x dim) */ i = 0; for (o = 0; o <= sp->order; ++o) { ierr = PetscMemzero(ind, dim * sizeof(PetscInt));CHKERRQ(ierr); while (ind[0] >= 0) { ierr = LatticePoint_Internal(dim, o, ind, tup);CHKERRQ(ierr); for (p = 0; p < npoints; ++p) { for (der = 0; der < dim; ++der) { D[(p*pdim + i)*dim + der] = 1.0; for (d = 0; d < dim; ++d) { if (d == der) { D[(p*pdim + i)*dim + der] *= LD[(tup[d]*dim + d)*npoints + p]; } else { D[(p*pdim + i)*dim + der] *= LB[(tup[d]*dim + d)*npoints + p]; } } } } ++i; } } } if (H) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Too lazy to code second derivatives"); ierr = PetscFree2(ind,tup);CHKERRQ(ierr); if (B) {ierr = DMRestoreWorkArray(dm, npoints*dim*ndegree, PETSC_REAL, &LB);CHKERRQ(ierr);} if (D) {ierr = DMRestoreWorkArray(dm, npoints*dim*ndegree, PETSC_REAL, &LD);CHKERRQ(ierr);} if (H) {ierr = DMRestoreWorkArray(dm, npoints*dim*ndegree, PETSC_REAL, &LH);CHKERRQ(ierr);} ierr = DMRestoreWorkArray(dm, npoints*ndegree*3, PETSC_REAL, &tmp);CHKERRQ(ierr); ierr = DMRestoreWorkArray(dm, npoints, PETSC_REAL, &lpoints);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpaceInitialize_Polynomial" PetscErrorCode PetscSpaceInitialize_Polynomial(PetscSpace sp) { PetscFunctionBegin; sp->ops->setfromoptions = PetscSpaceSetFromOptions_Polynomial; sp->ops->setup = PetscSpaceSetUp_Polynomial; sp->ops->view = PetscSpaceView_Polynomial; sp->ops->destroy = PetscSpaceDestroy_Polynomial; sp->ops->getdimension = PetscSpaceGetDimension_Polynomial; sp->ops->evaluate = PetscSpaceEvaluate_Polynomial; PetscFunctionReturn(0); } /*MC PETSCSPACEPOLYNOMIAL = "poly" - A PetscSpace object that encapsulates a polynomial space, e.g. P1 is the space of linear polynomials. Level: intermediate .seealso: PetscSpaceType, PetscSpaceCreate(), PetscSpaceSetType() M*/ #undef __FUNCT__ #define __FUNCT__ "PetscSpaceCreate_Polynomial" PETSC_EXTERN PetscErrorCode PetscSpaceCreate_Polynomial(PetscSpace sp) { PetscSpace_Poly *poly; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1); ierr = PetscNewLog(sp, PetscSpace_Poly, &poly);CHKERRQ(ierr); sp->data = poly; poly->numVariables = 0; poly->symmetric = PETSC_FALSE; poly->degrees = NULL; ierr = PetscSpaceInitialize_Polynomial(sp);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpacePolynomialSetSymmetric" PetscErrorCode PetscSpacePolynomialSetSymmetric(PetscSpace sp, PetscBool sym) { PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1); poly->symmetric = sym; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpacePolynomialGetSymmetric" PetscErrorCode PetscSpacePolynomialGetSymmetric(PetscSpace sp, PetscBool *sym) { PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1); PetscValidPointer(sym, 2); *sym = poly->symmetric; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpacePolynomialSetNumVariables" PetscErrorCode PetscSpacePolynomialSetNumVariables(PetscSpace sp, PetscInt n) { PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1); poly->numVariables = n; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscSpacePolynomialGetNumVariables" PetscErrorCode PetscSpacePolynomialGetNumVariables(PetscSpace sp, PetscInt *n) { PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1); PetscValidPointer(n, 2); *n = poly->numVariables; PetscFunctionReturn(0); } PetscInt PETSCDUALSPACE_CLASSID = 0; PetscFunctionList PetscDualSpaceList = NULL; PetscBool PetscDualSpaceRegisterAllCalled = PETSC_FALSE; #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceRegister" /*@C PetscDualSpaceRegister - Adds a new PetscDualSpace implementation Not Collective Input Parameters: + name - The name of a new user-defined creation routine - create_func - The creation routine itself Notes: PetscDualSpaceRegister() may be called multiple times to add several user-defined PetscDualSpaces Sample usage: .vb PetscDualSpaceRegister("my_space", MyPetscDualSpaceCreate); .ve Then, your PetscDualSpace type can be chosen with the procedural interface via .vb PetscDualSpaceCreate(MPI_Comm, PetscDualSpace *); PetscDualSpaceSetType(PetscDualSpace, "my_dual_space"); .ve or at runtime via the option .vb -petscdualspace_type my_dual_space .ve Level: advanced .keywords: PetscDualSpace, register .seealso: PetscDualSpaceRegisterAll(), PetscDualSpaceRegisterDestroy() @*/ PetscErrorCode PetscDualSpaceRegister(const char sname[], PetscErrorCode (*function)(PetscDualSpace)) { PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscFunctionListAdd(&PetscDualSpaceList, sname, function);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceSetType" /*@C PetscDualSpaceSetType - Builds a particular PetscDualSpace Collective on PetscDualSpace Input Parameters: + sp - The PetscDualSpace object - name - The kind of space Options Database Key: . -petscdualspace_type - Sets the PetscDualSpace type; use -help for a list of available types Level: intermediate .keywords: PetscDualSpace, set, type .seealso: PetscDualSpaceGetType(), PetscDualSpaceCreate() @*/ PetscErrorCode PetscDualSpaceSetType(PetscDualSpace sp, PetscDualSpaceType name) { PetscErrorCode (*r)(PetscDualSpace); PetscBool match; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); ierr = PetscObjectTypeCompare((PetscObject) sp, name, &match);CHKERRQ(ierr); if (match) PetscFunctionReturn(0); if (!PetscDualSpaceRegisterAllCalled) {ierr = PetscDualSpaceRegisterAll();CHKERRQ(ierr);} ierr = PetscFunctionListFind(PetscDualSpaceList, name, &r);CHKERRQ(ierr); if (!r) SETERRQ1(PetscObjectComm((PetscObject) sp), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscDualSpace type: %s", name); if (sp->ops->destroy) { ierr = (*sp->ops->destroy)(sp);CHKERRQ(ierr); sp->ops->destroy = NULL; } ierr = (*r)(sp);CHKERRQ(ierr); ierr = PetscObjectChangeTypeName((PetscObject) sp, name);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceGetType" /*@C PetscDualSpaceGetType - Gets the PetscDualSpace type name (as a string) from the object. Not Collective Input Parameter: . dm - The PetscDualSpace Output Parameter: . name - The PetscDualSpace type name Level: intermediate .keywords: PetscDualSpace, get, type, name .seealso: PetscDualSpaceSetType(), PetscDualSpaceCreate() @*/ PetscErrorCode PetscDualSpaceGetType(PetscDualSpace sp, PetscDualSpaceType *name) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); PetscValidCharPointer(name, 2); if (!PetscDualSpaceRegisterAllCalled) { ierr = PetscDualSpaceRegisterAll();CHKERRQ(ierr); } *name = ((PetscObject) sp)->type_name; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceView" /*@C PetscDualSpaceView - Views a PetscDualSpace Collective on PetscDualSpace Input Parameter: + sp - the PetscDualSpace object to view - v - the viewer Level: developer .seealso PetscDualSpaceDestroy() @*/ PetscErrorCode PetscDualSpaceView(PetscDualSpace sp, PetscViewer v) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); if (!v) { ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) sp), &v);CHKERRQ(ierr); } if (sp->ops->view) { ierr = (*sp->ops->view)(sp, v);CHKERRQ(ierr); } PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceViewFromOptions" /* PetscDualSpaceViewFromOptions - Processes command line options to determine if/how a PetscDualSpace is to be viewed. Collective on PetscDualSpace Input Parameters: + sp - the PetscDualSpace . prefix - prefix to use for viewing, or NULL to use prefix of 'rnd' - optionname - option to activate viewing Level: intermediate .keywords: PetscDualSpace, view, options, database .seealso: VecViewFromOptions(), MatViewFromOptions() */ PetscErrorCode PetscDualSpaceViewFromOptions(PetscDualSpace sp, const char prefix[], const char optionname[]) { PetscViewer viewer; PetscViewerFormat format; PetscBool flg; PetscErrorCode ierr; PetscFunctionBegin; if (prefix) { ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) sp), prefix, optionname, &viewer, &format, &flg);CHKERRQ(ierr); } else { ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) sp), ((PetscObject) sp)->prefix, optionname, &viewer, &format, &flg);CHKERRQ(ierr); } if (flg) { ierr = PetscViewerPushFormat(viewer, format);CHKERRQ(ierr); ierr = PetscDualSpaceView(sp, viewer);CHKERRQ(ierr); ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); } PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceSetFromOptions" /*@ PetscDualSpaceSetFromOptions - sets parameters in a PetscDualSpace from the options database Collective on PetscDualSpace Input Parameter: . sp - the PetscDualSpace object to set options for Options Database: . -petscspace_order the approximation order of the space Level: developer .seealso PetscDualSpaceView() @*/ PetscErrorCode PetscDualSpaceSetFromOptions(PetscDualSpace sp) { const char *defaultType; char typename[256]; PetscBool flg; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); if (!((PetscObject) sp)->type_name) { defaultType = PETSCDUALSPACELAGRANGE; } else { defaultType = ((PetscObject) sp)->type_name; } if (!PetscSpaceRegisterAllCalled) {ierr = PetscSpaceRegisterAll();CHKERRQ(ierr);} ierr = PetscObjectOptionsBegin((PetscObject) sp);CHKERRQ(ierr); ierr = PetscOptionsList("-petscdualspace_type", "Dual space", "PetscDualSpaceSetType", PetscDualSpaceList, defaultType, typename, 256, &flg);CHKERRQ(ierr); if (flg) { ierr = PetscDualSpaceSetType(sp, typename);CHKERRQ(ierr); } else if (!((PetscObject) sp)->type_name) { ierr = PetscDualSpaceSetType(sp, defaultType);CHKERRQ(ierr); } ierr = PetscOptionsInt("-petscdualspace_order", "The approximation order", "PetscDualSpaceSetOrder", sp->order, &sp->order, NULL);CHKERRQ(ierr); if (sp->ops->setfromoptions) { ierr = (*sp->ops->setfromoptions)(sp);CHKERRQ(ierr); } /* process any options handlers added with PetscObjectAddOptionsHandler() */ ierr = PetscObjectProcessOptionsHandlers((PetscObject) sp);CHKERRQ(ierr); ierr = PetscOptionsEnd();CHKERRQ(ierr); ierr = PetscDualSpaceViewFromOptions(sp, NULL, "-petscdualspace_view");CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceSetUp" /*@C PetscDualSpaceSetUp - Construct a basis for the PetscDualSpace Collective on PetscDualSpace Input Parameter: . sp - the PetscDualSpace object to setup Level: developer .seealso PetscDualSpaceView(), PetscDualSpaceDestroy() @*/ PetscErrorCode PetscDualSpaceSetUp(PetscDualSpace sp) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); if (sp->ops->setup) {ierr = (*sp->ops->setup)(sp);CHKERRQ(ierr);} PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceDestroy" /*@ PetscDualSpaceDestroy - Destroys a PetscDualSpace object Collective on PetscDualSpace Input Parameter: . sp - the PetscDualSpace object to destroy Level: developer .seealso PetscDualSpaceView() @*/ PetscErrorCode PetscDualSpaceDestroy(PetscDualSpace *sp) { PetscInt dim, f; PetscErrorCode ierr; PetscFunctionBegin; if (!*sp) PetscFunctionReturn(0); PetscValidHeaderSpecific((*sp), PETSCDUALSPACE_CLASSID, 1); if (--((PetscObject)(*sp))->refct > 0) {*sp = 0; PetscFunctionReturn(0);} ((PetscObject) (*sp))->refct = 0; /* if memory was published with AMS then destroy it */ ierr = PetscObjectAMSViewOff((PetscObject) *sp);CHKERRQ(ierr); ierr = PetscDualSpaceGetDimension(*sp, &dim);CHKERRQ(ierr); for (f = 0; f < dim; ++f) { ierr = PetscQuadratureDestroy(&(*sp)->functional[f]);CHKERRQ(ierr); } ierr = PetscFree((*sp)->functional);CHKERRQ(ierr); ierr = DMDestroy(&(*sp)->dm);CHKERRQ(ierr); if ((*sp)->ops->destroy) {ierr = (*(*sp)->ops->destroy)(*sp);CHKERRQ(ierr);} ierr = PetscHeaderDestroy(sp);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceCreate" /*@ PetscDualSpaceCreate - Creates an empty PetscDualSpace object. The type can then be set with PetscDualSpaceSetType(). Collective on MPI_Comm Input Parameter: . comm - The communicator for the PetscDualSpace object Output Parameter: . sp - The PetscDualSpace object Level: beginner .seealso: PetscDualSpaceSetType(), PETSCDUALSPACELAGRANGE @*/ PetscErrorCode PetscDualSpaceCreate(MPI_Comm comm, PetscDualSpace *sp) { PetscDualSpace s; PetscErrorCode ierr; PetscFunctionBegin; PetscValidPointer(sp, 2); *sp = NULL; #if !defined(PETSC_USE_DYNAMIC_LIBRARIES) ierr = PetscFEInitializePackage();CHKERRQ(ierr); #endif ierr = PetscHeaderCreate(s, _p_PetscDualSpace, struct _PetscDualSpaceOps, PETSCDUALSPACE_CLASSID, "PetscDualSpace", "Dual Space", "PetscDualSpace", comm, PetscDualSpaceDestroy, PetscDualSpaceView);CHKERRQ(ierr); ierr = PetscMemzero(s->ops, sizeof(struct _PetscDualSpaceOps));CHKERRQ(ierr); s->order = 0; *sp = s; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceGetDM" PetscErrorCode PetscDualSpaceGetDM(PetscDualSpace sp, DM *dm) { PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); PetscValidPointer(dm, 2); *dm = sp->dm; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceSetDM" PetscErrorCode PetscDualSpaceSetDM(PetscDualSpace sp, DM dm) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); PetscValidHeaderSpecific(dm, DM_CLASSID, 2); ierr = DMDestroy(&sp->dm);CHKERRQ(ierr); ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); sp->dm = dm; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceGetOrder" PetscErrorCode PetscDualSpaceGetOrder(PetscDualSpace sp, PetscInt *order) { PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); PetscValidPointer(order, 2); *order = sp->order; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceSetOrder" PetscErrorCode PetscDualSpaceSetOrder(PetscDualSpace sp, PetscInt order) { PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); sp->order = order; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceGetFunctional" PetscErrorCode PetscDualSpaceGetFunctional(PetscDualSpace sp, PetscInt i, PetscQuadrature *functional) { PetscInt dim; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); PetscValidPointer(functional, 3); ierr = PetscDualSpaceGetDimension(sp, &dim);CHKERRQ(ierr); if ((i < 0) || (i >= dim)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Functional index %d must be in [0, %d)", i, dim); *functional = sp->functional[i]; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceGetDimension" /* Dimension of the space, i.e. number of basis vectors */ PetscErrorCode PetscDualSpaceGetDimension(PetscDualSpace sp, PetscInt *dim) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); PetscValidPointer(dim, 2); *dim = 0; if (sp->ops->getdimension) {ierr = (*sp->ops->getdimension)(sp, dim);CHKERRQ(ierr);} PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceSetUp_Lagrange" PetscErrorCode PetscDualSpaceSetUp_Lagrange(PetscDualSpace sp) { DM dm = sp->dm; PetscInt order = sp->order; PetscSection csection; Vec coordinates; PetscReal *qpoints, *qweights; PetscInt depth, dim, pdim, *pStart, *pEnd, coneSize, d, n, f = 0; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscDualSpaceGetDimension(sp, &pdim);CHKERRQ(ierr); ierr = PetscMalloc(pdim * sizeof(PetscQuadrature), &sp->functional);CHKERRQ(ierr); /* Classify element type */ ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); ierr = PetscMalloc2(depth+1,PetscInt,&pStart,depth+1,PetscInt,&pEnd);CHKERRQ(ierr); for (d = 0; d < depth; ++d) { ierr = DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d]);CHKERRQ(ierr); } ierr = DMPlexGetConeSize(dm, pStart[depth], &coneSize);CHKERRQ(ierr); ierr = DMPlexGetCoordinateSection(dm, &csection);CHKERRQ(ierr); ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); if (coneSize == dim+1) { PetscInt *closure = NULL, closureSize, c; /* Simplex */ ierr = DMPlexGetTransitiveClosure(dm, pStart[depth], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); for (c = 0; c < closureSize*2; c += 2) { const PetscInt p = closure[c]; if ((p >= pStart[0]) && (p < pEnd[0])) { /* Vertices */ const PetscScalar *coords; PetscInt dof, off, d; if (order < 1) continue; sp->functional[f].numQuadPoints = 1; ierr = PetscMalloc(sp->functional[f].numQuadPoints*dim * sizeof(PetscReal), &qpoints);CHKERRQ(ierr); ierr = PetscMalloc(sp->functional[f].numQuadPoints * sizeof(PetscReal), &qweights);CHKERRQ(ierr); ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr); ierr = PetscSectionGetDof(csection, p, &dof);CHKERRQ(ierr); ierr = PetscSectionGetOffset(csection, p, &off);CHKERRQ(ierr); if (dof != dim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of coordinates %d does not match spatial dimension %d", dof, dim); for (d = 0; d < dof; ++d) {qpoints[d] = coords[off+d];} qweights[0] = 1.0; sp->functional[f].quadPoints = qpoints; sp->functional[f].quadWeights = qweights; ++f; ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr); } else if ((p >= pStart[1]) && (p < pEnd[1])) { /* Edges */ PetscScalar *coords; PetscInt k; if (order < 2) continue; coords = NULL; ierr = DMPlexVecGetClosure(dm, csection, coordinates, p, &n, &coords);CHKERRQ(ierr); if (n != dim*2) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %d has %d coordinate values instead of %d", p, n, dim*2); for (k = 1; k < order; ++k) { sp->functional[f].numQuadPoints = 1; ierr = PetscMalloc(sp->functional[f].numQuadPoints*dim * sizeof(PetscReal), &qpoints);CHKERRQ(ierr); ierr = PetscMalloc(sp->functional[f].numQuadPoints * sizeof(PetscReal), &qweights);CHKERRQ(ierr); for (d = 0; d < dim; ++d) {qpoints[d] = k*(coords[1*dim+d] - coords[0*dim+d])/order + coords[0*dim+d];} qweights[0] = 1.0; sp->functional[f].quadPoints = qpoints; sp->functional[f].quadWeights = qweights; ++f; } ierr = DMPlexVecRestoreClosure(dm, csection, coordinates, p, &n, &coords);CHKERRQ(ierr); } else if ((p >= pStart[depth-1]) && (p < pEnd[depth-1])) { /* Faces */ if (order < 3) continue; SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Too lazy to implement faces"); } else if ((p >= pStart[depth]) && (p < pEnd[depth])) { /* Cells */ if ((order > 0) && (order < 3)) continue; SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Too lazy to implement cells"); } } ierr = DMPlexRestoreTransitiveClosure(dm, pStart[depth], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot handle cells with cone size %d", coneSize); ierr = PetscFree2(pStart,pEnd);CHKERRQ(ierr); if (f != pdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of dual basis vector %d not equal to dimension %d", f, pdim); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceDestroy_Lagrange" PetscErrorCode PetscDualSpaceDestroy_Lagrange(PetscDualSpace sp) { PetscDualSpace_Lag *lag = (PetscDualSpace_Lag *) sp->data; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscFree(lag);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceGetDimension_Lagrange" PetscErrorCode PetscDualSpaceGetDimension_Lagrange(PetscDualSpace sp, PetscInt *dim) { PetscInt deg = sp->order; PetscReal D = 1.0; PetscInt n, i; PetscErrorCode ierr; PetscFunctionBegin; /* TODO: Assumes simplices */ ierr = DMPlexGetDimension(sp->dm, &n);CHKERRQ(ierr); for (i = 1; i <= n; ++i) { D *= ((PetscReal) (deg+i))/i; } *dim = (PetscInt) (D + 0.5); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceInitialize_Lagrange" PetscErrorCode PetscDualSpaceInitialize_Lagrange(PetscDualSpace sp) { PetscFunctionBegin; sp->ops->setfromoptions = NULL; sp->ops->setup = PetscDualSpaceSetUp_Lagrange; sp->ops->view = NULL; sp->ops->destroy = PetscDualSpaceDestroy_Lagrange; sp->ops->getdimension = PetscDualSpaceGetDimension_Lagrange; PetscFunctionReturn(0); } /*MC PETSCDUALSPACELAGRANGE = "lagrange" - A PetscDualSpace object that encapsulates a dual space of pointwise evaluation functionals Level: intermediate .seealso: PetscDualSpaceType, PetscDualSpaceCreate(), PetscDualSpaceSetType() M*/ #undef __FUNCT__ #define __FUNCT__ "PetscDualSpaceCreate_Lagrange" PETSC_EXTERN PetscErrorCode PetscDualSpaceCreate_Lagrange(PetscDualSpace sp) { PetscDualSpace_Lag *lag; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1); ierr = PetscNewLog(sp, PetscDualSpace_Lag, &lag);CHKERRQ(ierr); sp->data = lag; /* lag->n = 0; */ ierr = PetscDualSpaceInitialize_Lagrange(sp);CHKERRQ(ierr); PetscFunctionReturn(0); } PetscInt PETSCFE_CLASSID = 0; #undef __FUNCT__ #define __FUNCT__ "PetscFEView" /*@C PetscFEView - Views a PetscFE Collective on PetscFE Input Parameter: + sp - the PetscFE object to view - v - the viewer Level: developer .seealso PetscFEDestroy() @*/ PetscErrorCode PetscFEView(PetscFE fem, PetscViewer v) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1); if (!v) { ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) fem), &v);CHKERRQ(ierr); } if (fem->ops->view) { ierr = (*fem->ops->view)(fem, v);CHKERRQ(ierr); } PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscFEDestroy" /*@ PetscFEDestroy - Destroys a PetscFE object Collective on PetscFE Input Parameter: . fem - the PetscFE object to destroy Level: developer .seealso PetscFEView() @*/ PetscErrorCode PetscFEDestroy(PetscFE *fem) { PetscErrorCode ierr; PetscFunctionBegin; if (!*fem) PetscFunctionReturn(0); PetscValidHeaderSpecific((*fem), PETSCFE_CLASSID, 1); if (--((PetscObject)(*fem))->refct > 0) {*fem = 0; PetscFunctionReturn(0);} ((PetscObject) (*fem))->refct = 0; /* if memory was published with AMS then destroy it */ ierr = PetscObjectAMSViewOff((PetscObject) *fem);CHKERRQ(ierr); ierr = PetscSpaceDestroy(&(*fem)->basisSpace);CHKERRQ(ierr); ierr = PetscDualSpaceDestroy(&(*fem)->dualSpace);CHKERRQ(ierr); ierr = PetscQuadratureDestroy(&(*fem)->quadrature);CHKERRQ(ierr); if ((*fem)->ops->destroy) {ierr = (*(*fem)->ops->destroy)(*fem);CHKERRQ(ierr);} ierr = PetscHeaderDestroy(fem);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscFECreate" /*@ PetscFECreate - Creates an empty PetscFE object. The type can then be set with PetscFESetType(). Collective on MPI_Comm Input Parameter: . comm - The communicator for the PetscFE object Output Parameter: . fem - The PetscFE object Level: beginner .seealso: PetscFESetType(), PETSCFEGALERKIN @*/ PetscErrorCode PetscFECreate(MPI_Comm comm, PetscFE *fem) { PetscFE f; PetscErrorCode ierr; PetscFunctionBegin; PetscValidPointer(fem, 2); *fem = NULL; #if !defined(PETSC_USE_DYNAMIC_LIBRARIES) ierr = PetscFEInitializePackage();CHKERRQ(ierr); #endif ierr = PetscHeaderCreate(f, _p_PetscFE, struct _PetscFEOps, PETSCFE_CLASSID, "PetscFE", "Finite Element", "PetscFE", comm, PetscFEDestroy, PetscFEView);CHKERRQ(ierr); ierr = PetscMemzero(f->ops, sizeof(struct _PetscFEOps));CHKERRQ(ierr); f->basisSpace = NULL; f->dualSpace = NULL; f->numComponents = 1; ierr = PetscMemzero(&f->quadrature, sizeof(PetscQuadrature));CHKERRQ(ierr); *fem = f; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscFEGetDimension" PetscErrorCode PetscFEGetDimension(PetscFE fem, PetscInt *dim) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1); PetscValidPointer(dim, 2); ierr = PetscSpaceGetDimension(fem->basisSpace, dim);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscFESetNumComponents" PetscErrorCode PetscFESetNumComponents(PetscFE fem, PetscInt comp) { PetscFunctionBegin; PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1); fem->numComponents = comp; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscFEGetNumComponents" PetscErrorCode PetscFEGetNumComponents(PetscFE fem, PetscInt *comp) { PetscFunctionBegin; PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1); PetscValidPointer(comp, 2); *comp = fem->numComponents; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscFEGetBasisSpace" PetscErrorCode PetscFEGetBasisSpace(PetscFE fem, PetscSpace *sp) { PetscFunctionBegin; PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1); PetscValidPointer(sp, 2); *sp = fem->basisSpace; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscFESetBasisSpace" PetscErrorCode PetscFESetBasisSpace(PetscFE fem, PetscSpace sp) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1); PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 2); ierr = PetscSpaceDestroy(&fem->basisSpace);CHKERRQ(ierr); fem->basisSpace = sp; ierr = PetscObjectReference((PetscObject) fem->basisSpace);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscFEGetDualSpace" PetscErrorCode PetscFEGetDualSpace(PetscFE fem, PetscDualSpace *sp) { PetscFunctionBegin; PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1); PetscValidPointer(sp, 2); *sp = fem->dualSpace; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscFESetDualSpace" PetscErrorCode PetscFESetDualSpace(PetscFE fem, PetscDualSpace sp) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1); PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 2); ierr = PetscDualSpaceDestroy(&fem->dualSpace);CHKERRQ(ierr); fem->dualSpace = sp; ierr = PetscObjectReference((PetscObject) fem->dualSpace);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscFEGetQuadrature" PetscErrorCode PetscFEGetQuadrature(PetscFE fem, PetscQuadrature *q) { PetscFunctionBegin; PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1); PetscValidPointer(q, 2); *q = fem->quadrature; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscFESetQuadrature" PetscErrorCode PetscFESetQuadrature(PetscFE fem, PetscQuadrature q) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1); ierr = PetscQuadratureDestroy(&fem->quadrature);CHKERRQ(ierr); fem->quadrature = q; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscFEGetTabulation" PetscErrorCode PetscFEGetTabulation(PetscFE fem, PetscReal **B, PetscReal **D, PetscReal **H) { DM dm; PetscInt pdim; /* Dimension of FE space P */ PetscInt dim; /* Spatial dimension */ PetscInt comp; /* Field components */ PetscInt npoints = fem->quadrature.numQuadPoints; const PetscReal *points = fem->quadrature.quadPoints; PetscReal *tmpB, *tmpD, *invV; PetscInt p, d, j, k; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1); PetscValidPointer(points, 3); if (B) PetscValidPointer(B, 4); if (D) PetscValidPointer(D, 5); if (H) PetscValidPointer(H, 6); ierr = PetscDualSpaceGetDM(fem->dualSpace, &dm);CHKERRQ(ierr); ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr); ierr = PetscSpaceGetDimension(fem->basisSpace, &pdim);CHKERRQ(ierr); ierr = PetscFEGetNumComponents(fem, &comp);CHKERRQ(ierr); /* if (nvalues%dim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of coordinate values %d must be divisible by the spatial dimension %d", nvalues, dim); */ if (B) { ierr = DMGetWorkArray(dm, npoints*pdim*comp, PETSC_REAL, B);CHKERRQ(ierr); ierr = DMGetWorkArray(dm, npoints*pdim, PETSC_REAL, &tmpB);CHKERRQ(ierr); } if (D) { ierr = DMGetWorkArray(dm, npoints*pdim*comp*dim, PETSC_REAL, D);CHKERRQ(ierr); ierr = DMGetWorkArray(dm, npoints*pdim*dim, PETSC_REAL, &tmpD);CHKERRQ(ierr); } if (H) {ierr = DMGetWorkArray(dm, npoints*pdim*dim*dim, PETSC_REAL, H);CHKERRQ(ierr);} ierr = PetscSpaceEvaluate(fem->basisSpace, npoints, points, B ? tmpB : NULL, D ? tmpD : NULL, H ? *H : NULL);CHKERRQ(ierr); ierr = DMGetWorkArray(dm, pdim*pdim, PETSC_REAL, &invV);CHKERRQ(ierr); for (j = 0; j < pdim; ++j) { PetscReal *Bf; PetscQuadrature f; PetscInt q; ierr = PetscDualSpaceGetFunctional(fem->dualSpace, j, &f); ierr = DMGetWorkArray(dm, f.numQuadPoints*pdim, PETSC_REAL, &Bf);CHKERRQ(ierr); ierr = PetscSpaceEvaluate(fem->basisSpace, f.numQuadPoints, f.quadPoints, Bf, NULL, NULL);CHKERRQ(ierr); for (k = 0; k < pdim; ++k) { /* n_j \cdot \phi_k */ invV[j*pdim+k] = 0.0; for (q = 0; q < f.numQuadPoints; ++q) { invV[j*pdim+k] += Bf[q*pdim+k]*f.quadWeights[q]; } } ierr = DMRestoreWorkArray(dm, f.numQuadPoints*pdim, PETSC_REAL, &Bf);CHKERRQ(ierr); } { PetscReal *work; PetscBLASInt *pivots; PetscBLASInt n = pdim, info; ierr = DMGetWorkArray(dm, pdim, PETSC_INT, &pivots);CHKERRQ(ierr); ierr = DMGetWorkArray(dm, pdim, PETSC_REAL, &work);CHKERRQ(ierr); PetscStackCallBLAS("LAPACKgetrf", LAPACKgetrf_(&n, &n, invV, &n, pivots, &info)); PetscStackCallBLAS("LAPACKgetri", LAPACKgetri_(&n, invV, &n, pivots, work, &n, &info)); ierr = DMRestoreWorkArray(dm, pdim, PETSC_INT, &pivots);CHKERRQ(ierr); ierr = DMRestoreWorkArray(dm, pdim, PETSC_REAL, &work);CHKERRQ(ierr); } for (p = 0; p < npoints; ++p) { if (B) { /* Multiply by V^{-1} (pdim x pdim) */ for (j = 0; j < pdim; ++j) { const PetscInt i = (p*pdim + j)*comp; PetscInt c; (*B)[i] = 0.0; for (k = 0; k < pdim; ++k) { (*B)[i] += invV[k*pdim+j] * tmpB[p*pdim + k]; } for (c = 1; c < comp; ++c) { (*B)[i+c] = (*B)[i]; } } } if (D) { /* Multiply by V^{-1} (pdim x pdim) */ for (j = 0; j < pdim; ++j) { for (d = 0; d < dim; ++d) { const PetscInt i = ((p*pdim + j)*comp + 0)*dim + d; PetscInt c; (*D)[i] = 0.0; for (k = 0; k < pdim; ++k) { (*D)[i] += invV[k*pdim+j] * tmpD[(p*pdim + k)*dim + d]; } for (c = 1; c < comp; ++c) { (*D)[((p*pdim + j)*comp + c)*dim + d] = (*D)[i]; } } } } } ierr = DMRestoreWorkArray(dm, pdim*pdim, PETSC_REAL, &invV);CHKERRQ(ierr); if (B) {ierr = DMRestoreWorkArray(dm, npoints*pdim, PETSC_REAL, &tmpB);CHKERRQ(ierr);} if (D) {ierr = DMRestoreWorkArray(dm, npoints*pdim*dim, PETSC_REAL, &tmpD);CHKERRQ(ierr);} PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscFERestoreTabulation" PetscErrorCode PetscFERestoreTabulation(PetscFE fem, PetscReal **B, PetscReal **D, PetscReal **H) { DM dm; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1); ierr = PetscDualSpaceGetDM(fem->dualSpace, &dm);CHKERRQ(ierr); if (B) {ierr = DMRestoreWorkArray(dm, 0, PETSC_REAL, B);CHKERRQ(ierr);} if (D) {ierr = DMRestoreWorkArray(dm, 0, PETSC_REAL, D);CHKERRQ(ierr);} if (H) {ierr = DMRestoreWorkArray(dm, 0, PETSC_REAL, H);CHKERRQ(ierr);} PetscFunctionReturn(0); }