예제 #1
0
/*@
   ISEmbed   -   embed IS a into IS b by finding the locations in b that have the same indices as in a.
                 If c is the IS of these locations, we have a = b*c, regarded as a composition of the
                 corresponding ISLocalToGlobalMaps.

  Not collective.

  Input arguments:
+ a    -  IS to embed
. b    -  IS to embed into
- drop -  flag indicating whether to drop a's indices that are not in b.

  Output arguments:
. c    -  local embedding indices

  Note:
  If some of a's global indices are not among b's indices the embedding is impossible.  The local indices of a
  corresponding to these global indices are either mapped to -1 (if !drop) or are omitted (if drop).  In the former
  case the size of c is that same as that of a, in the latter case c's size may be smaller.

  The resulting IS is sequential, since the index substition it encodes is purely local.

  Level: advanced

.seealso ISLocalToGlobalMapping
 @*/
PetscErrorCode ISEmbed(IS a, IS b, PetscBool drop, IS *c)
{
  PetscErrorCode             ierr;
  ISLocalToGlobalMapping     ltog;
  ISGlobalToLocalMappingType gtoltype = IS_GTOLM_DROP;
  PetscInt                   alen, clen, *cindices, *cindices2;
  const PetscInt             *aindices;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(a, IS_CLASSID, 1);
  PetscValidHeaderSpecific(b, IS_CLASSID, 2);
  PetscValidPointer(c,4);
  ierr = ISLocalToGlobalMappingCreateIS(b, &ltog);CHKERRQ(ierr);
  ierr = ISGetLocalSize(a, &alen);CHKERRQ(ierr);
  ierr = ISGetIndices(a, &aindices);CHKERRQ(ierr);
  ierr = PetscMalloc1(alen, &cindices);CHKERRQ(ierr);
  if (!drop) gtoltype = IS_GTOLM_MASK;
  ierr = ISGlobalToLocalMappingApply(ltog,gtoltype,alen,aindices,&clen,cindices);CHKERRQ(ierr);
  ierr = ISLocalToGlobalMappingDestroy(&ltog);CHKERRQ(ierr);
  if (clen != alen) {
    cindices2 = cindices;
    ierr      = PetscMalloc1(clen, &cindices);CHKERRQ(ierr);
    ierr      = PetscMemcpy(cindices,cindices2,clen*sizeof(PetscInt));CHKERRQ(ierr);
    ierr      = PetscFree(cindices2);CHKERRQ(ierr);
  }
  ierr = ISCreateGeneral(PETSC_COMM_SELF,clen,cindices,PETSC_OWN_POINTER,c);CHKERRQ(ierr);
  PetscFunctionReturn(0);
}
예제 #2
0
PetscErrorCode  DMSetUp_DA_2D(DM da)
{
    DM_DA            *dd = (DM_DA*)da->data;
    const PetscInt   M            = dd->M;
    const PetscInt   N            = dd->N;
    PetscInt         m            = dd->m;
    PetscInt         n            = dd->n;
    const PetscInt   dof          = dd->w;
    const PetscInt   s            = dd->s;
    DMDABoundaryType bx           = dd->bx;
    DMDABoundaryType by           = dd->by;
    DMDAStencilType  stencil_type = dd->stencil_type;
    PetscInt         *lx          = dd->lx;
    PetscInt         *ly          = dd->ly;
    MPI_Comm         comm;
    PetscMPIInt      rank,size;
    PetscInt         xs,xe,ys,ye,x,y,Xs,Xe,Ys,Ye,start,end,IXs,IXe,IYs,IYe;
    PetscInt         up,down,left,right,i,n0,n1,n2,n3,n5,n6,n7,n8,*idx,nn,*idx_cpy;
    const PetscInt   *idx_full;
    PetscInt         xbase,*bases,*ldims,j,x_t,y_t,s_t,base,count;
    PetscInt         s_x,s_y; /* s proportionalized to w */
    PetscInt         sn0 = 0,sn2 = 0,sn6 = 0,sn8 = 0;
    Vec              local,global;
    VecScatter       ltog,gtol;
    IS               to,from,ltogis;
    PetscErrorCode   ierr;

    PetscFunctionBegin;
    if (stencil_type == DMDA_STENCIL_BOX && (bx == DMDA_BOUNDARY_MIRROR || by == DMDA_BOUNDARY_MIRROR)) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_SUP,"Mirror boundary and box stencil");
    ierr = PetscObjectGetComm((PetscObject)da,&comm);
    CHKERRQ(ierr);
#if !defined(PETSC_USE_64BIT_INDICES)
    if (((Petsc64bitInt) M)*((Petsc64bitInt) N)*((Petsc64bitInt) dof) > (Petsc64bitInt) PETSC_MPI_INT_MAX) SETERRQ3(comm,PETSC_ERR_INT_OVERFLOW,"Mesh of %D by %D by %D (dof) is too large for 32 bit indices",M,N,dof);
#endif

    if (dof < 1) SETERRQ1(comm,PETSC_ERR_ARG_OUTOFRANGE,"Must have 1 or more degrees of freedom per node: %D",dof);
    if (s < 0) SETERRQ1(comm,PETSC_ERR_ARG_OUTOFRANGE,"Stencil width cannot be negative: %D",s);

    ierr = MPI_Comm_size(comm,&size);
    CHKERRQ(ierr);
    ierr = MPI_Comm_rank(comm,&rank);
    CHKERRQ(ierr);

    if (m != PETSC_DECIDE) {
        if (m < 1) SETERRQ1(comm,PETSC_ERR_ARG_OUTOFRANGE,"Non-positive number of processors in X direction: %D",m);
        else if (m > size) SETERRQ2(comm,PETSC_ERR_ARG_OUTOFRANGE,"Too many processors in X direction: %D %d",m,size);
    }
    if (n != PETSC_DECIDE) {
        if (n < 1) SETERRQ1(comm,PETSC_ERR_ARG_OUTOFRANGE,"Non-positive number of processors in Y direction: %D",n);
        else if (n > size) SETERRQ2(comm,PETSC_ERR_ARG_OUTOFRANGE,"Too many processors in Y direction: %D %d",n,size);
    }

    if (m == PETSC_DECIDE || n == PETSC_DECIDE) {
        if (n != PETSC_DECIDE) {
            m = size/n;
        } else if (m != PETSC_DECIDE) {
            n = size/m;
        } else {
            /* try for squarish distribution */
            m = (PetscInt)(0.5 + PetscSqrtReal(((PetscReal)M)*((PetscReal)size)/((PetscReal)N)));
            if (!m) m = 1;
            while (m > 0) {
                n = size/m;
                if (m*n == size) break;
                m--;
            }
            if (M > N && m < n) {
                PetscInt _m = m;
                m = n;
                n = _m;
            }
        }
        if (m*n != size) SETERRQ(comm,PETSC_ERR_PLIB,"Unable to create partition, check the size of the communicator and input m and n ");
    } else if (m*n != size) SETERRQ(comm,PETSC_ERR_ARG_OUTOFRANGE,"Given Bad partition");

    if (M < m) SETERRQ2(comm,PETSC_ERR_ARG_OUTOFRANGE,"Partition in x direction is too fine! %D %D",M,m);
    if (N < n) SETERRQ2(comm,PETSC_ERR_ARG_OUTOFRANGE,"Partition in y direction is too fine! %D %D",N,n);

    /*
       Determine locally owned region
       xs is the first local node number, x is the number of local nodes
    */
    if (!lx) {
        ierr = PetscMalloc(m*sizeof(PetscInt), &dd->lx);
        CHKERRQ(ierr);
        lx   = dd->lx;
        for (i=0; i<m; i++) {
            lx[i] = M/m + ((M % m) > i);
        }
    }
    x  = lx[rank % m];
    xs = 0;
    for (i=0; i<(rank % m); i++) {
        xs += lx[i];
    }
