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: }