Actual source code: iga.c
1: #include <private/igaimpl.h> /*I "petscdmiga.h" I*/
5: PetscErrorCode DMDestroy_IGA(DM dm)
6: {
7: DM_IGA *iga = (DM_IGA *) dm->data;
11: PetscFree(iga->Ux);
12: PetscFree(iga->Uy);
13: PetscFree(iga->Uz);
14: BDDestroy(&iga->bdX);
15: BDDestroy(&iga->bdY);
16: BDDestroy(&iga->bdZ);
17: DMDestroy(&iga->da_dof);
18: DMDestroy(&iga->da_geometry);
19: return(0);
20: }
24: PetscErrorCode DMView_IGA(DM dm, PetscViewer viewer)
25: {
26: DM_IGA *iga = (DM_IGA *) dm->data;
27: PetscBool iascii;
31: PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);
33: if (iascii){
34: PetscViewerASCIIPrintf(viewer, "IGA:\n");
35: PetscViewerASCIIPrintf(viewer, " number of elements: %d %d %d\n", iga->Nx, iga->Ny, iga->Nz);
36: PetscViewerASCIIPrintf(viewer, " polynomial order: %d %d %d\n", iga->px, iga->py, iga->pz);
37: PetscViewerASCIIPrintf(viewer, " Data DM:\n");
38: DMView(iga->da_dof, viewer);
39: PetscViewerASCIIPrintf(viewer, " Geometry DM:\n");
40: DMView(iga->da_geometry, viewer);
41: } else {
42: SETERRQ1(((PetscObject)viewer)->comm,PETSC_ERR_SUP,"Viewer type %s not supported by this mesh object", ((PetscObject)viewer)->type_name);
43: }
44: return(0);
45: }
49: PetscErrorCode DMCreateGlobalVector_IGA(DM dm, Vec *gvec)
50: {
51: DM_IGA *iga = (DM_IGA *) dm->data;
55: DMCreateGlobalVector(iga->da_dof, gvec);
56: PetscObjectCompose((PetscObject)*gvec,"DM",(PetscObject)dm);
57: return(0);
58: }
62: PetscErrorCode DMCreateLocalVector_IGA(DM dm, Vec *lvec)
63: {
64: DM_IGA *iga = (DM_IGA *) dm->data;
68: DMCreateLocalVector(iga->da_dof, lvec);
69: PetscObjectCompose((PetscObject)*lvec,"DM",(PetscObject)dm);
70: return(0);
71: }
75: PetscErrorCode DMGetMatrix_IGA(DM dm, const MatType mtype, Mat *J)
76: {
77: DM_IGA *iga = (DM_IGA *) dm->data;
81: DMGetMatrix(iga->da_dof, mtype, J);
82: PetscObjectCompose((PetscObject)*J,"DM",(PetscObject)dm);
83: return(0);
84: }
88: PetscErrorCode DMGlobalToLocalBegin_IGA(DM dm, Vec gv, InsertMode mode, Vec lv)
89: {
90: DM_IGA *iga = (DM_IGA *) dm->data;
94: DMGlobalToLocalBegin(iga->da_dof, gv, mode, lv);
95: return(0);
96: }
100: PetscErrorCode DMGlobalToLocalEnd_IGA(DM dm, Vec gv, InsertMode mode, Vec lv)
101: {
102: DM_IGA *iga = (DM_IGA *) dm->data;
106: DMGlobalToLocalEnd(iga->da_dof, gv, mode, lv);
107: return(0);
108: }
112: PetscErrorCode DMLocalToGlobalBegin_IGA(DM dm, Vec lv, InsertMode mode, Vec gv)
113: {
114: DM_IGA *iga = (DM_IGA *) dm->data;
118: DMLocalToGlobalBegin(iga->da_dof, lv, mode, gv);
119: return(0);
120: }
124: PetscErrorCode DMLocalToGlobalEnd_IGA(DM dm, Vec lv, InsertMode mode, Vec gv)
125: {
126: DM_IGA *iga = (DM_IGA *) dm->data;
130: DMLocalToGlobalEnd(iga->da_dof, lv, mode, gv);
131: return(0);
132: }
136: /*@C
137: DMIGAGetPolynomialOrder - Gets the polynomial order for each direction
139: Not Collective
141: Input Parameter:
142: . dm - the IGA
144: Output Parameters:
145: + px - polynomial order in X
146: . py - polynomial order in Y
147: - pz - polynomial order in Z
149: Level: beginner
151: .keywords: distributed array, get, information
152: .seealso: DMCreate()
153: @*/
154: PetscErrorCode DMIGAGetPolynomialOrder(DM dm, PetscInt *px, PetscInt *py, PetscInt *pz)
155: {
156: DM_IGA *iga = (DM_IGA *) dm->data;
160: if (px) {
162: *px = iga->px;
163: }
164: if (py) {
166: *py = iga->py;
167: }
168: if (pz) {
170: *pz = iga->pz;
171: }
172: return(0);
173: }
177: /*@C
178: DMIGAGetNumQuadraturePoints - Gets the number of quadrature points for each direction
180: Not Collective
182: Input Parameter:
183: . dm - the IGA
185: Output Parameters:
186: + nx - number of quadrature points in X
187: . ny - number of quadrature points in Y
188: - nz - number of quadrature points in Z
190: Level: beginner
192: .keywords: distributed array, get, information
193: .seealso: DMCreate()
194: @*/
195: PetscErrorCode DMIGAGetNumQuadraturePoints(DM dm, PetscInt *nx, PetscInt *ny, PetscInt *nz)
196: {
197: DM_IGA *iga = (DM_IGA *) dm->data;
201: if (nx) {
203: *nx = iga->ngx;
204: }
205: if (ny) {
207: *ny = iga->ngy;
208: }
209: if (nz) {
211: *nz = iga->ngz;
212: }
213: return(0);
214: }
218: /*@C
219: DMIGAGetBasisData - Gets the basis data at quadrature points for each direction
221: Not Collective
223: Input Parameter:
224: . dm - the IGA
226: Output Parameters:
227: + bdX - basis data in X
228: . bdY - basis data in Y
229: - bdZ - basis data in Z
231: Level: beginner
233: .keywords: distributed array, get, information
234: .seealso: DMCreate()
235: @*/
236: PetscErrorCode DMIGAGetBasisData(DM dm, BD *bdX, BD *bdY, BD *bdZ)
237: {
238: DM_IGA *iga = (DM_IGA *) dm->data;
242: if (bdX) {
244: *bdX = iga->bdX;
245: }
246: if (bdY) {
248: *bdY = iga->bdY;
249: }
250: if (bdZ) {
252: *bdZ = iga->bdZ;
253: }
254: return(0);
255: }
259: /*@C
260: DMIGASetFieldName - Sets the names of individual field components in multicomponent vectors associated with a IGA.
262: Not Collective
264: Input Parameters:
265: + dm - the IGA
266: . nf - field number for the IGA (0, 1, ... dof-1), where dof indicates the number of degrees of freedom per node within the IGA
267: - names - the name of the field (component)
269: Level: intermediate
271: .keywords: distributed array, get, component name
272: .seealso: DMIGAGetFieldName()
273: @*/
274: PetscErrorCode DMIGASetFieldName(DM dm, PetscInt nf, const char name[])
275: {
276: DM_IGA *iga = (DM_IGA *) dm->data;
281: DMDASetFieldName(iga->da_dof, nf, name);
282: return(0);
283: }
287: /*@C
288: DMIGAGetFieldName - Gets the names of individual field components in multicomponent vectors associated with a IGA.
290: Not Collective
292: Input Parameters:
293: + dm - the IGA
294: - nf - field number for the IGA (0, 1, ... dof-1), where dof indicates the number of degrees of freedom per node within the IGA
296: Output Parameter:
297: . names - the name of the field (component)
299: Level: intermediate
301: .keywords: distributed array, get, component name
302: .seealso: DMIGASetFieldName()
303: @*/
304: PetscErrorCode DMIGAGetFieldName(DM dm, PetscInt nf, const char **name)
305: {
306: DM_IGA *iga = (DM_IGA *) dm->data;
312: DMDAGetFieldName(iga->da_dof, nf, name);
313: return(0);
314: }
318: /*@C
319: DMIGAVecGetArray - Returns a multiple dimension array that shares data with the underlying vector and is indexed using the global dimensions.
321: Not Collective
323: Input Parameters:
324: + dm - the IGA
325: - vec - the vector, either a vector the same size as one obtained with DMCreateGlobalVector() or DMCreateLocalVector()
327: Output Parameter:
328: . array - the array
330: Notes:
331: Call DMIGAVecRestoreArray() once you have finished accessing the vector entries.
333: In C, the indexing is "backwards" from what expects: array[k][j][i] NOT array[i][j][k]!
335: If vec is a local vector (obtained with DMCreateLocalVector() etc) then they ghost point locations are accessable. If it is
336: a global vector then the ghost points are not accessable. Of course with the local vector you will have had to do the
337: appropriate DMLocalToGlobalBegin() and DMLocalToGlobalEnd() to have correct values in the ghost locations.
339: Level: intermediate
341: .keywords: distributed array, get, corners, nodes, local indices, coordinates
342: .seealso: DMIGAVecRestoreArray(), VecGetArray(), VecRestoreArray(), DMDAVecRestoreArray(), DMDAVecGetArray()
343: @*/
344: PetscErrorCode DMIGAVecGetArray(DM dm, Vec vec, void *array)
345: {
346: DM_IGA *iga = (DM_IGA *) dm->data;
353: DMDAVecGetArray(iga->da_dof, vec, array);
354: return(0);
355: }
359: /*@
360: DMIGAVecRestoreArray - Restores a multiple dimension array obtained with DMIGAVecGetArray()
362: Not Collective
364: Input Parameters:
365: + dm - the IGA
366: . vec - the vector, either a vector the same size as one obtained with DMCreateGlobalVector() or DMCreateLocalVector()
367: - array - the array
369: Level: intermediate
371: .keywords: distributed array, get, corners, nodes, local indices, coordinates
372: .seealso: DMIGAVecGetArray(), VecGetArray(), VecRestoreArray(), DMDAVecRestoreArray(), DMDAVecGetArray()
373: @*/
374: PetscErrorCode DMIGAVecRestoreArray(DM dm, Vec vec, void *array)
375: {
376: DM_IGA *iga = (DM_IGA *) dm->data;
383: DMDAVecRestoreArray(iga->da_dof, vec, array);
384: return(0);
385: }
389: /*@C
390: DMIGAGetLocalInfo - Gets information about a given IGA and this processors location in it
392: Not Collective
394: Input Parameter:
395: . dm - the IGA
397: Output Parameter:
398: . dainfo - structure containing the information
400: Level: beginner
402: .keywords: distributed array, get, information
403: .seealso: DMDAGetLocalInfo()
404: @*/
405: PetscErrorCode DMIGAGetLocalInfo(DM dm, DMDALocalInfo *info)
406: {
407: DM_IGA *iga = (DM_IGA *) dm->data;
413: DMDAGetLocalInfo(iga->da_dof, info);
414: return(0);
415: }
420: PetscErrorCode DMIGAInitializeUniform3d(DM dm,PetscBool IsRational,PetscInt NumDerivatives,PetscInt ndof,
421: PetscInt px,PetscInt Nx,PetscInt Cx,PetscReal Ux0, PetscReal Uxf,PetscBool IsPeriodicX,PetscInt ngx,
422: PetscInt py,PetscInt Ny,PetscInt Cy,PetscReal Uy0, PetscReal Uyf,PetscBool IsPeriodicY,PetscInt ngy,
423: PetscInt pz,PetscInt Nz,PetscInt Cz,PetscReal Uz0, PetscReal Uzf,PetscBool IsPeriodicZ,PetscInt ngz)
424: {
425: DM_IGA *iga = (DM_IGA *) dm->data;
427: DMDABoundaryType xptype = DMDA_BOUNDARY_NONE;
428: DMDABoundaryType yptype = DMDA_BOUNDARY_NONE;
429: DMDABoundaryType zptype = DMDA_BOUNDARY_NONE;
430: PetscInt sw;
431: DMDALocalInfo info_dof;
434: /* Test C < p */
435: if(px <= Cx || py <= Cy || pz <= Cz){
436: SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Discretization inconsistent: polynomial order must be greater than degree of continuity");
437: }
439: /* Load constants */
440: iga->px = px; iga->py = py; iga->pz = pz;
441: iga->Nx = Nx; iga->Ny = Nx; iga->Nz = Nz;
442: iga->Cx = Cx; iga->Cy = Cx; iga->Cz = Cx;
443: iga->ngx = ngx; iga->ngy = ngy; iga->ngz = ngz;
444: iga->IsPeriodicX = IsPeriodicX; iga->IsPeriodicY = IsPeriodicY; iga->IsPeriodicZ = IsPeriodicZ;
445: iga->numD = NumDerivatives;
447: /* Knot vector size */
448: iga->mx = 2*(iga->px+1);
449: iga->my = 2*(iga->py+1);
450: iga->mz = 2*(iga->pz+1);
451: iga->mx += (iga->px-iga->Cx)*(iga->Nx-1);
452: iga->my += (iga->py-iga->Cy)*(iga->Ny-1);
453: iga->mz += (iga->pz-iga->Cz)*(iga->Nz-1);
455: /* number of basis functions */
456: iga->nbx = iga->mx-iga->px-1;
457: iga->nby = iga->my-iga->py-1;
458: iga->nbz = iga->mz-iga->pz-1;
460: /* compute knot vectors */
461: PetscMalloc(iga->mx*sizeof(PetscReal), &iga->Ux);
462: PetscMalloc(iga->my*sizeof(PetscReal), &iga->Uy);
463: PetscMalloc(iga->mz*sizeof(PetscReal), &iga->Uz);
465: if(IsPeriodicX){
466: CreatePeriodicKnotVector(iga->Nx,iga->px,iga->Cx,iga->mx,iga->Ux,Ux0,Uxf);
467: iga->nbx -= iga->px;
468: }else{
469: CreateKnotVector(iga->Nx,iga->px,iga->Cx,iga->mx,iga->Ux,Ux0,Uxf);
470: }
471: if(IsPeriodicY){
472: CreatePeriodicKnotVector(iga->Ny,iga->py,iga->Cy,iga->my,iga->Uy,Uy0,Uyf);
473: iga->nby -= iga->py;
474: }else{
475: CreateKnotVector(iga->Ny,iga->py,iga->Cy,iga->my,iga->Uy,Uy0,Uyf);
476: }
477: if(IsPeriodicZ){
478: CreatePeriodicKnotVector(iga->Nz,iga->pz,iga->Cz,iga->mz,iga->Uz,Uz0,Uzf);
479: iga->nbz -= iga->pz;
480: }else{
481: CreateKnotVector(iga->Nz,iga->pz,iga->Cz,iga->mz,iga->Uz,Uz0,Uzf);
482: }
484: /* compute and store 1d basis functions at gauss points */
485: Compute1DBasisFunctions(iga->ngx, iga->numD, iga->Ux, iga->mx, iga->px, &iga->bdX);
486: Compute1DBasisFunctions(iga->ngy, iga->numD, iga->Uy, iga->my, iga->py, &iga->bdY);
487: Compute1DBasisFunctions(iga->ngz, iga->numD, iga->Uz, iga->mz, iga->pz, &iga->bdZ);
489: if (IsPeriodicX) xptype = DMDA_BOUNDARY_PERIODIC;
490: if (IsPeriodicY) yptype = DMDA_BOUNDARY_PERIODIC;
491: if (IsPeriodicZ) zptype = DMDA_BOUNDARY_PERIODIC;
493: sw = (iga->px>iga->py) ? iga->px : iga->py ; sw = (sw>iga->pz) ? sw : iga->pz ;
494: DMDACreate(PETSC_COMM_WORLD,&iga->da_dof);
495: DMDASetDim(iga->da_dof, 3);
496: DMDASetSizes(iga->da_dof,iga->nbx,iga->nby,iga->nbz);
497: DMDASetDof(iga->da_dof, ndof);
498: DMDASetBoundaryType(iga->da_dof, xptype, yptype, zptype);
499: DMDASetStencilType(iga->da_dof,DMDA_STENCIL_BOX);
500: DMDASetStencilWidth(iga->da_dof,sw);
501: DMSetFromOptions(iga->da_dof);
502: DMSetUp(iga->da_dof);
504: /* Determine how the elements map to processors */
506: DMDAGetLocalInfo(iga->da_dof,&info_dof);
507: BDSetElementOwnership(iga->bdX,iga->Nx,info_dof.xs,info_dof.xs+info_dof.xm-1,iga->px);
508: BDSetElementOwnership(iga->bdY,iga->Ny,info_dof.ys,info_dof.ys+info_dof.ym-1,iga->py);
509: BDSetElementOwnership(iga->bdZ,iga->Nz,info_dof.zs,info_dof.zs+info_dof.zm-1,iga->pz);
512: return(0);
513: }
518: PetscErrorCode DMIGAInitializeGeometry3d(DM dm,PetscInt ndof,PetscInt NumDerivatives,char *FunctionSpaceFile,char *GeomFile)
519: {
520: DM_IGA *iga = (DM_IGA *) dm->data;
521: FILE *fp;
523: MPI_Comm comm;
524: PetscViewer viewer;
525: PetscInt spatial_dim,i;
526: PetscReal Umax;
527: PetscInt numEl;
528: DMDABoundaryType ptype;
529: PetscInt sw;
530: DMDALocalInfo info_dof;
531: int ival;
532: double dval;
535: fp = fopen(FunctionSpaceFile, "r");
536: if (fp == NULL ){
537: SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_FILE_OPEN, "Cannot find geometry file");
538: }
540: if (fscanf(fp, "%d", &ival) != 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SYS,"Failed to read spatial dimension from %s",FunctionSpaceFile);
541: spatial_dim = ival;
542: if(spatial_dim != 3){
543: SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Geometry dimension != problem dimension");
544: }
546: /* Read in polynomial orders and number of basis functions */
547: {
548: int a,b,c;
549: if (fscanf(fp, "%d %d %d", &a, &b, &c) != 3) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SYS,"Failed to read polynomial orders from %s",FunctionSpaceFile);
550: iga->px = a; iga->py = b; iga->pz= c;
551: if (fscanf(fp, "%d %d %d", &a, &b, &c) != 3) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SYS,"Failed to read number of basis functions from %s",FunctionSpaceFile);
552: iga->nbx = a; iga->nby = b; iga->nbz= c;
553: }
555: /* Knot vector size */
556: iga->mx = iga->nbx + iga->px + 1;
557: iga->my = iga->nby + iga->py + 1;
558: iga->mz = iga->nbz + iga->pz + 1;
560: /* Read in my knot vectors */
561: PetscMalloc(iga->mx*sizeof(PetscReal), &iga->Ux);
562: PetscMalloc(iga->my*sizeof(PetscReal), &iga->Uy);
563: PetscMalloc(iga->mz*sizeof(PetscReal), &iga->Uz);
565: Umax = 0.0;
566: for(i=0;i<iga->mx;i++) {
567: if (fscanf(fp, "%lf ", &dval) != 1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SYS,"Failed to read X coordinate at %D from %s",i,FunctionSpaceFile);
568: iga->Ux[i] = dval;
569: if(iga->Ux[i] > Umax) Umax = iga->Ux[i];
570: }
571: for(i=0;i<iga->mx;i++) iga->Ux[i] /= Umax;
573: Umax = 0.0;
574: for(i=0;i<iga->my;i++) {
575: if (fscanf(fp, "%lf ", &dval) != 1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SYS,"Failed to read Y coordinate at %D from %s",i,FunctionSpaceFile);
576: iga->Uy[i] = dval;
577: if(iga->Uy[i] > Umax) Umax = iga->Uy[i];
578: }
579: for(i=0;i<iga->my;i++) iga->Uy[i] /= Umax;
581: Umax = 0.0;
582: for(i=0;i<iga->mz;i++) {
583: if (fscanf(fp, "%lf ", &dval) != 1) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_SYS,"Failed to read Z coordinate at %D from %s",i,FunctionSpaceFile);
584: iga->Uz[i] = dval;
585: if(iga->Uz[i] > Umax) Umax = iga->Uz[i];
586: }
587: for(i=0;i<iga->mz;i++) iga->Uz[i] /= Umax;
589: fclose(fp);
591: /* count the number of elements */
592: numEl = 0;
593: for(i = 0; i < iga->mx-1; ++i) {
594: PetscReal du = (iga->Ux[i+1]-iga->Ux[i]);
595: if(du > 1.0e-13) numEl++;
596: }
597: iga->Nx = numEl;
599: numEl = 0;
600: for(i = 0; i < iga->my-1; ++i) {
601: PetscReal du = (iga->Uy[i+1]-iga->Uy[i]);
602: if(du > 1.0e-13) numEl++;
603: }
604: iga->Ny = numEl;
606: numEl = 0;
607: for(i = 0; i < iga->mz-1; ++i) {
608: PetscReal du = (iga->Uz[i+1]-iga->Uz[i]);
609: if(du > 1.0e-13) numEl++;
610: }
611: iga->Nz = numEl;
613: /* Load constants */
614: iga->ngx = iga->px+1; iga->ngy = iga->py+1; iga->ngz = iga->pz+1;
615: iga->numD = NumDerivatives;
616: iga->IsRational = PETSC_TRUE;
617: iga->IsMapped = PETSC_TRUE;
619: /* compute and store 1d basis functions at gauss points */
620: Compute1DBasisFunctions(iga->ngx, iga->numD, iga->Ux, iga->mx, iga->px, &iga->bdX);
621: Compute1DBasisFunctions(iga->ngy, iga->numD, iga->Uy, iga->my, iga->py, &iga->bdY);
622: Compute1DBasisFunctions(iga->ngz, iga->numD, iga->Uz, iga->mz, iga->pz, &iga->bdZ);
624: ptype = DMDA_BOUNDARY_NONE ;
625: sw = (iga->px>iga->py) ? iga->px : iga->py ; sw = (sw>iga->pz) ? sw : iga->pz ;
627: /* DOF DA */
628: DMDACreate(PETSC_COMM_WORLD,&iga->da_dof);
629: DMDASetDim(iga->da_dof, 3);
630: DMDASetSizes(iga->da_dof,iga->nbx,iga->nby,iga->nbz);
631: DMDASetDof(iga->da_dof, ndof);
632: DMDASetBoundaryType(iga->da_dof, ptype, ptype, ptype);
633: DMDASetStencilType(iga->da_dof,DMDA_STENCIL_BOX);
634: DMDASetStencilWidth(iga->da_dof,sw);
635: DMSetFromOptions(iga->da_dof);
636: DMSetUp(iga->da_dof);
638: /* Determine how the elements map to processors */
639: DMDAGetLocalInfo(iga->da_dof,&info_dof);
640: BDSetElementOwnership(iga->bdX,iga->Nx,info_dof.xs,info_dof.xs+info_dof.xm-1,iga->px);
641: BDSetElementOwnership(iga->bdY,iga->Ny,info_dof.ys,info_dof.ys+info_dof.ym-1,iga->py);
642: BDSetElementOwnership(iga->bdZ,iga->Nz,info_dof.zs,info_dof.zs+info_dof.zm-1,iga->pz);
644: /* Geometry DA */
645: DMDACreate(PETSC_COMM_WORLD,&iga->da_geometry);
646: DMDASetDim(iga->da_geometry, 3);
647: DMDASetSizes(iga->da_geometry,iga->nbx,iga->nby,iga->nbz);
648: DMDASetDof(iga->da_geometry, 4);
649: DMDASetBoundaryType(iga->da_geometry, ptype, ptype, ptype);
650: DMDASetStencilType(iga->da_geometry,DMDA_STENCIL_BOX);
651: DMDASetStencilWidth(iga->da_geometry,sw);
652: DMSetFromOptions(iga->da_geometry);
653: DMSetUp(iga->da_geometry);
655: /* Read in the geometry */
656: DMCreateGlobalVector(iga->da_geometry,&iga->G);
657: PetscObjectGetComm((PetscObject)(iga->G),&comm);
658: PetscViewerBinaryOpen(comm,GeomFile,FILE_MODE_READ,&viewer);
659: VecLoad(iga->G,viewer);
660: PetscViewerDestroy(&viewer);
662: return(0);
663: }
667: PetscErrorCode DMIGAInitializeSymmetricTaper2d(DM dm,PetscBool IsRational,PetscInt NumDerivatives,PetscInt ndof,
668: PetscInt px,PetscInt Nx,PetscInt Cx,PetscReal fx,
669: PetscReal Ux0, PetscReal Uxf,PetscBool IsPeriodicX,PetscInt ngx,
670: PetscInt py,PetscInt Ny,PetscInt Cy,PetscReal fy,
671: PetscReal Uy0, PetscReal Uyf,PetscBool IsPeriodicY,PetscInt ngy)
672: {
673: DM_IGA *iga = (DM_IGA *) dm->data;
675: DMDABoundaryType xptype = DMDA_BOUNDARY_NONE ;
676: DMDABoundaryType yptype = DMDA_BOUNDARY_NONE ;
677: PetscInt sw;
678: DMDALocalInfo info_dof;
681: /* Test C < p */
682: if(px <= Cx || py <= Cy){
683: SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Discretization inconsistent: polynomial order must be greater than degree of continuity");
684: }
686: /* Load constants */
687: iga->px = px; iga->py = py;
688: iga->Nx = Nx; iga->Ny = Ny;
689: iga->Cx = Cx; iga->Cy = Cy;
690: iga->ngx = ngx; iga->ngy = ngy;
691: iga->IsPeriodicX = IsPeriodicX; iga->IsPeriodicY = IsPeriodicY;
692: iga->numD = NumDerivatives;
694: /* Knot vector size*/
695: iga->mx = 2*(iga->px+1);
696: iga->my = 2*(iga->py+1);
697: iga->mx += (iga->px-iga->Cx)*(iga->Nx-1);
698: iga->my += (iga->py-iga->Cy)*(iga->Ny-1);
700: /* number of basis functions */
701: iga->nbx = iga->mx-iga->px-1;
702: iga->nby = iga->my-iga->py-1;
704: /* compute knot vectors */
705: PetscMalloc(iga->mx*sizeof(PetscReal), &iga->Ux);
706: PetscMalloc(iga->my*sizeof(PetscReal), &iga->Uy);
708: if(IsPeriodicX){
710: SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Initialization routine for tapered meshes does not yet support periodicity");
711: CreatePeriodicKnotVector(iga->Nx,iga->px,iga->Cx,iga->mx,iga->Ux,Ux0,Uxf);
712: iga->nbx -= iga->px;
714: }else{
716: PetscReal *X1;
717: PetscReal *X2;
718: PetscInt i;
719: PetscReal *X;
721: PetscMalloc((Nx/2+1)*sizeof(PetscReal),&X1);
722: PetscMalloc((Nx/2+1)*sizeof(PetscReal),&X2);
724: CreateTaperSetOfPoints(Ux0,0.5*(Uxf+Ux0),fx,Nx/2+1,X1);
725: CreateTaperSetOfPoints(Uxf,0.5*(Uxf+Ux0),fx,Nx/2+1,X2);
727: PetscMalloc((Nx+1)*sizeof(PetscReal),&X);
729: if( Nx % 2 == 0){
731: for(i=0;i<Nx/2+1;i++) {
732: X[i]=X1[i];
733: X[Nx/2+i]=X2[Nx/2-i];
734: }
736: }else{
738: for(i=0;i<Nx/2+1;i++) {
739: X[i]=X1[i];
740: X[Nx/2+1+i]=X2[Nx/2-i];
741: }
743: X[Nx/2] = 2.0/3.0*X[Nx/2 - 1] + 1.0/3.0*X[Nx/2 + 2];
744: X[Nx/2+1] = 1.0/3.0*X[Nx/2 - 1] + 2.0/3.0*X[Nx/2 + 2];
746: }
748: CreateKnotVectorFromMesh(iga->Nx,iga->px,iga->Cx,iga->mx,iga->Ux,X,Nx+1);
750: PetscFree(X1);
751: PetscFree(X2);
752: PetscFree(X);
753: }
754: if(IsPeriodicY){
755: SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Initialization routine for tapered meshes does not yet support periodicity");
756: CreatePeriodicKnotVector(iga->Ny,iga->py,iga->Cy,iga->my,iga->Uy,Uy0,Uyf);
757: iga->nby -= iga->py;
758: }else{
761: PetscReal *X1;
762: PetscReal *X2;
763: PetscInt i;
764: PetscReal *X;
766: PetscMalloc((Ny/2+1)*sizeof(PetscReal),&X1);
767: PetscMalloc((Ny/2+1)*sizeof(PetscReal),&X2);
769: CreateTaperSetOfPoints(Uy0,0.5*(Uyf+Uy0),fy,Ny/2+1,X1);
770: CreateTaperSetOfPoints(Uyf,0.5*(Uyf+Uy0),fy,Ny/2+1,X2);
772: PetscMalloc((Ny+1)*sizeof(PetscReal),&X);
774: if( Ny % 2 == 0){
776: for(i=0;i<Ny/2+1;i++) {
777: X[i]=X1[i];
778: X[Ny/2+i]=X2[Ny/2-i];
779: }
781: }else{
783: for(i=0;i<Ny/2+1;i++) {
784: X[i]=X1[i];
785: X[Ny/2+1+i]=X2[Ny/2-i];
786: }
788: X[Ny/2] = 2.0/3.0*X[Ny/2 - 1] + 1.0/3.0*X[Ny/2 + 2];
789: X[Ny/2+1] = 1.0/3.0*X[Ny/2 - 1] + 2.0/3.0*X[Ny/2 + 2];
791: }
793: CreateKnotVectorFromMesh(iga->Ny,iga->py,iga->Cy,iga->my,iga->Uy,X,Ny+1);
795: PetscFree(X1);
796: PetscFree(X2);
797: PetscFree(X);
799: }
801: /* compute and store 1d basis functions at gauss points */
802: Compute1DBasisFunctions(iga->ngx, iga->numD, iga->Ux, iga->mx, iga->px, &iga->bdX);
803: Compute1DBasisFunctions(iga->ngy, iga->numD, iga->Uy, iga->my, iga->py, &iga->bdY);
805: if (IsPeriodicX) xptype = DMDA_BOUNDARY_PERIODIC;
806: if (IsPeriodicY) yptype = DMDA_BOUNDARY_PERIODIC;
808: sw = (iga->px>iga->py) ? iga->px : iga->py ;
809: DMDACreate(PETSC_COMM_WORLD,&iga->da_dof);
810: DMDASetDim(iga->da_dof, 2);
811: DMDASetSizes(iga->da_dof,iga->nbx,iga->nby,1);
812: DMDASetDof(iga->da_dof, ndof);
813: DMDASetBoundaryType(iga->da_dof, xptype, yptype, DMDA_BOUNDARY_NONE);
814: DMDASetStencilType(iga->da_dof,DMDA_STENCIL_BOX);
815: DMDASetStencilWidth(iga->da_dof,sw);
816: DMSetFromOptions(iga->da_dof);
817: DMSetUp(iga->da_dof);
819: /* Determine how the elements map to processors */
821: DMDAGetLocalInfo(iga->da_dof,&info_dof);
822: BDSetElementOwnership(iga->bdX,iga->Nx,info_dof.xs,info_dof.xs+info_dof.xm-1,iga->px);
823: BDSetElementOwnership(iga->bdY,iga->Ny,info_dof.ys,info_dof.ys+info_dof.ym-1,iga->py);
825: return(0);
826: }
831: PetscErrorCode DMIGAInitializeUniform2d(DM dm,PetscBool IsRational,PetscInt NumDerivatives,PetscInt ndof,
832: PetscInt px,PetscInt Nx,PetscInt Cx,PetscReal Ux0, PetscReal Uxf,PetscBool IsPeriodicX,PetscInt ngx,
833: PetscInt py,PetscInt Ny,PetscInt Cy,PetscReal Uy0, PetscReal Uyf,PetscBool IsPeriodicY,PetscInt ngy)
834: {
835: DM_IGA *iga = (DM_IGA *) dm->data;
837: DMDABoundaryType xptype = DMDA_BOUNDARY_NONE ;
838: DMDABoundaryType yptype = DMDA_BOUNDARY_NONE ;
839: PetscInt sw;
840: DMDALocalInfo info_dof;
843: /* Test C < p */
844: if(px <= Cx || py <= Cy){
845: SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Discretization inconsistent: polynomial order must be greater than degree of continuity");
846: }
848: /* Load constants */
849: iga->px = px; iga->py = py;
850: iga->Nx = Nx; iga->Ny = Ny;
851: iga->Cx = Cx; iga->Cy = Cy;
852: iga->ngx = ngx; iga->ngy = ngy;
853: iga->IsPeriodicX = IsPeriodicX; iga->IsPeriodicY = IsPeriodicY;
854: iga->numD = NumDerivatives;
856: /* Knot vector size */
857: iga->mx = 2*(iga->px+1);
858: iga->my = 2*(iga->py+1);
859: iga->mx += (iga->px-iga->Cx)*(iga->Nx-1);
860: iga->my += (iga->py-iga->Cy)*(iga->Ny-1);
862: /* number of basis functions */
863: iga->nbx = iga->mx-iga->px-1;
864: iga->nby = iga->my-iga->py-1;
866: /* compute knot vectors */
867: PetscMalloc(iga->mx*sizeof(PetscReal), &iga->Ux);
868: PetscMalloc(iga->my*sizeof(PetscReal), &iga->Uy);
870: if(IsPeriodicX){
871: CreatePeriodicKnotVector(iga->Nx,iga->px,iga->Cx,iga->mx,iga->Ux,Ux0,Uxf);
872: iga->nbx -= iga->px;
873: }else{
874: CreateKnotVector(iga->Nx,iga->px,iga->Cx,iga->mx,iga->Ux,Ux0,Uxf);
875: }
876: if(IsPeriodicY){
877: CreatePeriodicKnotVector(iga->Ny,iga->py,iga->Cy,iga->my,iga->Uy,Uy0,Uyf);
878: iga->nby -= iga->py;
879: }else{
880: CreateKnotVector(iga->Ny,iga->py,iga->Cy,iga->my,iga->Uy,Uy0,Uyf);
881: }
883: /* compute and store 1d basis functions at gauss points */
884: Compute1DBasisFunctions(iga->ngx, iga->numD, iga->Ux, iga->mx, iga->px, &iga->bdX);
885: Compute1DBasisFunctions(iga->ngy, iga->numD, iga->Uy, iga->my, iga->py, &iga->bdY);
887: if (IsPeriodicX) xptype = DMDA_BOUNDARY_PERIODIC;
888: if (IsPeriodicY) yptype = DMDA_BOUNDARY_PERIODIC;
890: sw = (iga->px>iga->py) ? iga->px : iga->py ;
891: DMDACreate(PETSC_COMM_WORLD,&iga->da_dof);
892: DMDASetDim(iga->da_dof, 2);
893: DMDASetSizes(iga->da_dof,iga->nbx,iga->nby,1);
894: DMDASetDof(iga->da_dof, ndof);
895: DMDASetBoundaryType(iga->da_dof, xptype, yptype, DMDA_BOUNDARY_NONE);
896: DMDASetStencilType(iga->da_dof,DMDA_STENCIL_BOX);
897: DMDASetStencilWidth(iga->da_dof,sw);
898: DMSetFromOptions(iga->da_dof);
899: DMSetUp(iga->da_dof);
901: /* Determine how the elements map to processors */
903: DMDAGetLocalInfo(iga->da_dof,&info_dof);
904: BDSetElementOwnership(iga->bdX,iga->Nx,info_dof.xs,info_dof.xs+info_dof.xm-1,iga->px);
905: BDSetElementOwnership(iga->bdY,iga->Ny,info_dof.ys,info_dof.ys+info_dof.ym-1,iga->py);
907: return(0);
908: }
912: PetscErrorCode DMIGAInitializeUniform1d(DM dm,PetscBool IsRational,PetscInt NumDerivatives,PetscInt ndof,
913: PetscInt px,PetscInt Nx,PetscInt Cx,PetscReal Ux0, PetscReal Uxf,PetscBool IsPeriodicX,PetscInt ngx)
914: {
915: DM_IGA *iga = (DM_IGA *) dm->data;
917: DMDABoundaryType ptype = DMDA_BOUNDARY_NONE ;
918: PetscInt sw;
919: DMDALocalInfo info_dof;
922: /* Test C < p */
923: if(px <= Cx){
924: SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Discretization inconsistent: polynomial order must be greater than degree of continuity");
925: }
927: /* Load constants */
928: iga->px = px;
929: iga->Nx = Nx;
930: iga->Cx = Cx;
931: iga->ngx = ngx;
932: iga->IsPeriodicX = IsPeriodicX;
933: iga->numD = NumDerivatives;
935: /* Knot vector size */
936: iga->mx = 2*(iga->px+1);
937: iga->mx += (iga->px-iga->Cx)*(iga->Nx-1);
939: /* number of basis functions */
940: iga->nbx = iga->mx-iga->px-1;
942: /* compute knot vectors */
943: PetscMalloc(iga->mx*sizeof(PetscReal), &iga->Ux);
945: if(IsPeriodicX){
946: CreatePeriodicKnotVector(iga->Nx,iga->px,iga->Cx,iga->mx,iga->Ux,Ux0,Uxf);
947: iga->nbx -= iga->px;
948: }else{
949: CreateKnotVector(iga->Nx,iga->px,iga->Cx,iga->mx,iga->Ux,Ux0,Uxf);
950: }
952: /* compute and store 1d basis functions at gauss points */
953: Compute1DBasisFunctions(iga->ngx, iga->numD, iga->Ux, iga->mx, iga->px, &iga->bdX);
955: if (IsPeriodicX) ptype = DMDA_BOUNDARY_PERIODIC;
957: sw = iga->px;
958: DMDACreate(PETSC_COMM_WORLD,&iga->da_dof);
959: DMDASetDim(iga->da_dof, 1);
960: DMDASetSizes(iga->da_dof,iga->nbx,1,1);
961: DMDASetDof(iga->da_dof, ndof);
962: DMDASetBoundaryType(iga->da_dof, ptype, ptype, ptype);
963: DMDASetStencilType(iga->da_dof,DMDA_STENCIL_BOX);
964: DMDASetStencilWidth(iga->da_dof,sw);
965: DMSetFromOptions(iga->da_dof);
966: DMSetUp(iga->da_dof);
968: /* Determine how the elements map to processors */
970: DMDAGetLocalInfo(iga->da_dof,&info_dof);
971: BDSetElementOwnership(iga->bdX,iga->Nx,info_dof.xs,info_dof.xs+info_dof.xm-1,iga->px);
973: return(0);
974: }
978: PetscErrorCode DMIGAKnotRefine3d(DM dm,PetscInt kx,PetscReal *Ux,PetscInt ky,PetscReal *Uy,PetscInt kz,PetscReal *Uz,DM iga_new)
979: {
980: DM_IGA *iga = (DM_IGA *) dm->data;
984: /* are the knots you are trying to insert feasible? */
985: CheckKnots(iga->mx,iga->Ux,kx,Ux);
986: CheckKnots(iga->my,iga->Uy,ky,Uy);
987: CheckKnots(iga->mz,iga->Uz,kz,Uz);
988: return(0);
989: }
993: PetscErrorCode DMIGAKnotRefine2d(DM dm,PetscInt kx,PetscReal *Ux,PetscInt ky,PetscReal *Uy,DM iga_new)
994: {
995: DM_IGA *iga = (DM_IGA *) dm->data;
999: /* are the knots you are trying to insert feasible? */
1000: CheckKnots(iga->mx,iga->Ux,kx,Ux);
1001: CheckKnots(iga->my,iga->Uy,ky,Uy);
1002: return(0);
1003: }
1007: PetscErrorCode BDCreate(BD *bd,PetscInt numD,PetscInt p,PetscInt numGP,PetscInt numEl)
1008: {
1009: BD bdd = PETSC_NULL;
1010: PetscInt i,j;
1014: PetscMalloc(sizeof(BasisData1D),bd);
1015: bdd = *bd;
1017: PetscMalloc(numEl*numGP*sizeof(GP),&(bdd->data));
1018: for(i=0;i<numEl;i++){
1019: for(j=0;j<numGP;j++){
1020: PetscMalloc((p+1)*(numD+1)*sizeof(PetscReal),&(bdd->data[i*numGP+j].basis));
1021: }
1022: }
1024: bdd->numD = numD;
1025: bdd->p = p;
1026: bdd->numGP = numGP;
1027: bdd->numEl = numEl;
1029: return(0);
1030: }
1036: PetscErrorCode BDDestroy(BD *bd)
1037: {
1039: PetscInt i,j;
1042: if (!(*bd)) return(0);
1043: for(i=0;i<(*bd)->numEl;i++) {
1044: for(j=0;j<(*bd)->numGP;j++) {
1045: PetscFree((*bd)->data[i*(*bd)->numGP+j].basis);
1046: }
1047: }
1048: PetscFree((*bd)->data);
1049: PetscFree(*bd);
1050: return(0);
1051: }
1055: PetscErrorCode BDGetBasis(BD bd, PetscInt iel, PetscInt igp, PetscInt ib, PetscInt ider, PetscReal *basis)
1056: {
1059: *basis = bd->data[iel*bd->numGP+igp].basis[ider*(bd->p+1)+ib];
1060: /* *basis = bd->arrayX[iel][igp*(bd->numD+1)*(bd->p+1) + ider*(bd->p+1) + ib]; */
1062: return(0);
1063: }
1067: PetscErrorCode BDSetBasis(BD bd, PetscInt iel, PetscInt igp, PetscInt ib, PetscInt ider, PetscReal basis)
1068: {
1071: bd->data[iel*bd->numGP+igp].basis[ider*(bd->p+1)+ib] = basis;
1072: /* bd->arrayX[iel][igp*(bd->numD+1)*(bd->p+1) + ider*(bd->p+1) + ib] = basis; */
1074: return(0);
1075: }
1079: PetscErrorCode BDSetGaussPt(BD bd, PetscInt iel, PetscInt igp, PetscReal gp)
1080: {
1083: bd->data[iel*bd->numGP+igp].gx = gp;
1084: /* bd->arrayX[iel][(bd->numD+1)*(bd->p+1)*(bd->numGP) + igp*(2)] = gp; */
1086: return(0);
1087: }
1091: PetscErrorCode BDSetGaussWt(BD bd, PetscInt iel, PetscInt igp, PetscReal gw)
1092: {
1095: bd->data[iel*bd->numGP+igp].gw = gw;
1096: /* bd->arrayX[iel][(bd->numD+1)*(bd->p+1)*(bd->numGP) + igp*(2) + 1] = gw; */
1098: return(0);
1099: }
1103: PetscErrorCode BDSetBasisOffset(BD bd, PetscInt iel, PetscInt bOffset)
1104: {
1105: PetscInt igp = 0;
1108: bd->data[iel*bd->numGP+igp].offset = bOffset;
1109: /* (bd->numD+1)*(bd->p+1)*(bd->numGP) + (bd->numGP)*(2) */
1110: /* bd->arrayX[iel][((bd->numD+1)*(bd->p+1)+2)*(bd->numGP)] = (PetscReal)bOffset; */
1112: return(0);
1113: }
1117: PetscErrorCode BDGetGaussPt(BD bd, PetscInt iel, PetscInt igp, PetscReal *gp)
1118: {
1120: *gp = bd->data[iel*bd->numGP+igp].gx;
1121: /* *gp = bd->arrayX[iel][(bd->numD+1)*(bd->p+1)*(bd->numGP) + igp*(2)]; */
1123: return(0);
1124: }
1128: PetscErrorCode BDGetGaussWt(BD bd, PetscInt iel, PetscInt igp, PetscReal *gw)
1129: {
1132: *gw = bd->data[iel*bd->numGP+igp].gw;
1133: /* *gw = bd->arrayX[iel][(bd->numD+1)*(bd->p+1)*(bd->numGP) + igp*(2) + 1]; */
1135: return(0);
1136: }
1140: PetscErrorCode BDGetBasisOffset(BD bd, PetscInt iel, PetscInt *bOffset)
1141: {
1142: PetscInt igp = 0;
1145: *bOffset = bd->data[iel*bd->numGP+igp].offset;
1146: /* (bd->numD+1)*(bd->p+1)*(bd->numGP) + (bd->numGP)*(2) */
1147: /* *bOffset = (int)bd->arrayX[iel][((bd->numD+1)*(bd->p+1)+2)*(bd->numGP)]; */
1149: return(0);
1150: }
1154: PetscErrorCode BDSetElementOwnership(BD bd,PetscInt nel,PetscInt dof_b,PetscInt dof_e,PetscInt p)
1155: {
1156: PetscInt i,boffset;
1159: bd->cont_b = nel; bd->cont_e = -1;
1160: bd->own_b = nel; bd->own_e = -1;
1161: for(i=0;i<nel;i++){ /* loop thru elements */
1163: BDGetBasisOffset(bd,i,&boffset); /* left-most dof */
1165: if(boffset >= dof_b && boffset <= dof_e){ /* I own this element */
1166: if(i < bd->own_b) bd->own_b = i;
1167: if(i > bd->own_e) bd->own_e = i;
1168: }
1170: if((boffset >= dof_b && boffset <= dof_e)||(boffset+p >= dof_b && boffset+p <= dof_e)){ /* This element contributes to me */
1171: if(i < bd->cont_b) bd->cont_b = i;
1172: if(i > bd->cont_e) bd->cont_e = i;
1173: }
1175: }
1177: return(0);
1178: }
1182: PetscErrorCode Compute1DBasisFunctions(PetscInt numGP, PetscInt numD, PetscReal *U, PetscInt m, PetscInt porder, BD *bd1D)
1183: {
1184: /* The idea of the 1d DA is to hold all information for a particular
1185: non-zero span of the knot vector. Here I will need to pass in the
1186: knot vector of which all processors will have a copy. Then I will
1187: need to determine which span in the knot vector corresponds to
1188: the nonzero spans represented in the DA */
1191: PetscReal *X, *W;
1192: PetscReal **Nu;
1193: PetscInt i;
1194: PetscInt numEl = 0;
1195: BD bd;
1196: PetscInt k,j,l;
1199: /* Setup gauss points */
1200: PetscMalloc2(numGP,PetscReal,&X,numGP,PetscReal,&W);
1201: SetupGauss1D(numGP,X,W);
1203: /* create space to get basis functions */
1204: PetscMalloc((numD+1)*sizeof(PetscReal *), &Nu);
1205: for(i = 0; i <= numD; ++i) {
1206: PetscMalloc((porder+1)*sizeof(PetscReal), &Nu[i]);
1207: }
1209: /* count the number of elements */
1210: for(i = 0; i < m-1; ++i) {
1211: PetscReal du = (U[i+1]-U[i]);
1212: if(du > 1.0e-13) numEl++;
1213: }
1215: /* initialize the bd */
1216: BDCreate(&bd,numD,porder,numGP,numEl);
1218: /* precompute the basis */
1219: for(i = 0; i < numEl; ++i) {
1220: PetscInt uspan = FindSpan(U,m,i,porder);
1221: PetscReal du = (U[uspan+1]-U[uspan]);
1223: /* here I am storing the first global basis number in 1d */
1224: BDSetBasisOffset(bd,i,uspan-porder);
1226: for(k = 0; k < numGP; ++k) {
1227: PetscReal u = (X[k]+1.0)*0.5*du + U[uspan];
1229: /* and also storing the gauss point and its weight (sneaky and flagrant abuse of DAs) */
1230: BDSetGaussPt(bd,i,k,u);
1231: BDSetGaussWt(bd,i,k,W[k]*0.5*du); /* note includes detJ for [-1:1]->[U[span]:U[span+1]] */
1232: GetDersBasisFuns(uspan,u,porder,U,Nu,numD);
1234: /* load values */
1235: for(j = 0; j < porder+1; ++j) {
1236: for(l = 0; l <= numD; ++l) {
1237: BDSetBasis(bd,i,k,j,l,Nu[l][j]);
1238: }
1239: }
1241: }
1242: }
1244: *bd1D = bd;
1246: /* Cleanup */
1247: for(i = 0; i <= numD; ++i) {
1248: PetscFree(Nu[i]);
1249: }
1250: PetscFree(Nu);
1251: PetscFree2(X, W);
1252: return(0);
1253: }
1255: PetscInt FindSpan(PetscReal *U,PetscInt m,PetscInt j,PetscInt p)
1256: {
1257: /* i is the span not counting zero spans, return the span including */
1259: PetscInt i,id = -1;
1260: for(i=p;i<m-p-1;i++)
1261: if(fabs(U[i+1]-U[i]) > 1.0e-14)
1262: {
1263: id += 1;
1264: if(id == j) return i;
1265: }
1267: return -1;
1268: }
1272: PetscErrorCode GetDersBasisFuns(PetscInt i,PetscReal u,PetscInt p,PetscReal *U, PetscReal **N,PetscInt nd)
1273: {
1274: /* This function calculates the non-vanishing spline basis functions
1275: and their derivatives. See the notes from the above function.
1276: i <-- knot span index
1277: u <-- parameter value for evaluation
1278: p <-- 1D polynomial order
1279: U <-- knot vector
1280: N --> (nd+1,p+1) matrix of function and derivative
1281: evaluations. The first row are the function evaluations,
1282: equivalent to the above function. The second row are the
1283: derivatives. */
1284: PetscInt j,k,r,s1,s2,rk,pk,j1,j2;
1285: PetscReal saved,temp,d;
1288: PetscReal **a, **ndu;
1289: PetscReal *left, *right;
1290: PetscMalloc(2*sizeof(PetscReal *), &a);
1291: PetscMalloc((p+1)*sizeof(PetscReal *), &ndu);
1292: PetscMalloc2((p+1),PetscReal,&left,(p+1),PetscReal,&right);
1295: for(j=0;j<(p+1);j++)
1296: {
1297: PetscMalloc((p+1)*sizeof(PetscReal), &ndu[j]);
1298: for(k=0;k<p+1;k++) {
1299: ndu[j][k] = 0.0;
1300: }
1301: }
1302: for(j=0;j<2;j++)
1303: {
1304: PetscMalloc((p+1)*sizeof(PetscReal), &a[j]);
1305: for(k=0;k<(p+1);k++) {
1306: a[j][k] = 0.0;
1307: }
1308: }
1309: ndu[0][0] = 1.0;
1310: for (j = 1; j <= p; j++)
1311: {
1312: left[j] = u - U[i + 1 - j];
1313: right[j] = U[i + j] - u;
1314: saved = 0.0;
1315: for (r = 0; r < j; r++)
1316: {
1317: /* Lower triangle */
1318: ndu[j][r] = right[r+1] + left[j-r];
1319: temp = ndu[r][j-1] / ndu[j][r];
1321: /* Upper triangle */
1322: ndu[r][j] = saved + right[r+1]*temp;
1323: saved = left[j-r]*temp;
1324: }
1325: ndu[j][j] = saved;
1326: }
1328: for (j = 0; j <= p; j++) N[0][j] = ndu[j][p];
1329: for (r = 0; r <= p; r++)
1330: {
1331: s1 = 0; s2 = 1; a[0][0] = 1.0;
1332: for (k = 1; k <= nd; k++)
1333: {
1334: d = 0.0;
1335: rk = r - k; pk = p - k;
1336: if (r >= k)
1337: {
1338: a[s2][0] = a[s1][0] / ndu[pk + 1][rk];
1339: d = a[s2][0] * ndu[rk][pk];
1340: }
1341: if (rk >= -1) {
1342: j1 = 1;
1343: } else {
1344: j1 = -rk;
1345: }
1346: if (r - 1 <= pk) {
1347: j2 = k - 1;
1348: } else {
1349: j2 = p - r;
1350: }
1351: for (j = j1; j <= j2; j++)
1352: {
1353: a[s2][j] = ( a[s1][j] - a[s1][j - 1] )/ndu[pk + 1][rk + j];
1354: d += a[s2][j]*ndu[rk + j][pk];
1355: }
1356: if (r <= pk)
1357: {
1358: a[s2][k] = - a[s1][k - 1]/ndu[pk + 1][r];
1359: d += a[s2][k]*ndu[r][pk];
1360: }
1361: N[k][r] = d;
1362: j = s1;
1363: s1 = s2;
1364: s2 = j;
1365: }
1366: }
1368: /* Multiply through by correct factors */
1369: r = p;
1370: for(k = 1; k <= nd; k++)
1371: {
1372: for(j = 0; j <= p; j++) N[k][j] *=r;
1373: r *= (p-k);
1374: }
1376: for(j=0;j<(p+1);j++)
1377: PetscFree(ndu[j]);
1378: for(j=0;j<2;j++)
1379: PetscFree(a[j]);
1380: PetscFree(a);
1381: PetscFree(ndu);
1382: PetscFree2(left, right);
1383: return(0);
1384: }
1388: PetscErrorCode SetupGauss1D(PetscInt n,PetscReal *X,PetscReal *W)
1389: {
1391: switch(n)
1392: {
1393: case 1: /* porder = 1 */
1394: X[0] = 0.0;
1395: W[0] = 2.0;
1396: break;
1397: case 2: /* porder = 3 */
1398: X[0] = -0.577350269189626;
1399: X[1] = -X[0];
1400: W[0] = 1.0;
1401: W[1] = 1.0;
1402: break;
1403: case 3: /* porder = 5 */
1404: X[0] = -0.774596669241483;
1405: X[1] = 0.0;
1406: X[2] = -X[0];
1407: W[0] = 0.555555555555556;
1408: W[1] = 0.888888888888889;
1409: W[2] = W[0];
1410: break;
1411: case 4: /* porder = 7 */
1412: X[0] = -.86113631159405257524;
1413: X[1] = -.33998104358485626481;
1414: X[2] = -X[1];
1415: X[3] = -X[0];
1416: W[0] = .34785484513745385736;
1417: W[1] = .65214515486254614264;
1418: W[2] = W[1];
1419: W[3] = W[0];
1420: break;
1421: case 5: /* porder = 9 */
1422: X[0] = -.90617984593866399282;
1423: X[1] = -.53846931010568309105;
1424: X[2] = 0.0;
1425: X[3] = .53846931010568309105;
1426: X[4] = .90617984593866399282;
1427: W[0] = .23692688505618908749;
1428: W[1] = .47862867049936646808;
1429: W[2] = .56888888888888888888;
1430: W[3] = .47862867049936646808;
1431: W[4] = .23692688505618908749;
1432: break;
1433: case 6:
1434: X[0] = -.9324695142031520 ;
1435: X[1] = -.6612093864662645 ;
1436: X[2] = -.2386191860831969 ;
1437: X[3] = .2386191860831969 ;
1438: X[4] = .6612093864662645 ;
1439: X[5] = .9324695142031520 ;
1440: W[0] = .1713244923791703 ;
1441: W[1] = .3607615730481386 ;
1442: W[2] = .4679139345726911 ;
1443: W[3] = .4679139345726911 ;
1444: W[4] = .3607615730481386 ;
1445: W[5] = .1713244923791703 ;
1446: break ;
1447: case 7:
1448: X[0] = -.9491079123427585 ;
1449: X[1] = -.7415311855993944 ;
1450: X[2] = -.4058451513773972 ;
1451: X[3] = 0.0 ;
1452: X[4] = .4058451513773972 ;
1453: X[5] = .7415311855993944 ;
1454: X[6] = .9491079123427585 ;
1455: W[0] = .1294849661688697 ;
1456: W[1] = .2797053914892767 ;
1457: W[2] = .3818300505051189 ;
1458: W[3] = .4179591836734694 ;
1459: W[4] = .3818300505051189 ;
1460: W[5] = .2797053914892767 ;
1461: W[6] = .1294849661688697 ;
1462: break ;
1463: case 8:
1464: X[0] = -.9602898564975362 ;
1465: X[1] = -.7966664774136267 ;
1466: X[2] = -.5255324099163290 ;
1467: X[3] = -.1834346424956498 ;
1468: X[4] = .1834346424956498 ;
1469: X[5] = .5255324099163290 ;
1470: X[6] = .7966664774136267 ;
1471: X[7] = .9602898564975362 ;
1472: W[0] = .1012285362903763 ;
1473: W[1] = .2223810344533745 ;
1474: W[2] = .3137066458778873 ;
1475: W[3] = .3626837833783620 ;
1476: W[4] = .3626837833783620 ;
1477: W[5] = .3137066458778873 ;
1478: W[6] = .2223810344533745 ;
1479: W[7] = .1012285362903763 ;
1480: break ;
1481: case 9:
1482: X[0] = -.9681602395076261 ;
1483: X[1] = -.8360311073266358 ;
1484: X[2] = -.6133714327005904 ;
1485: X[3] = -.3242534234038089 ;
1486: X[4] = 0.0 ;
1487: X[5] = .3242534234038089 ;
1488: X[6] = .6133714327005904 ;
1489: X[7] = .8360311073266358 ;
1490: X[8] = .9681602395076261 ;
1491: W[0] = .0812743883615744 ;
1492: W[1] = .1806481606948574 ;
1493: W[2] = .2606106964029354 ;
1494: W[3] = .3123470770400029 ;
1495: W[4] = .3302393550012598 ;
1496: W[5] = .3123470770400028 ;
1497: W[6] = .2606106964029355 ;
1498: W[7] = .1806481606948574 ;
1499: W[8] = .0812743883615744 ;
1500: break ;
1501: case 15:
1502: /* Generated in Mathematica:
1503: << NumericalDifferentialEquationAnalysis`
1504: GaussianQuadratureWeights[15, -1, 1, 25] here I overkilled
1505: the precision to make sure we get as much as possible. */
1506: X[0] = -0.9879925180204854284896 ; W[0] = 0.0307532419961172683546284 ;
1507: X[1] = -0.9372733924007059043078 ; W[1] = 0.0703660474881081247092674 ;
1508: X[2] = -0.8482065834104272162006 ; W[2] = 0.1071592204671719350118695 ;
1509: X[3] = -0.7244177313601700474162 ; W[3] = 0.139570677926154314447805 ;
1510: X[4] = -0.5709721726085388475372 ; W[4] = 0.166269205816993933553201 ;
1511: X[5] = -0.3941513470775633698972 ; W[5] = 0.186161000015562211026801 ;
1512: X[6] = -0.2011940939974345223006 ; W[6] = 0.198431485327111576456118 ;
1513: X[7] = 0.0000000000000000000000 ; W[7] = 0.202578241925561272880620 ;
1514: X[8] = 0.201194093997434522301 ; W[8] = 0.198431485327111576456118 ;
1515: X[9] = 0.394151347077563369897 ; W[9] = 0.186161000015562211026801 ;
1516: X[10] = 0.570972172608538847537 ; W[10] = 0.166269205816993933553201 ;
1517: X[11] = 0.724417731360170047416 ; W[11] = 0.139570677926154314447805 ;
1518: X[12] = 0.848206583410427216201 ; W[12] = 0.1071592204671719350118695 ;
1519: X[13] = 0.937273392400705904308 ; W[13] = 0.0703660474881081247092674 ;
1520: X[14] = 0.987992518020485428490 ; W[14] = 0.0307532419961172683546284 ;
1521: break ;
1522: case 20:
1523: /* Generated in Mathematica:
1524: << NumericalDifferentialEquationAnalysis`
1525: GaussianQuadratureWeights[20, -1, 1, 25] here I overkilled
1526: the precision to make sure we get as much as possible. */
1527: X[0] = -0.9931285991850949247861 ; W[0] = 0.0176140071391521183118620 ;
1528: X[1] = -0.9639719272779137912677 ; W[1] = 0.0406014298003869413310400 ;
1529: X[2] = -0.9122344282513259058678 ; W[2] = 0.0626720483341090635695065 ;
1530: X[3] = -0.839116971822218823395 ; W[3] = 0.083276741576704748724758 ;
1531: X[4] = -0.746331906460150792614 ; W[4] = 0.101930119817240435036750 ;
1532: X[5] = -0.636053680726515025453 ; W[5] = 0.118194531961518417312377 ;
1533: X[6] = -0.510867001950827098004 ; W[6] = 0.131688638449176626898494 ;
1534: X[7] = -0.373706088715419560673 ; W[7] = 0.142096109318382051329298 ;
1535: X[8] = -0.227785851141645078080 ; W[8] = 0.149172986472603746787829 ;
1536: X[9] = -0.076526521133497333755 ; W[9] = 0.152753387130725850698084 ;
1537: X[10] = 0.076526521133497333755 ; W[10] = 0.152753387130725850698084 ;
1538: X[11] = 0.227785851141645078080 ; W[11] = 0.149172986472603746787829 ;
1539: X[12] = 0.373706088715419560673 ; W[12] = 0.142096109318382051329298 ;
1540: X[13] = 0.510867001950827098004 ; W[13] = 0.131688638449176626898494 ;
1541: X[14] = 0.636053680726515025453 ; W[14] = 0.118194531961518417312377 ;
1542: X[15] = 0.746331906460150792614 ; W[15] = 0.101930119817240435036750 ;
1543: X[16] = 0.839116971822218823395 ; W[16] = 0.083276741576704748724758 ;
1544: X[17] = 0.912234428251325905868 ; W[17] = 0.0626720483341090635695065 ;
1545: X[18] = 0.963971927277913791268 ; W[18] = 0.0406014298003869413310400 ;
1546: X[19] = 0.993128599185094924786 ; W[19] = 0.0176140071391521183118620 ;
1547: break ;
1548: default:
1549: SETERRQ1(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Unimplemented number of gauss points %d!", n);
1550: }
1551: return(0);
1552: }
1556: PetscErrorCode CreateKnotVector(PetscInt N,PetscInt p,PetscInt C,PetscInt m, PetscReal *U,PetscReal U0,PetscReal Uf)
1557: {
1558: PetscInt i,j;
1559: PetscReal dU;
1563: dU = (Uf-U0)/N;
1564: for(i=0;i<(N-1);i++) /* insert N-1 knots */
1565: for(j=0;j<(p-C);j++) /* p-C times */
1566: U[(p+1) + i*(p-C) + j] = U0 + (i+1)*dU;
1568: for(i=0;i<(p+1);i++) /* open part */
1569: {
1570: U[i] = U0;
1571: U[m-i-1] = Uf;
1572: }
1574: return(0);
1575: }
1579: PetscErrorCode CreatePeriodicKnotVector(PetscInt N,PetscInt p,PetscInt C,PetscInt m, PetscReal *U,PetscReal U0,PetscReal Uf)
1580: {
1581: PetscInt i,j;
1582: PetscReal dU;
1586: dU = (Uf-U0)/N;
1587: for(i=0;i<(N+1);i++) /* insert N+1 knots */
1588: for(j=0;j<(p-C);j++) /* p-C times */
1589: U[(C+1) + i*(p-C) + j] = U0 + i*dU;
1591: for(i=0;i<(C+1);i++) /* periodic part */
1592: {
1593: U[i] = U0 - (Uf - U[(m-1-p)-(C+1)+i]);
1594: U[m-(C+1)+i] = Uf + (U[p+1+i] - U0);
1595: }
1597: return(0);
1598: }
1602: PetscErrorCode CreateKnotVectorFromMesh(PetscInt N,PetscInt p,PetscInt C,PetscInt m, PetscReal *U,PetscReal *X,PetscInt nX)
1603: {
1604: PetscInt i,j,countU=0;
1607: for(i=0;i<nX;i++){
1609: if(i==0 || i==nX-1){
1610: for(j=0;j<p+1;j++) {
1611: U[countU] = X[i];
1612: countU += 1;
1613: }
1614: }else{
1615: for(j=0;j<p-C;j++) {
1616: U[countU] = X[i];
1617: countU += 1;
1618: }
1619: }
1620: }
1622: return(0);
1623: }
1627: PetscErrorCode CreateTaperSetOfPoints(PetscReal Xbegin,PetscReal Xend,PetscReal f,PetscInt N,PetscReal *X)
1628: {
1629: /* N is the number of points, we will need number of spans, Ns */
1630: PetscInt Ns=N-1;
1631: PetscReal sum=0.0;
1632: PetscInt i;
1633: PetscReal dX;
1636: for(i=0;i<Ns;i++){
1637: sum += pow(f,i);
1638: }
1640: dX = (Xend-Xbegin)/sum;
1641: X[0] = Xbegin;
1642: for(i=1;i<N;i++){
1643: X[i] = X[i-1] + dX*pow(f,i-1.0);
1644: }
1646: return(0);
1647: }
1651: PetscErrorCode CheckKnots(PetscInt m,PetscReal *U,PetscInt k,PetscReal *Uadd)
1652: {
1653: /* Check the knots we are trying to insert into the vector U */
1655: /* 1) check that they are U[0] < Uadd[i] < U[m-1] */
1656: PetscInt j;
1659: for(j=0;j<k;j++)
1660: if(Uadd[j] < U[0] || Uadd[j] > U[m-1])
1661: SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Inserted knots beyond original knot vector limits");
1663: /* 2) I am lazy so I am not thinking about more that could go wrong */
1665: return(0);
1666: }