Example #1
0
File: vecd.c Project: xyuan/dohp
dErr VecDohpRestoreClosure(Vec v,Vec *c)
{
  dErr   err;
  dBool  isdohp;

  dFunctionBegin;
  dValidHeader(v,VEC_CLASSID,1);
  dValidPointer(c,2);
  err = PetscTypeCompare((dObject)v,VECDOHP,&isdohp);dCHK(err);
  if (!isdohp) dERROR(PETSC_COMM_SELF,1,"Vector type %s does not have closure",((dObject)v)->type_name);
  if (*c != ((Vec_MPI*)v->data)->localrep) dERROR(PETSC_COMM_SELF,1,"attempting to restore incorrect closure");
  err = VecStateSync_Private(v,*c);dCHK(err);
  err = PetscObjectDereference((dObject)*c);dCHK(err);
  *c = NULL;
  dFunctionReturn(0);
}
Example #2
0
File: vecd.c Project: xyuan/dohp
/** Create a cache for Dirichlet part of closure vector, and scatter from global closure to Dirichlet cache.

@arg[in] gvec Global vector
@arg[out] dcache New vector to hold the Dirichlet values
@arg[out] dscat Scatter from global closure to \a dcache

@note This could be local but it doesn't cost anything to make it global.
**/
dErr VecDohpCreateDirichletCache(Vec gvec,Vec *dcache,VecScatter *dscat)
{
  MPI_Comm comm;
  dErr     err;
  dBool    isdohp;
  IS       from;
  Vec      gc;
  dInt     n,nc,crstart;

  dFunctionBegin;
  dValidHeader(gvec,VEC_CLASSID,1);
  dValidPointer(dcache,2);
  dValidPointer(dscat,3);
  err = PetscTypeCompare((PetscObject)gvec,VECDOHP,&isdohp);dCHK(err);
  if (!isdohp) dERROR(PETSC_COMM_SELF,PETSC_ERR_SUP,"Vec type %s",((PetscObject)gvec)->type_name);
  err = PetscObjectGetComm((PetscObject)gvec,&comm);dCHK(err);
  err = VecGetLocalSize(gvec,&n);dCHK(err);
  err = VecDohpGetClosure(gvec,&gc);dCHK(err);
  err = VecGetLocalSize(gc,&nc);dCHK(err);
  err = VecGetOwnershipRange(gc,&crstart,NULL);dCHK(err);
  err = VecCreateMPI(comm,nc-n,PETSC_DECIDE,dcache);dCHK(err);
  err = ISCreateStride(comm,nc-n,crstart+n,1,&from);dCHK(err);
  err = VecScatterCreate(gc,from,*dcache,NULL,dscat);dCHK(err);
  err = VecDohpRestoreClosure(gvec,&gc);dCHK(err);
  err = ISDestroy(&from);dCHK(err);
  /* \todo deal with rotations */
  dFunctionReturn(0);
}
Example #3
0
File: vecd.c Project: xyuan/dohp
dErr VecCreateDohp(MPI_Comm comm,dInt bs,dInt n,dInt nc,dInt nghosts,const dInt ghosts[],Vec *v)
{
  Vec_MPI *vmpi;
  Vec      vc,vg;
  dScalar *a;
  dErr     err;

  dFunctionBegin;
  dValidPointer(v,7);
  *v = 0;
  err = VecCreateGhostBlock(comm,bs,nc*bs,PETSC_DECIDE,nghosts,ghosts,&vc);dCHK(err);
  err = VecGetArray(vc,&a);dCHK(err);
  err = VecCreateMPIWithArray(comm,n*bs,PETSC_DECIDE,a,&vg);dCHK(err);
  err = VecRestoreArray(vc,&a);dCHK(err);
  err = VecSetBlockSize(vg,bs);dCHK(err);
  vmpi = vg->data;
  if (vmpi->localrep) dERROR(PETSC_COMM_SELF,1,"Vector has localrep, expected no localrep");
  vmpi->localrep = vc;          /* subvert this field to mean closed rep */
  /* Since we subvect .localrep, VecDestroy_MPI will automatically destroy the closed form */
  vg->ops->duplicate = VecDuplicate_Dohp;
  //vg->ops->destroy   = VecDestroy_Dohp;
  /* It might be useful to set the (block) LocalToGlobal mapping here, but in the use case I have in mind, the user is
  * always working with the closed form anyway (in function evaluation).  The \e matrix does need a customized
  * LocalToGlobal mapping.
  */
  err = PetscObjectChangeTypeName((dObject)vg,VECDOHP);dCHK(err);
  *v = vg;
  dFunctionReturn(0);
}
Example #4
0
dErr dUnitsView(dUnits un,dViewer viewer)
{
  dBool iascii;
  dErr err;

  dFunctionBegin;
  dValidHeader(un,dUNITS_CLASSID,1);
  if (!viewer) {err = PetscViewerASCIIGetStdout(((dObject)un)->comm,&viewer);dCHK(err);}
  dValidHeader(viewer,PETSC_VIEWER_CLASSID,2);
  PetscCheckSameComm(un,1,viewer,2);

  err = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);dCHK(err);
  if (iascii) {
    err = PetscObjectPrintClassNamePrefixType((PetscObject)un,viewer,"Units Manager");dCHK(err);
    err = PetscViewerASCIIPushTab(viewer);dCHK(err);
    for (dInt i=0; i<un->nalloc && un->list[i]; i++) {
      dUnit u = un->list[i];
      err = PetscViewerASCIIPrintf(viewer,"%-12s: 1 internal unit = %10.4e %s (%s) = %10.4e %s\n",
                                   dUnitQuantityName(u),dUnitDimensionalize(u,1.0),dUnitName(u),dUnitShortName(u),dUnitDimensionalizeSI(u,1.0),dUnitSIName(u));dCHK(err);
      err = PetscViewerASCIIPrintf(viewer,"%-12s  1 %s = %10.4e %s\n","",dUnitShortName(u),dUnitDimensionalizeSI(u,dUnitNonDimensionalize(u,1.0)),dUnitSIName(u));dCHK(err);
    }
    err = PetscViewerASCIIPopTab(viewer);dCHK(err);
  } else dERROR(((dObject)un)->comm,PETSC_ERR_SUP,"Viewer type %s not supported",((PetscObject)viewer)->type_name);
  dFunctionReturn(0);
}
Example #5
0
// Logically collective
dErr dUnitsCreateUnit(dUnits un,const char *type,const char *longname,const char *shortname,dInt n,const dReal expon[],dUnit *newunit)
{
  dErr err;
  dUnit unit;

  dFunctionBegin;
  dValidHeader(un,dUNITS_CLASSID,1);
  if (n < 1 || n > dUNITS_MAX) dERROR(((dObject)un)->comm,PETSC_ERR_ARG_OUTOFRANGE,"The number of exponents %D must be positive, but no larger than %D",n,(dInt)dUNITS_MAX);
  dValidRealPointer(expon,5);
  dValidPointer(newunit,6);
  err = dUnitsGetEmptyUnit_Private(un,&unit);dCHK(err);
  err = PetscStrallocpy(type,&unit->quantity);dCHK(err);
  err = dUnitsAssignName(un,dUnitName,longname,n,expon,&unit->longname);dCHK(err);
  err = dUnitsAssignName(un,dUnitShortName,shortname,n,expon,&unit->shortname);dCHK(err);
  err = dUnitsAssignName(un,dUnitSIName,NULL,n,expon,&unit->siname);dCHK(err);
  unit->toSI = 1.0;
  unit->toCommon = 1.0;
  for (dInt i=0; i<n; i++) {
    dUnit base;
    err = dUnitsGetBase(un,i,&base);dCHK(err);
    unit->toCommon *= PetscPowScalar(dUnitDimensionalize(base,1.0),expon[i]);
    unit->toSI *= PetscPowScalar(dUnitDimensionalizeSI(base,1.0),expon[i]);
    unit->expon[i] = expon[i];
  }
  *newunit = unit;
  dFunctionReturn(0);
}
Example #6
0
static dErr JakoGradient2(VHTCase scase,const dReal field[],dInt i,dInt j,dReal grad[2])
{
  VHTCase_Jako *jako = scase->data;
  const dReal dx = jako->mygeo[1],dy = jako->mygeo[5];
  const dInt nx = jako->nx,ny = jako->ny;
  dReal fx0,fx1,fy0,fy1;
  dFunctionBegin;
  if (i+1 >= nx) dERROR(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"X slope would evaluate point (%D,%D) outside of valid range %Dx%D",i+1,j,nx,ny);
  if (j-1 < 0) dERROR(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Y slope would evaluate point (%D,%D) outside of valid range %Dx%D",i,j-1,nx,ny);
  fx0 = field[j*nx + i + 0] - field[j*nx + i - 1];
  fx1 = field[j*nx + i + 1] - field[j*nx + i + 0];
  grad[0] = (dAbs(fx0) < dAbs(fx1) ? fx0 : fx1) / dx;
  // The raster has Y axis flipped
  fy0 = field[(j+0)*nx + i] - field[(j+1)*nx + i];
  fy1 = field[(j-1)*nx + i] - field[(j+0)*nx + i];
  grad[1] = (dAbs(fy0) < dAbs(fy1) ? fy0 : fy1) / dy;
  dFunctionReturn(0);
}
Example #7
0
File: vecd.c Project: xyuan/dohp
/** Get the closed form of a Dohp vector
*
* @note Dohp vectors are basically just MPI vectors, the only difference is that instead of a local form, we have a
* closed form.  We subvert .localrep to mean the closed form.
*
**/
dErr VecDohpGetClosure(Vec v,Vec *c)
{
  Vec_MPI *vmpi;
  dBool    isdohp;
  dErr     err;

  dFunctionBegin;
  dValidHeader(v,VEC_CLASSID,1);
  dValidPointer(c,2);
  err = PetscTypeCompare((dObject)v,VECDOHP,&isdohp);dCHK(err);
  if (!isdohp) dERROR(PETSC_COMM_SELF,1,"Vector type %s does not have closure",((dObject)v)->type_name);
  vmpi = v->data;
  if (!vmpi->localrep) dERROR(PETSC_COMM_SELF,1,"Vector has no closure");
  *c = vmpi->localrep;
  err = VecStateSync_Private(v,*c);dCHK(err);
  err = PetscObjectReference((dObject)*c);dCHK(err);
  dFunctionReturn(0);
}
Example #8
0
static dErr JakoFindPixel(VHTCase scase,const dReal x[3],dInt *ix,dInt *iy)
{
  VHTCase_Jako *jako = scase->data;
  double xpixel,ypixel;
  dInt i,j;

  dFunctionBegin;
  *ix = -1;
  *iy = -1;
  if (x[0] < scase->bbox[0][0] || scase->bbox[0][1] < x[0])
    dERROR(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"x[0]=%f not in bounding box %f:%f",x[0],scase->bbox[0][0],scase->bbox[0][1]);
  if (x[1] < scase->bbox[1][0] || scase->bbox[1][1] < x[1])
    dERROR(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"x[1]=%f not in bounding box %f:%f",x[1],scase->bbox[1][0],scase->bbox[1][1]);
  GDALApplyGeoTransform(jako->myinvgeo,x[0],x[1],&xpixel,&ypixel);
  i = (dInt)xpixel;
  j = (dInt)ypixel;
  if (i < 0 || jako->nx <= i) dERROR(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Computed xp=%D not in range %D:%D",i,0,jako->nx);
  if (j < 0 || jako->ny <= j) dERROR(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Computed yp=%D not in range %D:%D",j,0,jako->ny);
  *ix = i;
  *iy = j;
  dFunctionReturn(0);
}
Example #9
0
/** Get the number of subelements and number of vertices of subelements.
**/
dErr dFSGetSubElementMesh(dFS fs,dInt nelems,dInt nconn,dEntTopology topo[],dInt off[],dInt ind[])
{
    dErr err;

    dFunctionBegin;
    dValidHeader(fs,DM_CLASSID,1);
    dValidIntPointer(topo,4);
    dValidIntPointer(off,5);
    dValidIntPointer(ind,6);
    if (!fs->ops->getsubelementmesh) dERROR(PETSC_COMM_SELF,1,"not implemented");
    err = (*fs->ops->getsubelementmesh)(fs,nelems,nconn,topo,off,ind);
    dCHK(err);
    dFunctionReturn(0);
}
Example #10
0
/** Get the number of subelements and number of vertices of subelements.
*
* @note the number of vertices is the same as the number of local nodes in closure vertor.
**/
dErr dFSGetSubElementMeshSize(dFS fs,dInt *nelems,dInt *nverts,dInt *nconn)
{
    dErr err;

    dFunctionBegin;
    dValidHeader(fs,DM_CLASSID,1);
    dValidIntPointer(nelems,2);
    dValidIntPointer(nverts,3);
    dValidIntPointer(nconn,4);
    if (!fs->ops->getsubelementmeshsize) dERROR(PETSC_COMM_SELF,1,"not implemented");
    err = (*fs->ops->getsubelementmeshsize)(fs,nelems,nverts,nconn);
    dCHK(err);
    dFunctionReturn(0);
}
Example #11
0
File: dunits.c Project: xyuan/dohp
static dErr dUnitsGetEmptyUnit_Private(dUnits un,dUnit *unit)
{
  dInt i;
  dErr err;

  dFunctionBegin;
  *unit = NULL;
  for (i=0; i<un->nalloc && un->list[i]; i++) ;
  if (i == un->nalloc) dERROR(((dObject)un)->comm,PETSC_ERR_SUP,"reallocation not implemented");
  err = dCallocA(1,&un->list[i]);dCHK(err);
  un->list[i]->world = un;
  *unit = un->list[i];
  dFunctionReturn(0);
}
Example #12
0
dErr dFSRotationView(dFSRotation rot,PetscViewer viewer)
{
  dErr err;

  dFunctionBegin;
  dValidHeader(rot,dFSROT_CLASSID,1);
  if (!viewer) {
    err = PetscViewerASCIIGetStdout(((dObject)rot)->comm,&viewer);dCHK(err);
  }
  dValidHeader(viewer,PETSC_VIEWER_CLASSID,2);
  PetscCheckSameComm(rot,1,viewer,2);

  dERROR(PETSC_COMM_SELF,1,"not implemented");
  dFunctionReturn(0);
}
Example #13
0
File: vecd.c Project: xyuan/dohp
dErr VecDohpZeroEntries(Vec v)
{
  dErr err;
  dBool  isdohp;
  Vec c;

  dFunctionBegin;
  dValidHeader(v,VEC_CLASSID,1);
  err = PetscTypeCompare((dObject)v,VECDOHP,&isdohp);dCHK(err);
  if (!isdohp) dERROR(PETSC_COMM_SELF,PETSC_ERR_SUP,"Vector type %s",((dObject)v)->type_name);
  err = VecDohpGetClosure(v,&c);dCHK(err);
  err = VecZeroEntries(c);dCHK(err);
  err = VecDohpRestoreClosure(v,&c);dCHK(err);
  dFunctionReturn(0);
}
Example #14
0
// Generates a mesh of a brick using run-time parameters.
// The new mesh populates the given root set.
// This should be converted to have a useful programmatic API.
dErr dMeshGenerateBlock(dMesh dmesh,dMeshESH root,PetscBool do_geom)
{
  const char pTagName[]="OWNING_PART", pSetName[]="PARALLEL_PARTITION";
  PetscBool  assoc_with_brick=0,do_color_bdy=0,do_material = 1,do_uniform = 1,do_global_number = 0,do_global_id = 1;
  PetscBool  do_partition = 1,do_pressure = 0,do_faces = 1,do_edges = 1;
  dReal rotate_y = 0;
  dInt verbose = 0;
  iMesh_Instance mesh;
  iBase_EntityHandle *entbuf;
  iBase_EntitySetHandle facesets[6];
  iBase_TagHandle pTag;
  MeshListEH v=MLZ,e=MLZ,f=MLZ,r=MLZ,c=MLZ;
  MeshListReal x=MLZ;
  MeshListInt s=MLZ,part=MLZ;
  dInt *face[6],facecount[6]={0};
  int err,i,j,k,m,n,p,M,N,P,I,J,K,order=iBase_INTERLEAVED;
  Box box;
  PetscViewer viewer;

  dFunctionBegin;
  dValidHeader(dmesh,dMESH_CLASSID,1);
  err = PetscViewerASCIIGetStdout(((PetscObject)dmesh)->comm,&viewer);dCHK(err);
  err = PetscOptionsBegin(((PetscObject)dmesh)->comm,((PetscObject)dmesh)->prefix,"dMeshGenerate Block: generate cartesian meshes",NULL);dCHK(err);
  {
    char boxstr[256] = "-1:1,-1:1,-1:1",mnp[256] = "5,5,5",MNP[256] = "2,2,2";
    err = PetscOptionsInt("-dmeshgen_block_verbose","verbosity of output","none",verbose,&verbose,NULL);dCHK(err);
    if (do_geom) {
      err = PetscOptionsBool("-dmeshgen_block_assoc_with_brick","associate boundaries with brick","none",assoc_with_brick,&assoc_with_brick,NULL);dCHK(err);
    }
    err = PetscOptionsBool("-dmeshgen_block_color_bdy","color boundary sets","none",do_color_bdy,&do_color_bdy,NULL);dCHK(err);
    err = PetscOptionsBool("-dmeshgen_block_material","create material sets","none",do_material,&do_material,NULL);dCHK(err);
    err = PetscOptionsBool("-dmeshgen_block_uniform","create uniform sets","none",do_uniform,&do_uniform,NULL);dCHK(err);
    err = PetscOptionsBool("-dmeshgen_block_global_number","create global_number tags","none",do_global_number,&do_global_number,NULL);dCHK(err);
    err = PetscOptionsBool("-dmeshgen_block_global_id","create GLOBAL_ID tags","none",do_global_id,&do_global_id,NULL);dCHK(err);
    err = PetscOptionsBool("-dmeshgen_block_partition","create partition sets","none",do_partition,&do_partition,NULL);dCHK(err);
    err = PetscOptionsBool("-dmeshgen_block_pressure","create pressure sets","none",do_pressure,&do_pressure,NULL);dCHK(err);
    err = PetscOptionsBool("-dmeshgen_block_faces","create face entities","none",do_faces,&do_faces,NULL);dCHK(err);
    err = PetscOptionsBool("-dmeshgen_block_edges","create face entities","none",do_edges,&do_edges,NULL);dCHK(err);
    err = PetscOptionsReal("-dmeshgen_block_rotate_y","rotate domain by given angle (degrees) around y axis)","none",rotate_y,&rotate_y,NULL);dCHK(err); rotate_y *= PETSC_PI/180.;
    err = PetscOptionsString("-dmeshgen_block_box","box x0:x1,y0:y1,z0:z1","none",boxstr,boxstr,sizeof(boxstr),NULL);dCHK(err);
    err = PetscOptionsString("-dmeshgen_block_mnp","number of points m,n,p","none",mnp,mnp,sizeof(mnp),NULL);dCHK(err);
    err = PetscOptionsString("-dmeshgen_block_procs_mnp","number of procs M,N,P","none",MNP,MNP,sizeof(MNP),NULL);dCHK(err);

    i = sscanf(boxstr,"%lf:%lf,%lf:%lf,%lf:%lf",&box.x0,&box.x1,&box.y0,&box.y1,&box.z0,&box.z1);
    if (i != 6) dERROR(PETSC_COMM_SELF,1,"Failed to parse bounding box.");
    i = sscanf(mnp,"%d,%d,%d",&m,&n,&p);
    if (i != 3) dERROR(PETSC_COMM_SELF,1,"Failed to parse size.");
    i = sscanf(MNP,"%d,%d,%d",&M,&N,&P);
    if (i != 3) dERROR(PETSC_COMM_SELF,1,"Failed to parse partition size.");
  }
  err = PetscOptionsEnd();
  err = dMeshGetInstance(dmesh,&mesh);dCHK(err);

  /* Allocate buffers */
  err = dMallocA(m*n*p*3,&entbuf);dCHK(err); /* More than enough to hold all entities of any given type */
  for (i=0; i<6; i++) {
    int n2max = dSqrInt(dMaxInt(m,dMaxInt(n,p)));
    err = dMallocA(2*n2max,&face[i]);dCHK(err);
    iMesh_createEntSet(mesh,0,&facesets[i],&err);dICHK(mesh,err);
  }

  /* Create vertices */
  x.a = x.s = m*n*p*3; x.v = malloc(x.a*sizeof(double));
  for (i=0; i<m; i++) {
    for (j=0; j<n; j++) {
      for (k=0; k<p; k++) {
        dReal X,Y,Z;
        I = (i*n+j)*p+k;
        if (i==0) AddToFace(face,facecount,3,I);
        else if (i==m-1) AddToFace(face,facecount,1,I);
        else if (j==0) AddToFace(face,facecount,0,I);
        else if (j==n-1) AddToFace(face,facecount,2,I);
        else if (k==0) AddToFace(face,facecount,4,I);
        else if (k==p-1) AddToFace(face,facecount,5,I);
        X = box.x0 + (box.x1-box.x0)*(1.*i/(m-1));
        Y = box.y0 + (box.y1-box.y0)*(1.*j/(n-1));
        Z = box.z0 + (box.z1-box.z0)*(1.*k/(p-1));
        x.v[3*I+0] = cos(rotate_y) * X - sin(rotate_y) * Z;
        x.v[3*I+1] = Y;
        x.v[3*I+2] = sin(rotate_y) * X + cos(rotate_y) * Z;
      }
    }
  }
  iMesh_createVtxArr(mesh,m*n*p,order,x.v,x.s,&v.v,&v.a,&v.s,&err);dICHK(mesh,err);
  err = CommitToFaceSets(mesh,v.v,face,facecount,facesets,entbuf);
  MeshListFree(x);

  /* Create regions */
  c.a = c.s = (m-1)*(n-1)*(p-1)*8; c.v = malloc(c.a*sizeof(iBase_EntityHandle)); /* connectivity */
  I=0;
  for (i=0; i<m-1; i++) {
    for (j=0; j<n-1; j++) {
      for (k=0; k<p-1; k++) {
        c.v[I++] = v.v[((i+0)*n+(j+0))*p+(k+0)];
        c.v[I++] = v.v[((i+1)*n+(j+0))*p+(k+0)];
        c.v[I++] = v.v[((i+1)*n+(j+1))*p+(k+0)];
        c.v[I++] = v.v[((i+0)*n+(j+1))*p+(k+0)];
        c.v[I++] = v.v[((i+0)*n+(j+0))*p+(k+1)];
        c.v[I++] = v.v[((i+1)*n+(j+0))*p+(k+1)];
        c.v[I++] = v.v[((i+1)*n+(j+1))*p+(k+1)];
        c.v[I++] = v.v[((i+0)*n+(j+1))*p+(k+1)];
      }
    }
  }
  if (I != c.s) dERROR(PETSC_COMM_SELF,1,"Wrong number of regions.");
  iMesh_createEntArr(mesh,iMesh_HEXAHEDRON,c.v,c.s,&r.v,&r.a,&r.s,&s.v,&s.a,&s.s,&err);dICHK(mesh,err);
  if (r.s != (m-1)*(n-1)*(p-1)) dERROR(PETSC_COMM_SELF,1,"Wrong number of regions created.");
  if (verbose > 0) {err = PetscViewerASCIIPrintf(viewer,"region size %d, status size %d\n",r.s,s.s);dCHK(err);}

  if (do_global_number) {err = doGlobalNumber(mesh,root);dCHK(err);}
  if (do_global_id) {err = doGlobalID(mesh,root);dCHK(err);}

  if (do_partition) {           /* Partition tags */
    /* Create partition. */
    part.a = part.s = r.s; part.v = malloc(part.a*sizeof(int));
    for (i=0; i<m-1; i++) {
      for (j=0; j<n-1; j++) {
        for (k=0; k<p-1; k++) {
          I = i*M/(m-1); J = j*N/(n-1); K = k*P/(p-1);
          part.v[(i*(n-1)+j)*(p-1)+k] = (I*N+J)*P+K;
        }
      }
    }
    /* MATERIAL_SET is a special name associated with all iMesh instances
    * If we are using a different name, we can assume it is not special. */
    if (strcmp(pTagName,"MATERIAL_SET")) {
      iMesh_createTag(mesh,pTagName,1,iBase_INTEGER,&pTag,&err,sizeof(pTagName));dICHK(mesh,err);
    } else {
      iMesh_getTagHandle(mesh,"MATERIAL_SET",&pTag,&err,sizeof("MATERIAL_SET"));dICHK(mesh,err);
    }
    iMesh_setIntArrData(mesh,r.v,r.s,pTag,part.v,part.s,&err);dICHK(mesh,err);
    MeshListFree(part);
  }

  if (do_partition)             /* Partition sets */
  {
    int ii,jj,kk;
    iBase_EntitySetHandle partset;
    iBase_EntityHandle *entp;
    /* reuse some stuff, set up the a partition set */
    iMesh_createTag(mesh,pSetName,1,iBase_INTEGER,&pTag,&err,sizeof(pSetName));dICHK(mesh,err);
    for (i=0; i<M; i++) {
      for (j=0; j<N; j++) {
        for (k=0; k<P; k++) {
          iMesh_createEntSet(mesh,0,&partset,&err);dICHK(mesh,err);
          entp = entbuf;
          for (ii=i*(m-1)/M; ii<(i+1)*(m-1)/M; ii++) {
            for (jj=j*(n-1)/N; jj<(j+1)*(n-1)/N; jj++) {
              for (kk=k*(p-1)/P; kk<(k+1)*(p-1)/P; kk++) {
                *entp++ = r.v[(ii*(n-1)+jj)*(p-1)+kk];
              }
            }
          }
          if (verbose > 0) {err = PetscViewerASCIIPrintf(viewer,"part[%d (%d,%d,%d)] has %d regions\n",(i*N+j)*P+k,i,j,k,(int)(entp-entbuf));dCHK(err);}
          iMesh_addEntArrToSet(mesh,entbuf,(int)(entp-entbuf),partset,&err);dICHK(mesh,err);
          iMesh_setEntSetIntData(mesh,partset,pTag,(i*N+j)*P+k,&err);dICHK(mesh,err);
        }
      }
    }
  }
  MeshListFree(r); MeshListFree(s); MeshListFree(c);

  if (do_faces)
  {
    /* Create faces */
    c.a = c.s = 4*((m-1)*(n-1)*p + (m-1)*n*(p-1) + m*(n-1)*(p-1)); c.v = malloc(c.a*sizeof(iBase_EntityHandle));
    I = 0;
    for (i=0; i<m-1; i++) {     /* Faces with normal pointing in positive z direction */
      for (j=0; j<n-1; j++) {
        for (k=0; k<p; k++) {
          if (k==0) AddToFace(face,facecount,4,I/4);
          if (k==p-1) AddToFace(face,facecount,5,I/4);
          c.v[I++] = v.v[((i+0)*n+(j+0))*p+k];
          c.v[I++] = v.v[((i+1)*n+(j+0))*p+k];
          c.v[I++] = v.v[((i+1)*n+(j+1))*p+k];
          c.v[I++] = v.v[((i+0)*n+(j+1))*p+k];
        }
      }
    }
    for (i=0; i<m-1; i++) {     /* Faces with normal pointing in negative y direction */
      for (j=0; j<n; j++) {
        for (k=0; k<p-1; k++) {
          if (j==0) AddToFace(face,facecount,0,I/4);
          if (j==n-1) AddToFace(face,facecount,2,I/4);
          c.v[I++] = v.v[((i+0)*n+j)*p+(k+0)];
          c.v[I++] = v.v[((i+1)*n+j)*p+(k+0)];
          c.v[I++] = v.v[((i+1)*n+j)*p+(k+1)];
          c.v[I++] = v.v[((i+0)*n+j)*p+(k+1)];
        }
      }
    }
    for (i=0; i<m; i++) {       /* Faces with normal pointing in positive x direction */
      for (j=0; j<n-1; j++) {
        for (k=0; k<p-1; k++) {
          if (i==0) AddToFace(face,facecount,3,I/4);
          if (i==m-1) AddToFace(face,facecount,1,I/4);
          c.v[I++] = v.v[(i*n+(j+0))*p+(k+0)];
          c.v[I++] = v.v[(i*n+(j+1))*p+(k+0)];
          c.v[I++] = v.v[(i*n+(j+1))*p+(k+1)];
          c.v[I++] = v.v[(i*n+(j+0))*p+(k+1)];
        }
      }
    }
    if (I != c.s) dERROR(PETSC_COMM_SELF,1, "Wrong number of faces.");
    iMesh_createEntArr(mesh,iMesh_QUADRILATERAL,c.v,c.s,&f.v,&f.a,&f.s,&s.v,&s.a,&s.s,&err);dICHK(mesh,err);
    err = CommitToFaceSets(mesh,f.v,face,facecount,facesets,entbuf);dCHK(err);
    if (verbose > 0) {err = PetscViewerASCIIPrintf(viewer,"face size %d, status size %d\n",f.s,s.s);dCHK(err);}
    MeshListFree(f); MeshListFree(s); MeshListFree(c);
  }

  if (do_edges)
  {
    /* Create edges */
    c.a = c.s = 2*(m*n*(p-1) + m*(n-1)*p + (m-1)*n*p); c.v = malloc(c.a*sizeof(iBase_EntityHandle));
    I = 0;
    for (i=0; i<m; i++) {
      for (j=0; j<n; j++) {
        for (k=0; k<p-1; k++) {
          if (i==0) AddToFace(face,facecount,0,I/2);
          else if (i==m-1) AddToFace(face,facecount,2,I/2);
          else if (j==0) AddToFace(face,facecount,3,I/2);
          else if (j==n-1) AddToFace(face,facecount,1,I/2);
          c.v[I++] = v.v[(i*n+j)*p+(k+0)];
          c.v[I++] = v.v[(i*n+j)*p+(k+1)];
        }
      }
    }
    for (i=0; i<m; i++) {
      for (j=0; j<n-1; j++) {
        for (k=0; k<p; k++) {
          if (i==0) AddToFace(face,facecount,0,I/2);
          else if (i==m-1) AddToFace(face,facecount,2,I/2);
          else if (k==0) AddToFace(face,facecount,4,I/2);
          else if (k==p-1) AddToFace(face,facecount,5,I/2);
          c.v[I++] = v.v[(i*n+(j+0))*p+k];
          c.v[I++] = v.v[(i*n+(j+1))*p+k];
        }
      }
    }
    for (i=0; i<m-1; i++) {
      for (j=0; j<n; j++) {
        for (k=0; k<p; k++) {
          if (j==0) AddToFace(face,facecount,3,I/2);
          else if (j==n-1) AddToFace(face,facecount,1,I/2);
          else if (k==0) AddToFace(face,facecount,4,I/2);
          else if (k==p-1) AddToFace(face,facecount,5,I/2);
          c.v[I++] = v.v[((i+0)*n+j)*p+k];
          c.v[I++] = v.v[((i+1)*n+j)*p+k];
        }
      }
    }
    if (I != c.s) dERROR(PETSC_COMM_SELF,1, "Wrong number of edges.");
    iMesh_createEntArr(mesh,iMesh_LINE_SEGMENT,c.v,c.s, &e.v,&e.a,&e.s, &s.v,&s.a,&s.s,&err);dICHK(mesh,err);
    err = CommitToFaceSets(mesh,e.v,face,facecount,facesets,entbuf);dCHK(err);
    if (verbose > 0) {err = PetscViewerASCIIPrintf(viewer,"edge size %d, status size %d\n",e.s,s.s);dCHK(err);}
    MeshListFree(e); MeshListFree(s); MeshListFree(c);
  }

  /* We are done with the master vertex record. */
  MeshListFree(v);

  /* Create boundary sets, these are not related to geometry here */
  {
    dMeshESH wallset,topset,bottomset,senseSet;
    iBase_TagHandle bdyTag,senseTag;
    iMesh_getTagHandle(mesh,"NEUMANN_SET",&bdyTag,&err,sizeof("NEUMANN_SET"));dICHK(mesh,err);
    iMesh_createTag(mesh,"SENSE",1,iBase_INTEGER,&senseTag,&err,sizeof "SENSE");dICHK(mesh,err);
    iMesh_createEntSet(mesh,0,&wallset,&err);dICHK(mesh,err);
    iMesh_createEntSet(mesh,0,&topset,&err);dICHK(mesh,err);
    iMesh_createEntSet(mesh,0,&bottomset,&err);dICHK(mesh,err);
    iMesh_setEntSetIntData(mesh,wallset,bdyTag,100,&err);dICHK(mesh,err);
    iMesh_setEntSetIntData(mesh,topset,bdyTag,200,&err);dICHK(mesh,err);
    iMesh_setEntSetIntData(mesh,bottomset,bdyTag,300,&err);dICHK(mesh,err);
    for (i=0; i<4; i++) {iMesh_addEntSet(mesh,facesets[i],wallset,&err);dICHK(mesh,err);}
    iMesh_addEntSet(mesh,facesets[5],topset,&err);dICHK(mesh,err);
    iMesh_addEntSet(mesh,facesets[4],bottomset,&err);dICHK(mesh,err);

    /* Deal with SENSE on the walls */
    iMesh_createEntSet(mesh,0,&senseSet,&err);dICHK(mesh,err);
    iMesh_addEntSet(mesh,facesets[2],senseSet,&err);dICHK(mesh,err);
    iMesh_addEntSet(mesh,facesets[3],senseSet,&err);dICHK(mesh,err);
    iMesh_setEntSetIntData(mesh,senseSet,senseTag,-1,&err);dICHK(mesh,err);
    iMesh_addEntSet(mesh,senseSet,wallset,&err);dICHK(mesh,err);

    /* Deal with SENSE on the bottom */
    iMesh_createEntSet(mesh,0,&senseSet,&err);dICHK(mesh,err);
    iMesh_addEntSet(mesh,facesets[4],senseSet,&err);dICHK(mesh,err);
    iMesh_setEntSetIntData(mesh,senseSet,senseTag,-1,&err);dICHK(mesh,err);
    iMesh_addEntSet(mesh,senseSet,bottomset,&err);dICHK(mesh,err);

    for (i=0; i<6; i++) {err = dFree(face[i]);}
    err = dFree(entbuf);dCHK(err);
  }

  if (do_material) {err = doMaterial(mesh,root);dCHK(err);}

  /* Add a real valued tag over the vertices. */
  if (do_pressure) {
    static const char *myTagName = "pressure";
    iBase_TagHandle myTag;
    double *myData;

    iMesh_getEntities(mesh,root,iBase_VERTEX,iMesh_POINT,&v.v,&v.a,&v.s,&err);dICHK(mesh,err);
    iMesh_createTag(mesh,myTagName,1,iBase_DOUBLE,&myTag,&err,(int)strlen(myTagName));dICHK(mesh,err);
    err = PetscMalloc(v.s*sizeof(double),&myData);dCHK(err);
    for (i=0; i<v.s; i++) { myData[i] = 1.0 * i; }
    iMesh_setDblArrData(mesh,v.v,v.s,myTag,myData,v.s,&err);dICHK(mesh,err);
    err = PetscFree(myData);dCHK(err);
    MeshListFree(v);
  }

  if (do_uniform) {err = createUniformTags(mesh,root);dCHK(err);}

  if (do_geom)
#ifndef dHAVE_ITAPS_REL
    dERROR(((dObject)dmesh)->comm,PETSC_ERR_ARG_UNKNOWN_TYPE,"Dohp has not been configured with support for geometry");
#else
  {
    const char geom_options[] = ";ENGINE=OCC;";
    const char rel_options[] = "";
    iGeom_Instance geom;
    iRel_Instance assoc;
    iRel_PairHandle pair;
    iBase_EntityHandle brick;
    iGeom_newGeom(geom_options,&geom,&err,sizeof geom_options);dIGCHK(geom,err);
    iRel_create(rel_options,&assoc,&err,sizeof rel_options);dIRCHK(assoc,err);
    iRel_createPair(assoc,geom,0,iRel_IGEOM_IFACE,iRel_ACTIVE,mesh,1,iRel_IMESH_IFACE,iRel_ACTIVE,&pair,&err);dIGCHK(assoc,err);
    iGeom_createBrick(geom,box.x1-box.x0,box.y1-box.y0,box.z1-box.z0,&brick,&err);dIGCHK(geom,err);
    iGeom_moveEnt(geom,brick,0.5*(box.x0+box.x1),0.5*(box.y0+box.y1),0.5*(box.z0+box.z1),&err);dIGCHK(geom,err);
    if (verbose > 0) {err = BoundingBoxView(geom,brick,"brick",viewer);dCHK(err);}
    {
      iBase_EntityHandle gface[6],*gface_p=gface;
      int gface_a=6,gface_s;
      iGeom_getEntAdj(geom,brick,2,&gface_p,&gface_a,&gface_s,&err);dIGCHK(geom,err);
      for (i=0; i<6; i++) {
        char name[20];
        sprintf(name,"face_%d",i);
        err = BoundingBoxView(geom,gface[i],name,viewer);dCHK(err);
      }
      if (assoc_with_brick) {
        for (i=0; i<6; i++) {
          iRel_setEntSetRelation(assoc,pair,brick,facesets[i],&err);dIRCHK(assoc,err);
        }
      } else {
        /* Set associations.  With the current Lasso implementation, these will not be saved */
        iRel_setEntSetRelation(assoc,pair,gface[0],facesets[3],&err);dIRCHK(assoc,err);
        iRel_setEntSetRelation(assoc,pair,gface[1],facesets[1],&err);dIRCHK(assoc,err);
        iRel_setEntSetRelation(assoc,pair,gface[2],facesets[0],&err);dIRCHK(assoc,err);
        iRel_setEntSetRelation(assoc,pair,gface[3],facesets[2],&err);dIRCHK(assoc,err);
        iRel_setEntSetRelation(assoc,pair,gface[4],facesets[4],&err);dIRCHK(assoc,err);
        iRel_setEntSetRelation(assoc,pair,gface[5],facesets[5],&err);dIRCHK(assoc,err);
      }
    }
    {
      dMeshTag meshGlobalIDTag,meshGeomDimTag,geomGlobalIDTag;
      /* Manually set association tags, these are set so that the associations above can be inferred. */
      iMesh_getTagHandle(mesh,"GLOBAL_ID",&meshGlobalIDTag,&err,sizeof "GLOBAL_ID");dICHK(mesh,err);
      iMesh_getTagHandle(mesh,"GEOM_DIMENSION",&meshGeomDimTag,&err,sizeof "GEOM_DIMENSION");dICHK(mesh,err);
      iGeom_getTagHandle(geom,"GLOBAL_ID",&geomGlobalIDTag,&err,sizeof "GLOBAL_ID");dIGCHK(geom,err);
      for (i=0; i<6; i++) {
        iBase_EntityHandle gface;
        int gid,gdim;
        iRel_getSetEntRelation(assoc,pair,facesets[i],1,&gface,&err);dIRCHK(assoc,err);
        iGeom_getEntType(geom,gface,&gdim,&err);dIGCHK(geom,err);
        if (gdim != 2) dERROR(PETSC_COMM_SELF,1,"Geometric dimension is %d, expected 2",gdim);
        iGeom_getIntData(geom,gface,geomGlobalIDTag,&gid,&err);dIGCHK(geom,err);
        iMesh_setEntSetIntData(mesh,facesets[i],meshGeomDimTag,2,&err);dICHK(mesh,err);
        /* If the following line is disabled, Lasso will pick up the wrong relations, but at least they will still be with
        * surfaces.  Wouldn't it be better to not find relations? */
        iMesh_setEntSetIntData(mesh,facesets[i],meshGlobalIDTag,gid,&err);dICHK(mesh,err);
      }
    }
    err = dMeshSetGeometryRelation(dmesh,geom,assoc);dCHK(err);
  }
#endif
  dFunctionReturn(0);
}
Example #15
0
/** dFSRedimension - Create a new function space with the same layout, but different number of dofs per node
 *
 */
dErr dFSRedimension(dFS fs,dInt bs,dFSClosureMode mode,dFS *infs)
{
    dErr err;
    dFS rfs;
    dJacobi jac;

    dFunctionBegin;
    dValidHeader(fs,DM_CLASSID,1);
    if (bs < 1) dERROR(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Block size must be at least 1, was %D",bs);
    dValidPointer(infs,4);
    *infs = NULL;

    if (!fs->spacebuilt) dERROR(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Cannot redimension a space that has not been built");
    if (!fs->mesh || !fs->set.active) dERROR(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Space has been built, but does not have a mesh (should not happen)");

    err = dFSCreate(((dObject)fs)->comm,&rfs);
    dCHK(err);
    err = dFSSetBlockSize(rfs,bs);
    dCHK(err);
    err = dFSSetMesh(rfs,fs->mesh,fs->set.active);
    dCHK(err);
    err = dFSGetJacobi(fs,&jac);
    dCHK(err);
    err = dFSSetDegree(rfs,jac,fs->tag.degree);
    dCHK(err);
    switch (mode) {
    case dFS_CLOSURE:
        dERROR(PETSC_COMM_SELF,PETSC_ERR_SUP,"Probably not what you want"); /* because ordering would be different, but there is nothing to do for this choice. */
        break;
    case dFS_INTERIOR: {
        dMeshESH *bsets;
        dInt nsets;
        err = dMeshGetNumSubsets(fs->mesh,fs->set.boundaries,0,&nsets);
        dCHK(err);
        err = dMallocA(nsets,&bsets);
        dCHK(err);
        err = dMeshGetSubsets(fs->mesh,fs->set.boundaries,0,bsets,nsets,NULL);
        dCHK(err);
        for (dInt i=0; i<nsets; i++) {
            dFSBStatus bstat;
            err = dMeshTagSGetData(fs->mesh,fs->tag.bstatus,&bsets[i],1,&bstat,sizeof(bstat),dDATA_BYTE);
            dCHK(err);
            err = dFSRegisterBoundarySet(rfs,bsets[i],bstat,NULL,NULL);
            dCHK(err); /* TODO: handle dFSConstraintCtx */
        }
        err = dFree(bsets);
        dCHK(err);
    }
    break;
    default:
        dERROR(PETSC_COMM_SELF,PETSC_ERR_SUP,"No support for dFSClosureMode %s",dFSClosureModes[mode]);
    }
    err = dFSSetType(rfs,((dObject)fs)->type_name);
    dCHK(err);
    err = dFSSetOrderingType(rfs,fs->orderingtype);
    dCHK(err);
    rfs->set.ordered = fs->set.ordered;
    {   // The FS has the layout, ordering, and boundary status tags set so we are ready to build the function space.
        dMesh          mesh;
        dMeshAdjacency meshadj;

        err = dFSGetMesh(rfs,&mesh);
        dCHK(err);
        err = dMeshGetAdjacency(mesh,rfs->set.ordered,&meshadj);
        dCHK(err);
        err = dFSPopulatePartitionedSets_Private(rfs,meshadj);
        dCHK(err);
        err = dFSBuildSpaceWithOrderedSet_Private(rfs,meshadj);
        dCHK(err);
        err = dMeshRestoreAdjacency(mesh,rfs->set.ordered,&meshadj);
        dCHK(err);
    }

    *infs = rfs;
    dFunctionReturn(0);
}
Example #16
0
static dErr dFSCreateGeometryFromMesh_Private(dFS fs)
{
    dErr err;
    dMesh mesh;
    dJacobi jacobi;
    dMeshEH *ents;
    dEntTopology *topo;
    const dInt *offset;
    const dReal *rcoords;
    dScalar *x;
    dInt nents,n;
    dFS cfs;
    Vec Expanded,Global,Count;

    dFunctionBegin;
    err = dFSGetMesh(fs,&mesh);
    dCHK(err);
    err = dFSGetJacobi(fs,&jacobi);
    dCHK(err);
    err = dFSGetCoordinateFS(fs,&cfs);
    dCHK(err);
    err = dFSCreateExpandedVector(cfs,&Expanded);
    dCHK(err);
    err = dFSCreateGlobalVector(cfs,&Global);
    dCHK(err);
    err = VecDuplicate(Global,&Count);
    dCHK(err);

    /* Count the number of elements in which each node appears */
    err = VecSet(Expanded,1.);
    dCHK(err);
    err = VecZeroEntries(Count);
    dCHK(err);
    err = dFSExpandedToGlobal(cfs,Expanded,Count,dFS_HOMOGENEOUS,ADD_VALUES);
    dCHK(err);

    /* Populate \a Expanded with local coordinates from mesh */
    err = dMeshGetNumEnts(mesh,fs->set.active,dTYPE_REGION,dTOPO_ALL,&nents);
    dCHK(err);
    err = dMallocA2(nents,&ents,nents,&topo);
    dCHK(err);
    err = dMeshGetEnts(mesh,fs->set.active,dTYPE_REGION,dTOPO_ALL,ents,nents,NULL);
    dCHK(err);
    err = dMeshGetTopo(mesh,nents,ents,topo);
    dCHK(err);
    err = dMeshGetAdjVertexCoords(mesh,nents,ents,&offset,&rcoords);
    dCHK(err);
    err = VecGetLocalSize(Expanded,&n);
    dCHK(err);
    if (n != 3*offset[nents]) dERROR(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Size of Expanded %D does not match offset %D",n,3*offset[nents]);
    err = VecGetArray(Expanded,&x);
    dCHK(err);
    for (dInt e=0,k=0; e<nents; e++) {
        switch (topo[e]) {
        case dTOPO_HEX:
            for (dInt i=0; i<8; i++) {
                static const dInt connidx[8] = {0,4,3,7,1,5,2,6}; /* FIXME: generalize this */
                for (dInt j=0; j<3; j++) x[k++] = rcoords[(offset[e]+connidx[i])*3+j];
            }
            break;
        default:
            dERROR(PETSC_COMM_SELF,PETSC_ERR_SUP,"No support for topology %s",dMeshEntTopologyName(topo[e]));
        }
    }
    err = VecRestoreArray(Expanded,&x);
    dCHK(err);
    err = dMeshRestoreAdjVertexCoords(mesh,nents,ents,&offset,&rcoords);
    dCHK(err);
    err = dFree2(ents,topo);
    dCHK(err);

    /* Populate \a Global with the average coordinates from all the elements whose closure contains the node */
    err = dFSExpandedToGlobal(cfs,Expanded,Global,dFS_INHOMOGENEOUS,ADD_VALUES);
    dCHK(err);
    err = VecPointwiseDivide(Global,Global,Count);
    dCHK(err);
    err = VecDestroy(&Count);
    dCHK(err);

    fs->geometry.expanded = Expanded;
    fs->geometry.global   = Global;
    dFunctionReturn(0);
}
Example #17
0
/** Apply rotation to local vector
*
* @note does nothing if rotation is NULL
**/
dErr dFSRotationApplyLocal(dFSRotation rot,Vec l,dFSRotateMode rmode,dFSHomogeneousMode hmode)
{
  dErr err;

  dFunctionBegin;
  if (!rot) dFunctionReturn(0);
  dValidHeader(rot,dFSROT_CLASSID,1);
  dValidHeader(l,VEC_CLASSID,2);
  if (rot->ops->applylocal) {
    err = rot->ops->applylocal(rot,l,rmode,hmode);dCHK(err);
  } else {
    const dInt *idx,bs = rot->bs;
    const dScalar *s;
    dScalar *v,*strong;
    dScalar tmp[16];

    if (bs > 16) dERROR(PETSC_COMM_SELF,1,"large block size");
    err = ISGetIndices(rot->is,&idx);dCHK(err);
    err = VecGetArray(l,&v);dCHK(err);
    if (hmode == dFS_INHOMOGENEOUS) {
      err = VecGetArray(rot->strong,&strong);dCHK(err);
      s = strong;
    } else { s = 0; }
    for (dInt i=0; i<rot->n; i++) {
      const dInt ii = idx[i];
      const dReal *rmat = &rot->rmat[ii*bs*bs];
      for (dInt j=0; j<bs; j++) {
        tmp[j] = v[ii*bs+j];
        v[ii*bs+j] = 0;
      }
      switch (rmode) {
        case dFS_ROTATE_FORWARD:
          for (dInt j=0; j<bs; j++) {
            for (dInt k=0; k<bs; k++) {
              v[ii*bs+k] += rmat[k*bs+j] * tmp[j];
            }
          }
          switch (hmode) {
            case dFS_HOMOGENEOUS:   for (dInt j=0; j<s[i]; j++) v[ii*bs+j] = 0;    break;
            case dFS_INHOMOGENEOUS: for (dInt j=0; j<s[i]; j++) v[ii*bs+j] = *s++; break;
            default: dERROR(PETSC_COMM_SELF,1,"Invalid homogeneous mode");
          }
          break;
        case dFS_ROTATE_REVERSE:
          switch (hmode) {
            case dFS_HOMOGENEOUS:   for (dInt j=0; j<s[i]; j++) tmp[j] = 0;    break;
            case dFS_INHOMOGENEOUS: for (dInt j=0; j<s[i]; j++) tmp[j] = *s++; break;
            default: dERROR(PETSC_COMM_SELF,1,"Invalid homogeneous mode");
          }
          for (dInt j=0; j<bs; j++) {
            for (dInt k=0; k<bs; k++) {
              v[ii*bs+k] += rmat[j*bs+k] * tmp[k];
            }
          }
          break;
        default: dERROR(PETSC_COMM_SELF,1,"Invalid rotate mode");
      }
    }
    err = ISRestoreIndices(rot->is,&idx);dCHK(err);
    err = VecRestoreArray(l,&v);dCHK(err);
    if (hmode == dFS_HOMOGENEOUS) {
      dInt n;
      err = VecGetSize(rot->strong,&n);dCHK(err);
      if (s-strong != n) dERROR(PETSC_COMM_SELF,1,"should not happen");
      err = VecRestoreArray(rot->strong,&strong);dCHK(err);
    }
  }
  dFunctionReturn(0);
}