#if defined(PETSC_USE_DEBUG)
    left = xs;
    for (i=(rank % m); i<m; i++) {
        left += lx[i];
    }
    if (left != M) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Sum of lx across processors not equal to M: %D %D",left,M);
#endif

    /*
       Determine locally owned region
       ys is the first local node number, y is the number of local nodes
    */
    if (!ly) {
        ierr = PetscMalloc(n*sizeof(PetscInt), &dd->ly);
        CHKERRQ(ierr);
        ly   = dd->ly;
        for (i=0; i<n; i++) {
            ly[i] = N/n + ((N % n) > i);
        }
    }
    y  = ly[rank/m];
    ys = 0;
    for (i=0; i<(rank/m); i++) {
        ys += ly[i];
    }
#if defined(PETSC_USE_DEBUG)
    left = ys;
    for (i=(rank/m); i<n; i++) {
        left += ly[i];
    }
    if (left != N) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Sum of ly across processors not equal to N: %D %D",left,N);
#endif

    /*
     check if the scatter requires more than one process neighbor or wraps around
     the domain more than once
    */
    if ((x < s) && ((m > 1) || (bx == DMDA_BOUNDARY_PERIODIC))) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Local x-width of domain x %D is smaller than stencil width s %D",x,s);
    if ((y < s) && ((n > 1) || (by == DMDA_BOUNDARY_PERIODIC))) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Local y-width of domain y %D is smaller than stencil width s %D",y,s);
    xe = xs + x;
    ye = ys + y;

    /* determine ghost region (Xs) and region scattered into (IXs)  */
    if (xs-s > 0) {
        Xs = xs - s;
        IXs = xs - s;
    } else {
        if (bx) {
            Xs = xs - s;
        } else {
            Xs = 0;
        }
        IXs = 0;
    }
    if (xe+s <= M) {
        Xe = xe + s;
        IXe = xe + s;
    } else {
        if (bx) {
            Xs = xs - s;
            Xe = xe + s;
        } else {
            Xe = M;
        }
        IXe = M;
    }

    if (bx == DMDA_BOUNDARY_PERIODIC || bx == DMDA_BOUNDARY_MIRROR) {
        IXs = xs - s;
        IXe = xe + s;
        Xs  = xs - s;
        Xe  = xe + s;
    }

    if (ys-s > 0) {
        Ys = ys - s;
        IYs = ys - s;
    } else {
        if (by) {
            Ys = ys - s;
        } else {
            Ys = 0;
        }
        IYs = 0;
    }
    if (ye+s <= N) {
        Ye = ye + s;
        IYe = ye + s;
    } else {
        if (by) {
            Ye = ye + s;
        } else {
            Ye = N;
        }
        IYe = N;
    }

    if (by == DMDA_BOUNDARY_PERIODIC || by == DMDA_BOUNDARY_MIRROR) {
        IYs = ys - s;
        IYe = ye + s;
        Ys  = ys - s;
        Ye  = ye + s;
    }

    /* stencil length in each direction */
    s_x = s;
    s_y = s;

    /* determine starting point of each processor */
    nn       = x*y;
    ierr     = PetscMalloc2(size+1,PetscInt,&bases,size,PetscInt,&ldims);
    CHKERRQ(ierr);
    ierr     = MPI_Allgather(&nn,1,MPIU_INT,ldims,1,MPIU_INT,comm);
    CHKERRQ(ierr);
    bases[0] = 0;
    for (i=1; i<=size; i++) {
        bases[i] = ldims[i-1];
    }
    for (i=1; i<=size; i++) {
        bases[i] += bases[i-1];
    }
    base = bases[rank]*dof;

    /* allocate the base parallel and sequential vectors */
    dd->Nlocal = x*y*dof;
    ierr       = VecCreateMPIWithArray(comm,dof,dd->Nlocal,PETSC_DECIDE,0,&global);
    CHKERRQ(ierr);
    dd->nlocal = (Xe-Xs)*(Ye-Ys)*dof;
    ierr       = VecCreateSeqWithArray(PETSC_COMM_SELF,dof,dd->nlocal,0,&local);
    CHKERRQ(ierr);

    /* generate appropriate vector scatters */
    /* local to global inserts non-ghost point region into global */
    ierr = VecGetOwnershipRange(global,&start,&end);
    CHKERRQ(ierr);
    ierr = ISCreateStride(comm,x*y*dof,start,1,&to);
    CHKERRQ(ierr);

    ierr  = PetscMalloc(x*y*sizeof(PetscInt),&idx);
    CHKERRQ(ierr);
    left  = xs - Xs;
    right = left + x;
    down  = ys - Ys;
    up = down + y;
    count = 0;
    for (i=down; i<up; i++) {
        for (j=left; j<right; j++) {
            idx[count++] = i*(Xe-Xs) + j;
        }
    }

    ierr = ISCreateBlock(comm,dof,count,idx,PETSC_OWN_POINTER,&from);
    CHKERRQ(ierr);
    ierr = VecScatterCreate(local,from,global,to,&ltog);
    CHKERRQ(ierr);
    ierr = PetscLogObjectParent(dd,ltog);
    CHKERRQ(ierr);
    ierr = ISDestroy(&from);
    CHKERRQ(ierr);
    ierr = ISDestroy(&to);
    CHKERRQ(ierr);

    /* global to local must include ghost points within the domain,
       but not ghost points outside the domain that aren't periodic */
    if (stencil_type == DMDA_STENCIL_BOX) {
        count = (IXe-IXs)*(IYe-IYs);
        ierr  = PetscMalloc(count*sizeof(PetscInt),&idx);
        CHKERRQ(ierr);

        left  = IXs - Xs;
        right = left + (IXe-IXs);
        down  = IYs - Ys;
        up = down + (IYe-IYs);
        count = 0;
        for (i=down; i<up; i++) {
            for (j=left; j<right; j++) {
                idx[count++] = j + i*(Xe-Xs);
            }
        }
        ierr = ISCreateBlock(comm,dof,count,idx,PETSC_OWN_POINTER,&to);
        CHKERRQ(ierr);

    } else {
        /* must drop into cross shape region */
        /*       ---------|
                |  top    |
             |---         ---| up
             |   middle      |
             |               |
             ----         ---- down
                | bottom  |
                -----------
             Xs xs        xe Xe */
        count = (ys-IYs)*x + y*(IXe-IXs) + (IYe-ye)*x;
        ierr  = PetscMalloc(count*sizeof(PetscInt),&idx);
        CHKERRQ(ierr);

        left  = xs - Xs;
        right = left + x;
        down  = ys - Ys;
        up = down + y;
        count = 0;
        /* bottom */
        for (i=(IYs-Ys); i<down; i++) {
            for (j=left; j<right; j++) {
                idx[count++] = j + i*(Xe-Xs);
            }
        }
        /* middle */
        for (i=down; i<up; i++) {
            for (j=(IXs-Xs); j<(IXe-Xs); j++) {
                idx[count++] = j + i*(Xe-Xs);
            }
        }
        /* top */
        for (i=up; i<up+IYe-ye; i++) {
            for (j=left; j<right; j++) {
                idx[count++] = j + i*(Xe-Xs);
            }
        }
        ierr = ISCreateBlock(comm,dof,count,idx,PETSC_OWN_POINTER,&to);
        CHKERRQ(ierr);
    }


    /* determine who lies on each side of us stored in    n6 n7 n8
                                                          n3    n5
                                                          n0 n1 n2
    */

    /* Assume the Non-Periodic Case */
    n1 = rank - m;
    if (rank % m) {
        n0 = n1 - 1;
    } else {
        n0 = -1;
    }
    if ((rank+1) % m) {
        n2 = n1 + 1;
        n5 = rank + 1;
        n8 = rank + m + 1;
        if (n8 >= m*n) n8 = -1;
    } else {
        n2 = -1;
        n5 = -1;
        n8 = -1;
    }
    if (rank % m) {
        n3 = rank - 1;
        n6 = n3 + m;
        if (n6 >= m*n) n6 = -1;
    } else {
        n3 = -1;
        n6 = -1;
    }
    n7 = rank + m;
    if (n7 >= m*n) n7 = -1;

    if (bx == DMDA_BOUNDARY_PERIODIC && by == DMDA_BOUNDARY_PERIODIC) {
        /* Modify for Periodic Cases */
        /* Handle all four corners */
        if ((n6 < 0) && (n7 < 0) && (n3 < 0)) n6 = m-1;
        if ((n8 < 0) && (n7 < 0) && (n5 < 0)) n8 = 0;
        if ((n2 < 0) && (n5 < 0) && (n1 < 0)) n2 = size-m;
        if ((n0 < 0) && (n3 < 0) && (n1 < 0)) n0 = size-1;

        /* Handle Top and Bottom Sides */
        if (n1 < 0) n1 = rank + m * (n-1);
        if (n7 < 0) n7 = rank - m * (n-1);
        if ((n3 >= 0) && (n0 < 0)) n0 = size - m + rank - 1;
        if ((n3 >= 0) && (n6 < 0)) n6 = (rank%m)-1;
        if ((n5 >= 0) && (n2 < 0)) n2 = size - m + rank + 1;
        if ((n5 >= 0) && (n8 < 0)) n8 = (rank%m)+1;

        /* Handle Left and Right Sides */
        if (n3 < 0) n3 = rank + (m-1);
        if (n5 < 0) n5 = rank - (m-1);
        if ((n1 >= 0) && (n0 < 0)) n0 = rank-1;
        if ((n1 >= 0) && (n2 < 0)) n2 = rank-2*m+1;
        if ((n7 >= 0) && (n6 < 0)) n6 = rank+2*m-1;
        if ((n7 >= 0) && (n8 < 0)) n8 = rank+1;
    } else if (by == DMDA_BOUNDARY_PERIODIC) {  /* Handle Top and Bottom Sides */
        if (n1 < 0) n1 = rank + m * (n-1);
        if (n7 < 0) n7 = rank - m * (n-1);
        if ((n3 >= 0) && (n0 < 0)) n0 = size - m + rank - 1;
        if ((n3 >= 0) && (n6 < 0)) n6 = (rank%m)-1;
        if ((n5 >= 0) && (n2 < 0)) n2 = size - m + rank + 1;
        if ((n5 >= 0) && (n8 < 0)) n8 = (rank%m)+1;
    } else if (bx == DMDA_BOUNDARY_PERIODIC) { /* Handle Left and Right Sides */
        if (n3 < 0) n3 = rank + (m-1);
        if (n5 < 0) n5 = rank - (m-1);
        if ((n1 >= 0) && (n0 < 0)) n0 = rank-1;
        if ((n1 >= 0) && (n2 < 0)) n2 = rank-2*m+1;
        if ((n7 >= 0) && (n6 < 0)) n6 = rank+2*m-1;
        if ((n7 >= 0) && (n8 < 0)) n8 = rank+1;
    }

    ierr = PetscMalloc(9*sizeof(PetscInt),&dd->neighbors);
    CHKERRQ(ierr);

    dd->neighbors[0] = n0;
    dd->neighbors[1] = n1;
    dd->neighbors[2] = n2;
    dd->neighbors[3] = n3;
    dd->neighbors[4] = rank;
    dd->neighbors[5] = n5;
    dd->neighbors[6] = n6;
    dd->neighbors[7] = n7;
    dd->neighbors[8] = n8;

    if (stencil_type == DMDA_STENCIL_STAR) {
        /* save corner processor numbers */
        sn0 = n0;
        sn2 = n2;
        sn6 = n6;
        sn8 = n8;
        n0  = n2 = n6 = n8 = -1;
    }

    ierr = PetscMalloc((Xe-Xs)*(Ye-Ys)*sizeof(PetscInt),&idx);
    CHKERRQ(ierr);
    ierr = PetscLogObjectMemory(da,(Xe-Xs)*(Ye-Ys)*sizeof(PetscInt));
    CHKERRQ(ierr);

    nn = 0;
    xbase = bases[rank];
    for (i=1; i<=s_y; i++) {
        if (n0 >= 0) { /* left below */
            x_t = lx[n0 % m];
            y_t = ly[(n0/m)];
            s_t = bases[n0] + x_t*y_t - (s_y-i)*x_t - s_x;
            for (j=0; j<s_x; j++) idx[nn++] = s_t++;
        }

        if (n1 >= 0) { /* directly below */
            x_t = x;
            y_t = ly[(n1/m)];
            s_t = bases[n1] + x_t*y_t - (s_y+1-i)*x_t;
            for (j=0; j<x_t; j++) idx[nn++] = s_t++;
        } else if (by == DMDA_BOUNDARY_MIRROR) {
            for (j=0; j<x; j++) idx[nn++] = bases[rank] + x*(s_y - i + 1)  + j;
        }

        if (n2 >= 0) { /* right below */
            x_t = lx[n2 % m];
            y_t = ly[(n2/m)];
            s_t = bases[n2] + x_t*y_t - (s_y+1-i)*x_t;
            for (j=0; j<s_x; j++) idx[nn++] = s_t++;
        }
    }

    for (i=0; i<y; i++) {
        if (n3 >= 0) { /* directly left */
            x_t = lx[n3 % m];
            /* y_t = y; */
            s_t = bases[n3] + (i+1)*x_t - s_x;
            for (j=0; j<s_x; j++) idx[nn++] = s_t++;
        } else if (bx == DMDA_BOUNDARY_MIRROR) {
            for (j=0; j<s_x; j++) idx[nn++] = bases[rank] + x*i + s_x - j;
        }

        for (j=0; j<x; j++) idx[nn++] = xbase++; /* interior */

        if (n5 >= 0) { /* directly right */
            x_t = lx[n5 % m];
            /* y_t = y; */
            s_t = bases[n5] + (i)*x_t;
            for (j=0; j<s_x; j++) idx[nn++] = s_t++;
        } else if (bx == DMDA_BOUNDARY_MIRROR) {
            for (j=0; j<s_x; j++) idx[nn++] = bases[rank] + x*(i + 1) - 2 - j;
        }
    }

    for (i=1; i<=s_y; i++) {
        if (n6 >= 0) { /* left above */
            x_t = lx[n6 % m];
            /* y_t = ly[(n6/m)]; */
            s_t = bases[n6] + (i)*x_t - s_x;
            for (j=0; j<s_x; j++) idx[nn++] = s_t++;
        }

        if (n7 >= 0) { /* directly above */
            x_t = x;
            /* y_t = ly[(n7/m)]; */
            s_t = bases[n7] + (i-1)*x_t;
            for (j=0; j<x_t; j++) idx[nn++] = s_t++;
        } else if (by == DMDA_BOUNDARY_MIRROR) {
            for (j=0; j<x; j++) idx[nn++] = bases[rank] + x*(y - i - 1)  + j;
        }

        if (n8 >= 0) { /* right above */
            x_t = lx[n8 % m];
            /* y_t = ly[(n8/m)]; */
            s_t = bases[n8] + (i-1)*x_t;
            for (j=0; j<s_x; j++) idx[nn++] = s_t++;
        }
    }

    ierr = ISCreateBlock(comm,dof,nn,idx,PETSC_COPY_VALUES,&from);
    CHKERRQ(ierr);
    ierr = VecScatterCreate(global,from,local,to,&gtol);
    CHKERRQ(ierr);
    ierr = PetscLogObjectParent(da,gtol);
    CHKERRQ(ierr);
    ierr = ISDestroy(&to);
    CHKERRQ(ierr);
    ierr = ISDestroy(&from);
    CHKERRQ(ierr);

    if (stencil_type == DMDA_STENCIL_STAR) {
        n0 = sn0;
        n2 = sn2;
        n6 = sn6;
        n8 = sn8;
    }

    if (((stencil_type == DMDA_STENCIL_STAR)  ||
            (bx && bx != DMDA_BOUNDARY_PERIODIC) ||
            (by && by != DMDA_BOUNDARY_PERIODIC))) {
        /*
            Recompute the local to global mappings, this time keeping the
          information about the cross corner processor numbers and any ghosted
          but not periodic indices.
        */
        nn    = 0;
        xbase = bases[rank];
        for (i=1; i<=s_y; i++) {
            if (n0 >= 0) { /* left below */
                x_t = lx[n0 % m];
                y_t = ly[(n0/m)];
                s_t = bases[n0] + x_t*y_t - (s_y-i)*x_t - s_x;
                for (j=0; j<s_x; j++) idx[nn++] = s_t++;
            } else if (xs-Xs > 0 && ys-Ys > 0) {
                for (j=0; j<s_x; j++) idx[nn++] = -1;
            }
            if (n1 >= 0) { /* directly below */
                x_t = x;
                y_t = ly[(n1/m)];
                s_t = bases[n1] + x_t*y_t - (s_y+1-i)*x_t;
                for (j=0; j<x_t; j++) idx[nn++] = s_t++;
            } else if (ys-Ys > 0) {
                if (by == DMDA_BOUNDARY_MIRROR) {
                    for (j=0; j<x; j++) idx[nn++] = bases[rank] + x*(s_y - i + 1)  + j;
                } else {
                    for (j=0; j<x; j++) idx[nn++] = -1;
                }
            }
            if (n2 >= 0) { /* right below */
                x_t = lx[n2 % m];
                y_t = ly[(n2/m)];
                s_t = bases[n2] + x_t*y_t - (s_y+1-i)*x_t;
                for (j=0; j<s_x; j++) idx[nn++] = s_t++;
            } else if (Xe-xe> 0 && ys-Ys > 0) {
                for (j=0; j<s_x; j++) idx[nn++] = -1;
            }
        }

        for (i=0; i<y; i++) {
            if (n3 >= 0) { /* directly left */
                x_t = lx[n3 % m];
                /* y_t = y; */
                s_t = bases[n3] + (i+1)*x_t - s_x;
                for (j=0; j<s_x; j++) idx[nn++] = s_t++;
            } else if (xs-Xs > 0) {
                if (bx == DMDA_BOUNDARY_MIRROR) {
                    for (j=0; j<s_x; j++) idx[nn++] = bases[rank] + x*i + s_x - j;
                } else {
                    for (j=0; j<s_x; j++) idx[nn++] = -1;
                }
            }

            for (j=0; j<x; j++) idx[nn++] = xbase++; /* interior */

            if (n5 >= 0) { /* directly right */
                x_t = lx[n5 % m];
                /* y_t = y; */
                s_t = bases[n5] + (i)*x_t;
                for (j=0; j<s_x; j++) idx[nn++] = s_t++;
            } else if (Xe-xe > 0) {
                if (bx == DMDA_BOUNDARY_MIRROR) {
                    for (j=0; j<s_x; j++) idx[nn++] = bases[rank] + x*(i + 1) - 2 - j;
                } else {
                    for (j=0; j<s_x; j++) idx[nn++] = -1;
                }
            }
        }

        for (i=1; i<=s_y; i++) {
            if (n6 >= 0) { /* left above */
                x_t = lx[n6 % m];
                /* y_t = ly[(n6/m)]; */
                s_t = bases[n6] + (i)*x_t - s_x;
                for (j=0; j<s_x; j++) idx[nn++] = s_t++;
            } else if (xs-Xs > 0 && Ye-ye > 0) {
                for (j=0; j<s_x; j++) idx[nn++] = -1;
            }
            if (n7 >= 0) { /* directly above */
                x_t = x;
                /* y_t = ly[(n7/m)]; */
                s_t = bases[n7] + (i-1)*x_t;
                for (j=0; j<x_t; j++) idx[nn++] = s_t++;
            } else if (Ye-ye > 0) {
                if (by == DMDA_BOUNDARY_MIRROR) {
                    for (j=0; j<x; j++) idx[nn++] = bases[rank] + x*(y - i - 1)  + j;
                } else {
                    for (j=0; j<x; j++) idx[nn++] = -1;
                }
            }
            if (n8 >= 0) { /* right above */
                x_t = lx[n8 % m];
                /* y_t = ly[(n8/m)]; */
                s_t = bases[n8] + (i-1)*x_t;
                for (j=0; j<s_x; j++) idx[nn++] = s_t++;
            } else if (Xe-xe > 0 && Ye-ye > 0) {
                for (j=0; j<s_x; j++) idx[nn++] = -1;
            }
        }
    }
    /*
       Set the local to global ordering in the global vector, this allows use
       of VecSetValuesLocal().
    */
    ierr = ISCreateBlock(comm,dof,nn,idx,PETSC_OWN_POINTER,&ltogis);
    CHKERRQ(ierr);
    ierr = PetscMalloc(nn*dof*sizeof(PetscInt),&idx_cpy);
    CHKERRQ(ierr);
    ierr = PetscLogObjectMemory(da,nn*dof*sizeof(PetscInt));
    CHKERRQ(ierr);
    ierr = ISGetIndices(ltogis, &idx_full);
    CHKERRQ(ierr);
    ierr = PetscMemcpy(idx_cpy,idx_full,nn*dof*sizeof(PetscInt));
    CHKERRQ(ierr);
    ierr = ISRestoreIndices(ltogis, &idx_full);
    CHKERRQ(ierr);
    ierr = ISLocalToGlobalMappingCreateIS(ltogis,&da->ltogmap);
    CHKERRQ(ierr);
    ierr = PetscLogObjectParent(da,da->ltogmap);
    CHKERRQ(ierr);
    ierr = ISDestroy(&ltogis);
    CHKERRQ(ierr);
    ierr = ISLocalToGlobalMappingBlock(da->ltogmap,dd->w,&da->ltogmapb);
    CHKERRQ(ierr);
    ierr = PetscLogObjectParent(da,da->ltogmap);
    CHKERRQ(ierr);

    ierr  = PetscFree2(bases,ldims);
    CHKERRQ(ierr);
    dd->m = m;
    dd->n  = n;
    /* note petsc expects xs/xe/Xs/Xe to be multiplied by #dofs in many places */
    dd->xs = xs*dof;
    dd->xe = xe*dof;
    dd->ys = ys;
    dd->ye = ye;
    dd->zs = 0;
    dd->ze = 1;
    dd->Xs = Xs*dof;
    dd->Xe = Xe*dof;
    dd->Ys = Ys;
    dd->Ye = Ye;
    dd->Zs = 0;
    dd->Ze = 1;

    ierr = VecDestroy(&local);
    CHKERRQ(ierr);
    ierr = VecDestroy(&global);
    CHKERRQ(ierr);

    dd->gtol      = gtol;
    dd->ltog      = ltog;
    dd->idx       = idx_cpy;
    dd->Nl        = nn*dof;
    dd->base      = base;
    da->ops->view = DMView_DA_2d;
    dd->ltol      = NULL;
    dd->ao        = NULL;
    PetscFunctionReturn(0);
}
예제 #3
0
/*
   PCISSetUp -
*/
PetscErrorCode  PCISSetUp(PC pc, PetscBool computesolvers)
{
  PC_IS          *pcis  = (PC_IS*)(pc->data);
  Mat_IS         *matis;
  MatReuse       reuse;
  PetscErrorCode ierr;
  PetscBool      flg,issbaij;
  Vec            counter;

  PetscFunctionBegin;
  ierr = PetscObjectTypeCompare((PetscObject)pc->pmat,MATIS,&flg);CHKERRQ(ierr);
  if (!flg) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONG,"Preconditioner type of Neumann Neumman requires matrix of type MATIS");
  matis = (Mat_IS*)pc->pmat->data;

  /* first time creation, get info on substructuring */
  if (!pc->setupcalled) {
    PetscInt    n_I;
    PetscInt    *idx_I_local,*idx_B_local,*idx_I_global,*idx_B_global;
    PetscBT     bt;
    PetscInt    i,j;

    /* get info on mapping */
    ierr = PetscObjectReference((PetscObject)pc->pmat->rmap->mapping);CHKERRQ(ierr);
    ierr = ISLocalToGlobalMappingDestroy(&pcis->mapping);CHKERRQ(ierr);
    pcis->mapping = pc->pmat->rmap->mapping;
    ierr = ISLocalToGlobalMappingGetSize(pcis->mapping,&pcis->n);CHKERRQ(ierr);
    ierr = ISLocalToGlobalMappingGetInfo(pcis->mapping,&(pcis->n_neigh),&(pcis->neigh),&(pcis->n_shared),&(pcis->shared));CHKERRQ(ierr);

    /* Identifying interior and interface nodes, in local numbering */
    ierr = PetscBTCreate(pcis->n,&bt);CHKERRQ(ierr);
    for (i=0;i<pcis->n_neigh;i++)
      for (j=0;j<pcis->n_shared[i];j++) {
          ierr = PetscBTSet(bt,pcis->shared[i][j]);CHKERRQ(ierr);
      }

    /* Creating local and global index sets for interior and inteface nodes. */
    ierr = PetscMalloc1(pcis->n,&idx_I_local);CHKERRQ(ierr);
    ierr = PetscMalloc1(pcis->n,&idx_B_local);CHKERRQ(ierr);
    for (i=0, pcis->n_B=0, n_I=0; i<pcis->n; i++) {
      if (!PetscBTLookup(bt,i)) {
        idx_I_local[n_I] = i;
        n_I++;
      } else {
        idx_B_local[pcis->n_B] = i;
        pcis->n_B++;
      }
    }

    /* Getting the global numbering */
    idx_B_global = idx_I_local + n_I; /* Just avoiding allocating extra memory, since we have vacant space */
    idx_I_global = idx_B_local + pcis->n_B;
    ierr         = ISLocalToGlobalMappingApply(pcis->mapping,pcis->n_B,idx_B_local,idx_B_global);CHKERRQ(ierr);
    ierr         = ISLocalToGlobalMappingApply(pcis->mapping,n_I,idx_I_local,idx_I_global);CHKERRQ(ierr);

    /* Creating the index sets */
    ierr = ISCreateGeneral(PETSC_COMM_SELF,pcis->n_B,idx_B_local,PETSC_COPY_VALUES, &pcis->is_B_local);CHKERRQ(ierr);
    ierr = ISCreateGeneral(PETSC_COMM_SELF,pcis->n_B,idx_B_global,PETSC_COPY_VALUES,&pcis->is_B_global);CHKERRQ(ierr);
    ierr = ISCreateGeneral(PETSC_COMM_SELF,n_I,idx_I_local,PETSC_COPY_VALUES, &pcis->is_I_local);CHKERRQ(ierr);
    ierr = ISCreateGeneral(PETSC_COMM_SELF,n_I,idx_I_global,PETSC_COPY_VALUES,&pcis->is_I_global);CHKERRQ(ierr);

    /* Freeing memory */
    ierr = PetscFree(idx_B_local);CHKERRQ(ierr);
    ierr = PetscFree(idx_I_local);CHKERRQ(ierr);
    ierr = PetscBTDestroy(&bt);CHKERRQ(ierr);

    /* Creating work vectors and arrays */
    ierr = VecDuplicate(matis->x,&pcis->vec1_N);CHKERRQ(ierr);
    ierr = VecDuplicate(pcis->vec1_N,&pcis->vec2_N);CHKERRQ(ierr);
    ierr = VecCreateSeq(PETSC_COMM_SELF,pcis->n-pcis->n_B,&pcis->vec1_D);CHKERRQ(ierr);
    ierr = VecDuplicate(pcis->vec1_D,&pcis->vec2_D);CHKERRQ(ierr);
    ierr = VecDuplicate(pcis->vec1_D,&pcis->vec3_D);CHKERRQ(ierr);
    ierr = VecDuplicate(pcis->vec1_D,&pcis->vec4_D);CHKERRQ(ierr);
    ierr = VecCreateSeq(PETSC_COMM_SELF,pcis->n_B,&pcis->vec1_B);CHKERRQ(ierr);
    ierr = VecDuplicate(pcis->vec1_B,&pcis->vec2_B);CHKERRQ(ierr);
    ierr = VecDuplicate(pcis->vec1_B,&pcis->vec3_B);CHKERRQ(ierr);
    ierr = MatCreateVecs(pc->pmat,&pcis->vec1_global,0);CHKERRQ(ierr);
    ierr = PetscMalloc1(pcis->n,&pcis->work_N);CHKERRQ(ierr);
    /* scaling vector */
    if (!pcis->D) { /* it can happen that the user passed in a scaling vector via PCISSetSubdomainDiagonalScaling */
      ierr = VecDuplicate(pcis->vec1_B,&pcis->D);CHKERRQ(ierr);
      ierr = VecSet(pcis->D,pcis->scaling_factor);CHKERRQ(ierr);
    }

    /* Creating the scatter contexts */
    ierr = VecScatterCreate(pcis->vec1_N,pcis->is_I_local,pcis->vec1_D,(IS)0,&pcis->N_to_D);CHKERRQ(ierr);
    ierr = VecScatterCreate(pcis->vec1_global,pcis->is_I_global,pcis->vec1_D,(IS)0,&pcis->global_to_D);CHKERRQ(ierr);
    ierr = VecScatterCreate(pcis->vec1_N,pcis->is_B_local,pcis->vec1_B,(IS)0,&pcis->N_to_B);CHKERRQ(ierr);
    ierr = VecScatterCreate(pcis->vec1_global,pcis->is_B_global,pcis->vec1_B,(IS)0,&pcis->global_to_B);CHKERRQ(ierr);

    /* map from boundary to local */
    ierr = ISLocalToGlobalMappingCreateIS(pcis->is_B_local,&pcis->BtoNmap);CHKERRQ(ierr);
  }

  /*
    Extracting the blocks A_II, A_BI, A_IB and A_BB from A. If the numbering
    is such that interior nodes come first than the interface ones, we have

        [ A_II | A_IB ]
    A = [------+------]
        [ A_BI | A_BB ]
  */
  reuse = MAT_INITIAL_MATRIX;
  if (pcis->reusesubmatrices && pc->setupcalled) {
    if (pc->flag == SAME_NONZERO_PATTERN) {
      reuse = MAT_REUSE_MATRIX;
    } else {
      reuse = MAT_INITIAL_MATRIX;
    }
  }
  if (reuse == MAT_INITIAL_MATRIX) {
    ierr = MatDestroy(&pcis->A_II);CHKERRQ(ierr);
    ierr = MatDestroy(&pcis->A_IB);CHKERRQ(ierr);
    ierr = MatDestroy(&pcis->A_BI);CHKERRQ(ierr);
    ierr = MatDestroy(&pcis->A_BB);CHKERRQ(ierr);
  }

  ierr = MatGetSubMatrix(matis->A,pcis->is_I_local,pcis->is_I_local,reuse,&pcis->A_II);CHKERRQ(ierr);
  ierr = MatGetSubMatrix(matis->A,pcis->is_B_local,pcis->is_B_local,reuse,&pcis->A_BB);CHKERRQ(ierr);
  ierr = PetscObjectTypeCompare((PetscObject)matis->A,MATSEQSBAIJ,&issbaij);CHKERRQ(ierr);
  if (!issbaij) {
    ierr = MatGetSubMatrix(matis->A,pcis->is_I_local,pcis->is_B_local,reuse,&pcis->A_IB);CHKERRQ(ierr);
    ierr = MatGetSubMatrix(matis->A,pcis->is_B_local,pcis->is_I_local,reuse,&pcis->A_BI);CHKERRQ(ierr);
  } else {
    Mat newmat;
    ierr = MatConvert(matis->A,MATSEQBAIJ,MAT_INITIAL_MATRIX,&newmat);CHKERRQ(ierr);
    ierr = MatGetSubMatrix(newmat,pcis->is_I_local,pcis->is_B_local,reuse,&pcis->A_IB);CHKERRQ(ierr);
    ierr = MatGetSubMatrix(newmat,pcis->is_B_local,pcis->is_I_local,reuse,&pcis->A_BI);CHKERRQ(ierr);
    ierr = MatDestroy(&newmat);CHKERRQ(ierr);
  }

  /* Creating scaling vector D */
  ierr = PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_is_use_stiffness_scaling",&pcis->use_stiffness_scaling,NULL);CHKERRQ(ierr);
  if (pcis->use_stiffness_scaling) {
    ierr = MatGetDiagonal(pcis->A_BB,pcis->D);CHKERRQ(ierr);
  }
  ierr = MatCreateVecs(pc->pmat,&counter,0);CHKERRQ(ierr); /* temporary auxiliar vector */
  ierr = VecSet(counter,0.0);CHKERRQ(ierr);
  ierr = VecScatterBegin(pcis->global_to_B,pcis->D,counter,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
  ierr = VecScatterEnd(pcis->global_to_B,pcis->D,counter,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
  ierr = VecScatterBegin(pcis->global_to_B,counter,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
  ierr = VecScatterEnd(pcis->global_to_B,counter,pcis->vec1_B,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
  ierr = VecPointwiseDivide(pcis->D,pcis->D,pcis->vec1_B);CHKERRQ(ierr);
  ierr = VecDestroy(&counter);CHKERRQ(ierr);

  /* See historical note 01, at the bottom of this file. */

  /* Creating the KSP contexts for the local Dirichlet and Neumann problems */
  if (computesolvers) {
    PC pc_ctx;

    pcis->pure_neumann = matis->pure_neumann;
    /* Dirichlet */
    ierr = KSPCreate(PETSC_COMM_SELF,&pcis->ksp_D);CHKERRQ(ierr);
    ierr = KSPSetErrorIfNotConverged(pcis->ksp_D,pc->erroriffailure);CHKERRQ(ierr);
    ierr = PetscObjectIncrementTabLevel((PetscObject)pcis->ksp_D,(PetscObject)pc,1);CHKERRQ(ierr);
    ierr = KSPSetOperators(pcis->ksp_D,pcis->A_II,pcis->A_II);CHKERRQ(ierr);
    ierr = KSPSetOptionsPrefix(pcis->ksp_D,"is_localD_");CHKERRQ(ierr);
    ierr = KSPGetPC(pcis->ksp_D,&pc_ctx);CHKERRQ(ierr);
    ierr = PCSetType(pc_ctx,PCLU);CHKERRQ(ierr);
    ierr = KSPSetType(pcis->ksp_D,KSPPREONLY);CHKERRQ(ierr);
    ierr = KSPSetFromOptions(pcis->ksp_D);CHKERRQ(ierr);
    /* the vectors in the following line are dummy arguments, just telling the KSP the vector size. Values are not used */
    ierr = KSPSetUp(pcis->ksp_D);CHKERRQ(ierr);
    /* Neumann */
    ierr = KSPCreate(PETSC_COMM_SELF,&pcis->ksp_N);CHKERRQ(ierr);
    ierr = KSPSetErrorIfNotConverged(pcis->ksp_N,pc->erroriffailure);CHKERRQ(ierr);
    ierr = PetscObjectIncrementTabLevel((PetscObject)pcis->ksp_N,(PetscObject)pc,1);CHKERRQ(ierr);
    ierr = KSPSetOperators(pcis->ksp_N,matis->A,matis->A);CHKERRQ(ierr);
    ierr = KSPSetOptionsPrefix(pcis->ksp_N,"is_localN_");CHKERRQ(ierr);
    ierr = KSPGetPC(pcis->ksp_N,&pc_ctx);CHKERRQ(ierr);
    ierr = PCSetType(pc_ctx,PCLU);CHKERRQ(ierr);
    ierr = KSPSetType(pcis->ksp_N,KSPPREONLY);CHKERRQ(ierr);
    ierr = KSPSetFromOptions(pcis->ksp_N);CHKERRQ(ierr);
    {
      PetscBool damp_fixed                    = PETSC_FALSE,
                remove_nullspace_fixed        = PETSC_FALSE,
                set_damping_factor_floating   = PETSC_FALSE,
                not_damp_floating             = PETSC_FALSE,
                not_remove_nullspace_floating = PETSC_FALSE;
      PetscReal fixed_factor,
                floating_factor;

      ierr = PetscOptionsGetReal(((PetscObject)pc_ctx)->options,((PetscObject)pc_ctx)->prefix,"-pc_is_damp_fixed",&fixed_factor,&damp_fixed);CHKERRQ(ierr);
      if (!damp_fixed) fixed_factor = 0.0;
      ierr = PetscOptionsGetBool(((PetscObject)pc_ctx)->options,((PetscObject)pc_ctx)->prefix,"-pc_is_damp_fixed",&damp_fixed,NULL);CHKERRQ(ierr);

      ierr = PetscOptionsGetBool(((PetscObject)pc_ctx)->options,((PetscObject)pc_ctx)->prefix,"-pc_is_remove_nullspace_fixed",&remove_nullspace_fixed,NULL);CHKERRQ(ierr);

      ierr = PetscOptionsGetReal(((PetscObject)pc_ctx)->options,((PetscObject)pc_ctx)->prefix,"-pc_is_set_damping_factor_floating",
                              &floating_factor,&set_damping_factor_floating);CHKERRQ(ierr);
      if (!set_damping_factor_floating) floating_factor = 0.0;
      ierr = PetscOptionsGetBool(((PetscObject)pc_ctx)->options,((PetscObject)pc_ctx)->prefix,"-pc_is_set_damping_factor_floating",&set_damping_factor_floating,NULL);CHKERRQ(ierr);
      if (!set_damping_factor_floating) floating_factor = 1.e-12;

      ierr = PetscOptionsGetBool(((PetscObject)pc_ctx)->options,((PetscObject)pc_ctx)->prefix,"-pc_is_not_damp_floating",&not_damp_floating,NULL);CHKERRQ(ierr);

      ierr = PetscOptionsGetBool(((PetscObject)pc_ctx)->options,((PetscObject)pc_ctx)->prefix,"-pc_is_not_remove_nullspace_floating",&not_remove_nullspace_floating,NULL);CHKERRQ(ierr);

      if (pcis->pure_neumann) {  /* floating subdomain */
        if (!(not_damp_floating)) {
          ierr = PCFactorSetShiftType(pc_ctx,MAT_SHIFT_NONZERO);CHKERRQ(ierr);
          ierr = PCFactorSetShiftAmount(pc_ctx,floating_factor);CHKERRQ(ierr);
        }
        if (!(not_remove_nullspace_floating)) {
          MatNullSpace nullsp;
          ierr = MatNullSpaceCreate(PETSC_COMM_SELF,PETSC_TRUE,0,NULL,&nullsp);CHKERRQ(ierr);
          ierr = MatSetNullSpace(matis->A,nullsp);CHKERRQ(ierr);
          ierr = MatNullSpaceDestroy(&nullsp);CHKERRQ(ierr);
        }
      } else {  /* fixed subdomain */
        if (damp_fixed) {
          ierr = PCFactorSetShiftType(pc_ctx,MAT_SHIFT_NONZERO);CHKERRQ(ierr);
          ierr = PCFactorSetShiftAmount(pc_ctx,floating_factor);CHKERRQ(ierr);
        }
        if (remove_nullspace_fixed) {
          MatNullSpace nullsp;
          ierr = MatNullSpaceCreate(PETSC_COMM_SELF,PETSC_TRUE,0,NULL,&nullsp);CHKERRQ(ierr);
          ierr = MatSetNullSpace(matis->A,nullsp);CHKERRQ(ierr);
          ierr = MatNullSpaceDestroy(&nullsp);CHKERRQ(ierr);
        }
      }
    }
    /* the vectors in the following line are dummy arguments, just telling the KSP the vector size. Values are not used */
    ierr = KSPSetUp(pcis->ksp_N);CHKERRQ(ierr);
  }

  PetscFunctionReturn(0);
}
예제 #4
0
파일: bddcschurs.c 프로젝트: PeiLiu90/petsc
PetscErrorCode PCBDDCSubSchursSetUp(PCBDDCSubSchurs sub_schurs, Mat S, IS is_A_I, IS is_A_B, PetscInt ncc, IS is_cc[], PetscInt xadj[], PetscInt adjncy[], PetscInt nlayers)
{
  Mat                    A_II,A_IB,A_BI,A_BB;
  ISLocalToGlobalMapping BtoNmap,ItoNmap;
  PetscBT                touched;
  PetscInt               i,n_I,n_B,n_local,*local_numbering;
  PetscBool              is_sorted;
  PetscErrorCode         ierr;

  PetscFunctionBegin;
  ierr = ISSorted(is_A_I,&is_sorted);CHKERRQ(ierr);
  if (!is_sorted) {
    SETERRQ(PetscObjectComm((PetscObject)is_A_I),PETSC_ERR_PLIB,"IS for I dofs should be shorted");
  }
  ierr = ISSorted(is_A_B,&is_sorted);CHKERRQ(ierr);
  if (!is_sorted) {
    SETERRQ(PetscObjectComm((PetscObject)is_A_B),PETSC_ERR_PLIB,"IS for B dofs should be shorted");
  }

  /* get sizes */
  ierr = ISGetLocalSize(is_A_I,&n_I);CHKERRQ(ierr);
  ierr = ISGetLocalSize(is_A_B,&n_B);CHKERRQ(ierr);
  n_local = n_I+n_B;

  /* maps */
  ierr = ISLocalToGlobalMappingCreateIS(is_A_B,&BtoNmap);CHKERRQ(ierr);
  if (nlayers >= 0 && xadj != NULL && adjncy != NULL) { /* I problems have a different size of the original ones */
    ierr = ISLocalToGlobalMappingCreateIS(is_A_I,&ItoNmap);CHKERRQ(ierr);
    /* allocate some auxiliary space */
    ierr = PetscMalloc1(n_local,&local_numbering);CHKERRQ(ierr);
    ierr = PetscBTCreate(n_local,&touched);CHKERRQ(ierr);
  } else {
    ItoNmap = 0;
    local_numbering = 0;
    touched = 0;
  }

  /* get Schur complement matrices */
  ierr = MatSchurComplementGetSubMatrices(S,&A_II,NULL,&A_IB,&A_BI,&A_BB);CHKERRQ(ierr);

  /* allocate space for schur complements */
  ierr = PetscMalloc5(ncc,&sub_schurs->is_AEj_I,ncc,&sub_schurs->is_AEj_B,ncc,&sub_schurs->S_Ej,ncc,&sub_schurs->work1,ncc,&sub_schurs->work2);CHKERRQ(ierr);
  sub_schurs->n_subs = ncc;

  /* cycle on subsets and extract schur complements */
  for (i=0;i<sub_schurs->n_subs;i++) {
    Mat      AE_II,AE_IE,AE_EI,AE_EE;
    IS       is_I,is_subset_B;

    /* get IS for subsets in B numbering */
    ierr = ISDuplicate(is_cc[i],&sub_schurs->is_AEj_B[i]);CHKERRQ(ierr);
    ierr = ISSort(sub_schurs->is_AEj_B[i]);CHKERRQ(ierr);
    ierr = ISGlobalToLocalMappingApplyIS(BtoNmap,IS_GTOLM_DROP,sub_schurs->is_AEj_B[i],&is_subset_B);CHKERRQ(ierr);

    /* BB block on subset */
    ierr = MatGetSubMatrix(A_BB,is_subset_B,is_subset_B,MAT_INITIAL_MATRIX,&AE_EE);CHKERRQ(ierr);

    if (ItoNmap) { /* is ItoNmap has been computed, extracts only a part of I dofs */
      const PetscInt* idx_B;
      PetscInt        n_local_dofs,n_prev_added,j,layer,subset_size;

      /* all boundary dofs must be skipped when adding layers */
      ierr = PetscBTMemzero(n_local,touched);CHKERRQ(ierr);
      ierr = ISGetIndices(is_A_B,&idx_B);CHKERRQ(ierr);
      for (j=0;j<n_B;j++) {
        ierr = PetscBTSet(touched,idx_B[j]);CHKERRQ(ierr);
      }
      ierr = ISRestoreIndices(is_A_B,&idx_B);CHKERRQ(ierr);

      /* add next layers of dofs */
      ierr = ISGetLocalSize(is_cc[i],&subset_size);CHKERRQ(ierr);
      ierr = ISGetIndices(is_cc[i],&idx_B);CHKERRQ(ierr);
      ierr = PetscMemcpy(local_numbering,idx_B,subset_size*sizeof(PetscInt));CHKERRQ(ierr);
      ierr = ISRestoreIndices(is_cc[i],&idx_B);CHKERRQ(ierr);
      n_local_dofs = subset_size;
      n_prev_added = subset_size;
      for (layer=0;layer<nlayers;layer++) {
        PetscInt n_added;
        if (n_local_dofs == n_I+subset_size) break;
        if (n_local_dofs > n_I+subset_size) {
          SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Error querying layer %d. Out of bound access (%d > %d)",layer,n_local_dofs,n_I+subset_size);
        }
        ierr = PCBDDCAdjGetNextLayer_Private(local_numbering+n_local_dofs,n_prev_added,touched,xadj,adjncy,&n_added);CHKERRQ(ierr);
        n_prev_added = n_added;
        n_local_dofs += n_added;
        if (!n_added) break;
      }

      /* IS for I dofs in original numbering and in I numbering */
      ierr = ISCreateGeneral(PetscObjectComm((PetscObject)ItoNmap),n_local_dofs-subset_size,local_numbering+subset_size,PETSC_COPY_VALUES,&sub_schurs->is_AEj_I[i]);CHKERRQ(ierr);
      ierr = ISSort(sub_schurs->is_AEj_I[i]);CHKERRQ(ierr);
      ierr = ISGlobalToLocalMappingApplyIS(ItoNmap,IS_GTOLM_DROP,sub_schurs->is_AEj_I[i],&is_I);CHKERRQ(ierr);

      /* II block */
      ierr = MatGetSubMatrix(A_II,is_I,is_I,MAT_INITIAL_MATRIX,&AE_II);CHKERRQ(ierr);
    } else { /* in this case we can take references of already existing IS and matrices for I dofs */
      /* IS for I dofs in original numbering */
      ierr = PetscObjectReference((PetscObject)is_A_I);CHKERRQ(ierr);
      sub_schurs->is_AEj_I[i] = is_A_I;

      /* IS for I dofs in I numbering TODO: "first" argument of ISCreateStride is not general */
      ierr = ISCreateStride(PetscObjectComm((PetscObject)is_A_I),n_I,0,1,&is_I);CHKERRQ(ierr);

      /* II block is the same */
      ierr = PetscObjectReference((PetscObject)A_II);CHKERRQ(ierr);
      AE_II = A_II;
    }

    /* IE block */
    ierr = MatGetSubMatrix(A_IB,is_I,is_subset_B,MAT_INITIAL_MATRIX,&AE_IE);CHKERRQ(ierr);

    /* EI block */
    ierr = MatGetSubMatrix(A_BI,is_subset_B,is_I,MAT_INITIAL_MATRIX,&AE_EI);CHKERRQ(ierr);

    /* setup Schur complements on subset */
    ierr = MatCreateSchurComplement(AE_II,AE_II,AE_IE,AE_EI,AE_EE,&sub_schurs->S_Ej[i]);CHKERRQ(ierr);
    ierr = MatGetVecs(sub_schurs->S_Ej[i],&sub_schurs->work1[i],&sub_schurs->work2[i]);CHKERRQ(ierr);
    if (AE_II == A_II) { /* we can reuse the same ksp */
      KSP ksp;
      ierr = MatSchurComplementGetKSP(S,&ksp);CHKERRQ(ierr);
      ierr = MatSchurComplementSetKSP(sub_schurs->S_Ej[i],ksp);CHKERRQ(ierr);
    } else { /* build new ksp object which inherits ksp and pc types from the original one */
      KSP      origksp,schurksp;
      PC       origpc,schurpc;
      KSPType  ksp_type;
      PCType   pc_type;
      PetscInt n_internal;

      ierr = MatSchurComplementGetKSP(S,&origksp);CHKERRQ(ierr);
      ierr = MatSchurComplementGetKSP(sub_schurs->S_Ej[i],&schurksp);CHKERRQ(ierr);
      ierr = KSPGetType(origksp,&ksp_type);CHKERRQ(ierr);
      ierr = KSPSetType(schurksp,ksp_type);CHKERRQ(ierr);
      ierr = KSPGetPC(schurksp,&schurpc);CHKERRQ(ierr);
      ierr = KSPGetPC(origksp,&origpc);CHKERRQ(ierr);
      ierr = PCGetType(origpc,&pc_type);CHKERRQ(ierr);
      ierr = PCSetType(schurpc,pc_type);CHKERRQ(ierr);
      ierr = ISGetSize(is_I,&n_internal);CHKERRQ(ierr);
      if (n_internal) { /* UMFPACK gives error with 0 sized problems */
        MatSolverPackage solver=NULL;
        ierr = PCFactorGetMatSolverPackage(origpc,(const MatSolverPackage*)&solver);CHKERRQ(ierr);
        if (solver) {
          ierr = PCFactorSetMatSolverPackage(schurpc,solver);CHKERRQ(ierr);
        }
      }
      ierr = KSPSetUp(schurksp);CHKERRQ(ierr);
    }
    /* free */
    ierr = MatDestroy(&AE_II);CHKERRQ(ierr);
    ierr = MatDestroy(&AE_EE);CHKERRQ(ierr);
    ierr = MatDestroy(&AE_IE);CHKERRQ(ierr);
    ierr = MatDestroy(&AE_EI);CHKERRQ(ierr);
    ierr = ISDestroy(&is_I);CHKERRQ(ierr);
    ierr = ISDestroy(&is_subset_B);CHKERRQ(ierr);
  }
  /* free */
  ierr = ISLocalToGlobalMappingDestroy(&ItoNmap);CHKERRQ(ierr);
  ierr = ISLocalToGlobalMappingDestroy(&BtoNmap);CHKERRQ(ierr);
  ierr = PetscFree(local_numbering);CHKERRQ(ierr);
  ierr = PetscBTDestroy(&touched);CHKERRQ(ierr);
  PetscFunctionReturn(0);
}