Exemplo n.º 1
0
/**
 * \param[in]  rcells
 * \param[out] adjncy
 */
template< size_t NDIM > void UnstructuredBlock< NDIM >::build_csr(
    const LookupTable<index_type, CLMFC> & rcells
  , LookupTable<index_type, 0> & adjncy)
const {
    // iterators.
    int icl, ifl, ieg;

    // fill.
    index_type const * prcells = reinterpret_cast<index_type const *>(rcells.row(0));
    index_type       * padjncy = reinterpret_cast<index_type       *>(adjncy.row(0));
    ieg = 0;
    for (icl=0; icl<ncell(); icl++) {
        for (ifl=0; ifl<CLMFC; ifl++) {
            if (prcells[ifl] != -1) {
                padjncy[ieg] = prcells[ifl];
                ieg += 1;
            };
        };
        // advance pointers.
        prcells += CLMFC;
    };
};
Exemplo n.º 2
0
void PltWin::drawIt(QPainter *p)
{
  QString txt;
  double x, y, x0, y0, x1, y1, x2, y2, xprev, yprev, shift, ubmin, ubmax, ub, alpha;
  int n, layer, lay, prev_layer, circDia, i, j, at, ichain, a, istart, iend, icurr, xs, ys;
  int idx, nmax;
  bool dum;

  QPen *pen = new QPen();
  QBrush *brush = new QBrush();
  QBrush *brush_unrld = new QBrush();

  // antialiasing of primitives if ANTIALIASE is set to true
  if (!paintEPS) p->setRenderHint(QPainter::Antialiasing, ANTIALIASE);

  // plot the grain boundary line
  if (isGBfile && showGB) {
    x0 = ZFact*xyzMin(1) - xPan - (ZFact-1)*xyzCen(1);
    x1 = ZFact*xyzMax(1) - xPan - (ZFact-1)*xyzCen(1);
    y  = ZFact*gbYcoor - yPan - (ZFact-1)*xyzCen(2);
    DrawLine(p, x0, y, x1, y);
  }

  if (AtomPos==COMPOSITE) {
    if (!paintEPS) {
      brush_unrld->setColor( Qt::lightGray );
      brush_unrld->setStyle( Qt::SolidPattern );
    }
  }

  // plotting of atomic arrangement in the initial configuration
  prev_layer = -1;
  x0 = y0 = x1 = y1 = 0;

  // need to construct the neighbor list in the relaxed configuration
  if (plotType == PLOT_ATOM_NEIGHBORS) {    
    if (AtomPos == UNRELAXED && NeighListInit.data == NULL)
      InitNeighborList(this, NeighListInit, numNeighInit);
    
    if ((AtomPos == RELAXED || AtomPos == COMPOSITE) && NeighListRel.data == NULL)
      RelNeighborList(this, rcut, NeighListRel, numNeighRel);

    if (AtomPos == UNRELAXED) {
      nmax = -1;
      for (at=1; at<=NInit; at++) {
	n = numNeighInit(at);
	if (n > nmax) nmax = n;
      }
      colormap(nmax+1, cmap);
    }

    if (AtomPos == RELAXED) {
      nmax = -1;
      for (at=1; at<=NRel; at++) {
	n = numNeighRel(at);
	if (n > nmax) nmax = n;
      }
      colormap(nmax+1, cmap);
    }
  }

  if (plotType == PLOT_ATOM_TYPES) {
    nmax = -1;
    for (at=1; at<=NInit; at++) {
      n = atomType(at);
      if (n > nmax) nmax = n;
    }
    colormap(nmax, cmap);
  }
  
  //
  //  Plot the atomic configuration such that the atoms in the front (in the top layer) are plotted
  //  at the end.
  //

  for (i=1; i<=NInit; i++) {
    at = aorder(i);
    if (!zLayerSel(zLayer(at)))
      continue;    

    layer = zLayer(at);
    circDia = zDiamLayer(layer);
    
    switch(plotType) {
      case PLOT_ATOM_LAYERS:
	layer = zLayer(at);

	if (!paintEPS && layer != prev_layer) {
	  pen->setColor(zColorLayer(layer, 1));
	  pen->setWidth(zLineThickLayer(layer));
	  p->setPen(*pen);
	  
	  brush->setColor(zColorLayer(layer, 2));
	  brush->setStyle(Qt::SolidPattern);
	  p->setBrush(*brush);
	}
	break;
	
      case PLOT_ATOM_TYPES:
	lay = layer;
	layer = atomType(at);
	
	if (!paintEPS && layer != prev_layer) {
	  pen->setColor(Qt::black);
	  pen->setWidth(zLineThickLayer(lay));
	  p->setPen(*pen);
	  
	  if (layer == 0) {
	    brush->setColor(Qt::lightGray);
	  } else {
	    brush->setColor(cmap[layer-1]);
	  }
	  brush->setStyle(Qt::SolidPattern);
	  p->setBrush(*brush);
	}
	break;

      case PLOT_ATOM_NEIGHBORS:
	lay = layer;
	if (AtomPos == UNRELAXED)
	  layer = numNeighInit(at);
	else if (AtomPos == RELAXED || AtomPos == COMPOSITE)	  
	  layer = numNeighRel(at);

	if (!paintEPS && layer != prev_layer) {
	  pen->setColor(Qt::black);
	  pen->setWidth(zLineThickLayer(lay));
	  p->setPen(*pen);
	  
	  if (layer == 0)
	    brush->setColor(Qt::lightGray);
	  else {
	    brush->setColor(QColor(cmap[layer]));
	  }
	  brush->setStyle(Qt::SolidPattern);
	  p->setBrush(*brush);
	}
	break;
    }
    
    if (layer != prev_layer) prev_layer = layer;

    switch(AtomPos) {
      case UNRELAXED:
        x = ZFact*xyzInit(at,1) - xPan - (ZFact-1)*xyzCen(1);
	y = ZFact*xyzInit(at,2) - yPan - (ZFact-1)*xyzCen(2);
	DrawAtom(p, at, x, y, circDia);	
        break;

      case RELAXED:
	x = ZFact*(xyzInit(at,1) + AtomDispScale*aDisp(at,1)) - xPan - (ZFact-1)*xyzCen(1);
        y = ZFact*(xyzInit(at,2) + AtomDispScale*aDisp(at,2)) - yPan - (ZFact-1)*xyzCen(2);
        DrawAtom(p, at, x, y, circDia);
	break;

      case COMPOSITE:
	if (!paintEPS) { p->setBrush( *brush_unrld ); }
	x = ZFact*xyzInit(at,1) - xPan - (ZFact-1)*xyzCen(1);
	y = ZFact*xyzInit(at,2) - yPan - (ZFact-1)*xyzCen(2);
        DrawAtom(p, -1, x, y, circDia);
        if (!paintEPS) { p->setBrush( *brush ); }
	x = ZFact*(xyzInit(at,1) + AtomDispScale*aDisp(at,1)) - xPan - (ZFact-1)*xyzCen(1);
	y = ZFact*(xyzInit(at,2) + AtomDispScale*aDisp(at,2)) - yPan - (ZFact-1)*xyzCen(2); 
        DrawAtom(p, at, x, y, circDia);
	break;
    }

    if (x < x0) x0 = x;
    if (x > x1) x1 = x;
    if (y < y0) y0 = y;
    if (y > y1) y1 = y;

    // atom numbers
    if (AtomNumbers) {
      txt.sprintf("%d", at);
      shift = circDia/(2.0*factor);
      DrawText(p, x+shift, y+shift, txt);
    }
  }

  // plot the inert atoms
  if (InertAtoms) {
    if (!paintEPS) {
      pen->setColor(Qt::black);
      pen->setWidth(zLineThickLayer(layer));
      p->setPen(*pen);
      
      brush->setColor(Qt::black);
      brush->setStyle(Qt::NoBrush);
      p->setBrush( *brush );
    }
            
    for (at=1; at<=NInert; at++) {
      // plot only those atoms which belong to the selected (active) layers
      //      if (!zLayerSel(zLayer(n)))
      //	continue;
      x = ZFact*xyzInert(at,1) - xPan - (ZFact-1)*xyzCen(1);
      y = ZFact*xyzInert(at,2) - yPan - (ZFact-1)*xyzCen(2);
      DrawAtom(p, 0, x, y, circDia);
    }    
  }

  // highlight the atoms picked
  if (!paintEPS && napicked > 0) {
    pen->setColor(Qt::green);
    pen->setWidth(2);
    p->setPen(*pen);    
    brush->setStyle(Qt::NoBrush);
    p->setBrush(*brush);
    
    dum = ATOM_3DSPHERE;
    ATOM_3DSPHERE = false;
    for (n=1; n<=napicked; n++) {
      at = apicked(n);
      x = ZFact*xyzInit(at,1) - xPan - (ZFact-1)*xyzCen(1);
      y = ZFact*xyzInit(at,2) - yPan - (ZFact-1)*xyzCen(2);
      DrawAtom(p, at, x, y, circDia+4);
      if (n > 1) DrawLine(p, xprev, yprev, x, y);
      xprev = x;
      yprev = y;
    }
    ATOM_3DSPHERE = dum;
  }

  // highlight the atoms in selected chains
  if (!paintEPS && nchain > 0) {
    pen->setColor(Qt::green);
    pen->setWidth(2);
    p->setPen(*pen);

    for (ichain=1; ichain<=nchain; ichain++) {
      for (i=1; i<=nachain(ichain); i++) {
	a = achain(ichain,i);
	x = ZFact*xyzInit(a,1) - xPan - (ZFact-1)*xyzCen(1);
	y = ZFact*xyzInit(a,2) - yPan - (ZFact-1)*xyzCen(2);	
	if (i>1) DrawLine(p, x0, y0, x, y);       
	x0 = x;
	y0 = y;

      }
    }

    if (!paintEPS && nchain >= 2) {
      QPen *pen2 = new QPen();
      pen2->setColor(Qt::green);
      pen2->setStyle(Qt::DashLine);
      p->setPen(*pen2);

      for (i=1; i<nchain; i+=2) {
	x1 = ZFact*dposchain(i,1) - xPan - (ZFact-1)*xyzCen(1);
	y1 = ZFact*dposchain(i,2) - yPan - (ZFact-1)*xyzCen(2);
	x2 = ZFact*dposchain(i+1,1) - xPan - (ZFact-1)*xyzCen(1);
	y2 = ZFact*dposchain(i+1,2) - yPan - (ZFact-1)*xyzCen(2);
	DrawLine(p, x1, y1, x2, y2);
      }
    }
  }

  // plotting the coordinate system centered at the initial position of
  // the dislocation line
  if (PlaneTraces) DrawPlaneTraces(p, x0, y0, x1, y1);

  // plotting of arrows
  if (arrNeighNum > 0) {
    if (!paintEPS) {
      pen->setColor(Qt::black);
      pen->setWidth(thicknessArrow);
      p->setPen(*pen); 
      p->setBrush(Qt::black);
    }
    
    switch(DispComponent) {
      case EDGE:
	plotEdgeComponent(p);
	break;
	
      case SCREW:
	plotScrewComponent(p);
	break;
      
      case PROJ:
	plotScrewComponent(p);   // plotted the same way as screw components
	break;
      
      case DIFF_EDGE:
      case DIFF_SCREW:
	plotDifference(p);
	break;
    }
  }
  
  // position of dislocation center
  if (DisloCenter) {
    DrawLine(p, xCore, y0, xCore, y1);    
    DrawLine(p, x0, yCore, x1, yCore);    
  }

  // small inset to show the active Z-layers
  if (!paintEPS && showZLayers)
    ShowActiveZLayers(p);

  // show color map
  if (!paintEPS && (plotType == PLOT_ATOM_TYPES || plotType == PLOT_ATOM_NEIGHBORS))
    ShowColorMap(p);

  // lines showing the division of the block into cells (for the linked neighbor list)
  if (showNeighCells) {
    if (!paintEPS) {
      pen->setColor(Qt::black);
      p->setPen(*pen);
    }

    for (i=0; i<=ncell(1); i++) {
      x = ZFact*(xyzMin(1)+i*cellsize(1)) - xPan - (ZFact-1)*xyzCen(1);
      y0 = ZFact*xyzMin(2) - yPan - (ZFact-1)*xyzCen(2);
      y1 = ZFact*xyzMax(2) - yPan - (ZFact-1)*xyzCen(2);
      DrawLine(p, x, y0, x, y1);    
      
      for (j=0; j<=ncell(2); j++) {
	y = ZFact*(xyzMin(2)+j*cellsize(2)) - yPan - (ZFact-1)*xyzCen(2);
	x0 = ZFact*xyzMin(1) - xPan - (ZFact-1)*xyzCen(1);
	x1 = ZFact*xyzMax(1) - xPan - (ZFact-1)*xyzCen(1);
	DrawLine(p, x0, y, x1, y);
      }
    }
  }

  // coordinate system of the block
  if (!paintEPS && showCSys)
    ShowCSys(p);

  // show the polygon that encompasses the dislocation center
  if (!paintEPS && ndpoly > 0) {
    pen->setColor(Qt::green);
    p->setPen(*pen);

    for (n=1; n<=ndpoly; n++) {
      x1 = ZFact*dpoly(n,1) - xPan - (ZFact-1)*xyzCen(1);
      y1 = ZFact*dpoly(n,2) - yPan - (ZFact-1)*xyzCen(2);
      if (n<ndpoly) {
	x2 = ZFact*dpoly(n+1,1) - xPan - (ZFact-1)*xyzCen(1);
	y2 = ZFact*dpoly(n+1,2) - yPan - (ZFact-1)*xyzCen(2);
      } else {
	x2 = ZFact*dpoly(1,1) - xPan - (ZFact-1)*xyzCen(1);
	y2 = ZFact*dpoly(1,2) - yPan - (ZFact-1)*xyzCen(2);
      }
      DrawLine(p, x1, y1, x2, y2);
    }
  }

  if (!paintEPS && ndpath > 0) {
    pen->setColor(Qt::green);
    p->setPen(*pen);
    brush->setColor(Qt::green);
    brush->setStyle(Qt::NoBrush);
    p->setBrush(*brush);

    for (n=1; n<ndpath; n++) {
      x1 = ZFact*dpath(n,1) - xPan - (ZFact-1)*xyzCen(1);
      y1 = ZFact*dpath(n,2) - yPan - (ZFact-1)*xyzCen(2);
      x2 = ZFact*dpath(n+1,1) - xPan - (ZFact-1)*xyzCen(1);
      y2 = ZFact*dpath(n+1,2) - yPan - (ZFact-1)*xyzCen(2);
      DrawLine(p, x1, y1, x2, y2);
      if (n==1) {
	xyWorldToScreen(x1, y1, xs, ys);
	xs -= 2;
	ys -= 2;
	p->drawEllipse(xs, ys, 4, 4);
      }
      xyWorldToScreen(x2, y2, xs, ys);
      xs -= 2;
      ys -= 2;
      p->drawEllipse(xs, ys, 4, 4);
    }
  }
}
Exemplo n.º 3
0
void UnstructuredBlock< NDIM >::build_faces_from_cells() {
    // pointers.
    int *pcltpn, *pclnds, *pclfcs, *pfctpn, *pfcnds, *pfccls;
    int *pifctpn, *pjfctpn, *pifcnds, *pjfcnds;
    int *pndfcs;
    // buffers.
    int *ndnfc, *ndfcs, *map, *map2;
    // scalars.
    int tpnicl, ndmfc, cond;
    // iterator.
    int icl, ifc, jfc, inf, jnf, ind, nd1, ifl;
    int it;

    const index_type mface = calc_max_nface(cltpn());
    index_type computed_nface = -1;

    // create temporary tables.
    LookupTable<index_type, MAX_CLNFC+1> tclfcs(0, ncell());
    LookupTable<index_type,           0> tfctpn(0, mface);
    LookupTable<index_type, MAX_FCNND+1> tfcnds(0, mface);
    LookupTable<index_type,     FCNCL  > tfccls(0, mface);
    tclfcs.fill(-1); tfcnds.fill(-1); tfccls.fill(-1);
    index_type * lclfcs = reinterpret_cast<index_type *>(tclfcs.row(0));
    index_type * lfctpn = reinterpret_cast<shape_type *>(tfctpn.row(0));
    index_type * lfcnds = reinterpret_cast<index_type *>(tfcnds.row(0));
    index_type * lfccls = reinterpret_cast<index_type *>(tfccls.row(0));

    // extract face definition from the node list of cells.
    pcltpn = reinterpret_cast<index_type *>(cltpn().row(0));
    pclnds = reinterpret_cast<index_type *>(clnds().row(0));
    pclfcs = lclfcs;
    pfctpn = lfctpn;
    pfcnds = lfcnds;
    ifc = 0;
    for (icl=0; icl<ncell(); icl++) {
        tpnicl = pcltpn[0];
        // parse each type of cell.
        if (tpnicl == 0) {
        } else if (tpnicl == 1) {   // line.
            // extract 2 points from a line.
            pclfcs[0] = 2;
            for (it=0; it<pclfcs[0]; it++) {
                pfctpn[it] = 0; // face type is point.
                pfcnds[it*(FCMND+1)] = 1;   // number of nodes per face.
            };
            pfctpn += pclfcs[0];
            // face 1.
            pclfcs[1] = ifc;
            pfcnds[1] = pclnds[1];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 2.
            pclfcs[2] = ifc;
            pfcnds[1] = pclnds[2];
            pfcnds += FCMND+1;
            ifc += 1;
        } else if (tpnicl == 2) {   // quadrilateral.
            // extract 4 lines from a quadrilateral.
            pclfcs[0] = 4;
            for (it=0; it<pclfcs[0]; it++) {
                pfctpn[it] = 1; // face type is line.
                pfcnds[it*(FCMND+1)] = 2;   // number of nodes per face.
            };
            pfctpn += pclfcs[0];
            // face 1.
            pclfcs[1] = ifc;
            pfcnds[1] = pclnds[1];
            pfcnds[2] = pclnds[2];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 2.
            pclfcs[2] = ifc;
            pfcnds[1] = pclnds[2];
            pfcnds[2] = pclnds[3];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 3.
            pclfcs[3] = ifc;
            pfcnds[1] = pclnds[3];
            pfcnds[2] = pclnds[4];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 4.
            pclfcs[4] = ifc;
            pfcnds[1] = pclnds[4];
            pfcnds[2] = pclnds[1];
            pfcnds += FCMND+1;
            ifc += 1;
        } else if (tpnicl == 3) {   // triangle.
            // extract 3 lines from a triangle.
            pclfcs[0] = 3;
            for (it=0; it<pclfcs[0]; it++) {
                pfctpn[it] = 1; // face type is line.
                pfcnds[it*(FCMND+1)] = 2;   // number of nodes per face.
            };
            pfctpn += pclfcs[0];
            // face 1.
            pclfcs[1] = ifc;
            pfcnds[1] = pclnds[1];
            pfcnds[2] = pclnds[2];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 2.
            pclfcs[2] = ifc;
            pfcnds[1] = pclnds[2];
            pfcnds[2] = pclnds[3];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 3.
            pclfcs[3] = ifc;
            pfcnds[1] = pclnds[3];
            pfcnds[2] = pclnds[1];
            pfcnds += FCMND+1;
            ifc += 1;
        } else if (tpnicl == 4) {   // hexahedron.
            // extract 6 quadrilaterals from a hexahedron.
            pclfcs[0] = 6;
            for (it=0; it<pclfcs[0]; it++) {
                pfctpn[it] = 2; // face type is quadrilateral.
                pfcnds[it*(FCMND+1)] = 4;   // number of nodes per face.
            };
            pfctpn += pclfcs[0];
            // face 1.
            pclfcs[1] = ifc;
            pfcnds[1] = pclnds[1];
            pfcnds[2] = pclnds[4];
            pfcnds[3] = pclnds[3];
            pfcnds[4] = pclnds[2];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 2.
            pclfcs[2] = ifc;
            pfcnds[1] = pclnds[2];
            pfcnds[2] = pclnds[3];
            pfcnds[3] = pclnds[7];
            pfcnds[4] = pclnds[6];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 3.
            pclfcs[3] = ifc;
            pfcnds[1] = pclnds[5];
            pfcnds[2] = pclnds[6];
            pfcnds[3] = pclnds[7];
            pfcnds[4] = pclnds[8];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 4.
            pclfcs[4] = ifc;
            pfcnds[1] = pclnds[1];
            pfcnds[2] = pclnds[5];
            pfcnds[3] = pclnds[8];
            pfcnds[4] = pclnds[4];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 5.
            pclfcs[5] = ifc;
            pfcnds[1] = pclnds[1];
            pfcnds[2] = pclnds[2];
            pfcnds[3] = pclnds[6];
            pfcnds[4] = pclnds[5];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 6.
            pclfcs[6] = ifc;
            pfcnds[1] = pclnds[3];
            pfcnds[2] = pclnds[4];
            pfcnds[3] = pclnds[8];
            pfcnds[4] = pclnds[7];
            pfcnds += FCMND+1;
            ifc += 1;
        } else if (tpnicl == 5) {   // tetrahedron.
            // extract 4 triangles from a tetrahedron.
            pclfcs[0] = 4;
            for (it=0; it<pclfcs[0]; it++) {
                pfctpn[it] = 3; // face type is triangle.
                pfcnds[it*(FCMND+1)] = 3;   // number of nodes per face.
            };
            pfctpn += pclfcs[0];
            // face 1.
            pclfcs[1] = ifc;
            pfcnds[1] = pclnds[1];
            pfcnds[2] = pclnds[3];
            pfcnds[3] = pclnds[2];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 2.
            pclfcs[2] = ifc;
            pfcnds[1] = pclnds[1];
            pfcnds[2] = pclnds[2];
            pfcnds[3] = pclnds[4];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 3.
            pclfcs[3] = ifc;
            pfcnds[1] = pclnds[1];
            pfcnds[2] = pclnds[4];
            pfcnds[3] = pclnds[3];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 4.
            pclfcs[4] = ifc;
            pfcnds[1] = pclnds[2];
            pfcnds[2] = pclnds[3];
            pfcnds[3] = pclnds[4];
            pfcnds += FCMND+1;
            ifc += 1;
        } else if (tpnicl == 6) {   // prism.
            // extract 2 triangles and 3 quadrilaterals from a prism.
            pclfcs[0] = 5;
            for (it=0; it<2; it++) {
                pfctpn[it] = 3; // face type is triangle.
                pfcnds[it*(FCMND+1)] = 3;   // number of nodes per face.
            };
            for (it=2; it<pclfcs[0]; it++) {
                pfctpn[it] = 2; // face type is quadrilateral.
                pfcnds[it*(FCMND+1)] = 4;   // number of nodes per face.
            };
            pfctpn += pclfcs[0];
            // face 1.
            pclfcs[1] = ifc;
            pfcnds[1] = pclnds[1];
            pfcnds[2] = pclnds[2];
            pfcnds[3] = pclnds[3];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 2.
            pclfcs[2] = ifc;
            pfcnds[1] = pclnds[4];
            pfcnds[2] = pclnds[6];
            pfcnds[3] = pclnds[5];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 3.
            pclfcs[3] = ifc;
            pfcnds[1] = pclnds[1];
            pfcnds[2] = pclnds[4];
            pfcnds[3] = pclnds[5];
            pfcnds[4] = pclnds[2];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 4.
            pclfcs[4] = ifc;
            pfcnds[1] = pclnds[1];
            pfcnds[2] = pclnds[3];
            pfcnds[3] = pclnds[6];
            pfcnds[4] = pclnds[4];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 5.
            pclfcs[5] = ifc;
            pfcnds[1] = pclnds[2];
            pfcnds[2] = pclnds[5];
            pfcnds[3] = pclnds[6];
            pfcnds[4] = pclnds[3];
            pfcnds += FCMND+1;
            ifc += 1;
        } else if (tpnicl == 7) {   // pyramid.
            // extract 4 triangles and 1 quadrilaterals from a pyramid.
            pclfcs[0] = 5;
            for (it=0; it<4; it++) {
                pfctpn[it] = 3; // face type is triangle.
                pfcnds[it*(FCMND+1)] = 3;   // number of nodes per face.
            };
            for (it=4; it<pclfcs[0]; it++) {
                pfctpn[it] = 2; // face type is quadrilateral.
                pfcnds[it*(FCMND+1)] = 4;   // number of nodes per face.
            };
            pfctpn += pclfcs[0];
            // face 1.
            pclfcs[1] = ifc;
            pfcnds[1] = pclnds[1];
            pfcnds[2] = pclnds[5];
            pfcnds[3] = pclnds[4];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 2.
            pclfcs[2] = ifc;
            pfcnds[1] = pclnds[2];
            pfcnds[2] = pclnds[5];
            pfcnds[3] = pclnds[1];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 3.
            pclfcs[3] = ifc;
            pfcnds[1] = pclnds[3];
            pfcnds[2] = pclnds[5];
            pfcnds[3] = pclnds[2];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 4.
            pclfcs[4] = ifc;
            pfcnds[1] = pclnds[4];
            pfcnds[2] = pclnds[5];
            pfcnds[3] = pclnds[3];
            pfcnds += FCMND+1;
            ifc += 1;
            // face 5.
            pclfcs[5] = ifc;
            pfcnds[1] = pclnds[1];
            pfcnds[2] = pclnds[4];
            pfcnds[3] = pclnds[3];
            pfcnds[4] = pclnds[2];
            pfcnds += FCMND+1;
            ifc += 1;
        };
        // advance pointers.
        pcltpn += 1;
        pclnds += CLMND+1;
        pclfcs += CLMFC+1;
    };

    // build the hash table, to know what faces connect to each node.
    /// first pass: get the maximum number of faces.
    ndnfc = (int *)malloc((size_t)nnode()*sizeof(int));
    for (ind=0; ind<nnode(); ind++) {    // initialize.
        ndnfc[ind] = 0;
    };
    pfcnds = lfcnds; // count.
    for (ifc=0; ifc<mface; ifc++) {
        for (inf=1; inf<=pfcnds[0]; inf++) {
            ind = pfcnds[inf];  // node of interest.
            ndnfc[ind] += 1;    // increment counting.
        };
        // advance pointers.
        pfcnds += FCMND+1;
    };
    ndmfc = 0;  // get maximum.
    for (ind=0; ind<nnode(); ind++) {
        if (ndnfc[ind] > ndmfc) {
            ndmfc = ndnfc[ind];
        };
    };
    free(ndnfc);
    /// second pass: scan again to build hash table.
    ndfcs = (int *)malloc((size_t)nnode()*(ndmfc+1)*sizeof(int));
    pndfcs = ndfcs; // initialize.
    for (ind=0; ind<nnode(); ind++) {
        pndfcs[0] = 0;
        for (it=1; it<=ndmfc; it++) { // <= or < ??
            pndfcs[it] = -1;
        };
        // advance pointers;
        pndfcs += ndmfc+1;
    };
    pfcnds = lfcnds; // build hash table mapping from node to face.
    for (ifc=0; ifc<mface; ifc++) {
        for (inf=1; inf<=pfcnds[0]; inf++) {
            ind = pfcnds[inf];  // node of interest.
            pndfcs = ndfcs + ind*(ndmfc+1);
            pndfcs[0] += 1; // increment face count for the node.
            pndfcs[pndfcs[0]] = ifc;
        };
        // advance pointers.
        pfcnds += FCMND+1;
    };

    // scan for duplicated faces and build duplication map.
    map = (int *)malloc((size_t)mface*sizeof(int));
    for (ifc=0; ifc<mface; ifc++) { // initialize.
        map[ifc] = ifc;
    };
    for (ifc=0; ifc<mface; ifc++) {
        if (map[ifc] == ifc) {
            pifcnds = lfcnds + ifc*(FCMND+1);
            nd1 = pifcnds[1];    // take only the FIRST node of a face.
            pndfcs = ndfcs + nd1*(ndmfc+1);
            for (it=1; it<=pndfcs[0]; it++) {
                jfc = pndfcs[it];
                // test for duplication.
                if ((jfc != ifc) && (lfctpn[jfc] == lfctpn[ifc])) {
                    pjfcnds = lfcnds + jfc*(FCMND+1);
                    cond = pjfcnds[0];
                    // scan all nodes in ifc and jfc to see if all the same.
                    for (jnf=1; jnf<=pjfcnds[0]; jnf++) {
                        for (inf=1; inf<=pifcnds[0]; inf++) {
                            if (pjfcnds[jnf] == pifcnds[inf]) {
                                cond -= 1;
                                break;
                            };
                        };
                    };
                    if (cond == 0) {
                        map[jfc] = ifc;  // record duplication.
                    };
                };
            };
        };
    };

    // use the duplication map to remap nodes in faces, and build renewed map.
    map2 = (int *)malloc((size_t)mface*sizeof(int));
    pifcnds = lfcnds;
    pjfcnds = lfcnds;
    pifctpn = lfctpn;
    pjfctpn = lfctpn;
    jfc = 0;
    for (ifc=0; ifc<mface; ifc++) {
        if (map[ifc] == ifc) {
            for (inf=0; inf<=FCMND; inf++) {
                pjfcnds[inf] = pifcnds[inf];
            };
            pjfctpn[0] = pifctpn[0];
            map2[ifc] = jfc;
            // increment j-face.
            jfc += 1;
            pjfcnds += FCMND+1;
            pjfctpn += 1;
        } else {
            map2[ifc] = map2[map[ifc]];
        };
        // advance pointers;
        pifcnds += FCMND+1;
        pifctpn += 1;
    };
    computed_nface = jfc;    // record deduplicated number of face.

    // rebuild faces in cells and build face neighboring, according to the
    // renewed face map.
    pfccls = lfccls; // initialize.
    for (ifc=0; ifc<mface; ifc++) {
        for (it=0; it<FCREL; it++) {
            pfccls[it] = -1;
        };
        // advance pointers;
        pfccls += FCREL;
    };
    pclfcs = lclfcs;
    for (icl=0; icl<ncell(); icl++) {
        for (ifl=1; ifl<=pclfcs[0]; ifl++) {
            ifc = pclfcs[ifl];
            jfc = map2[ifc];
            // rebuild faces in cells.
            pclfcs[ifl] = jfc;
            // build face neighboring.
            pfccls = lfccls + jfc*FCREL;
            if (pfccls[0] == -1) {
                pfccls[0] = icl;
            } else if (pfccls[1] == -1) {
                pfccls[1] = icl;
            };
        };
        // advance pointers;
        pclfcs += CLMFC+1;
    };

    free(map2);
    free(map);
    free(ndfcs);

    // recreate member tables.
    set_nface(computed_nface);
    create_fctpn(0, nface());
    create_fcnds(0, nface());
    create_fccls(0, nface());
    for (icl=0; icl < ncell(); ++icl) {
        clfcs().set(icl, tclfcs[icl]);
    }
    for (ifc=0; ifc < nface(); ++ifc) {
        fctpn().set(ifc, tfctpn[ifc]);
        fcnds().set(ifc, tfcnds[ifc]);
        fccls().set(ifc, tfccls[ifc]);
    }
    create_fccnd(0, nface());
    create_fcnml(0, nface());
    create_fcara(0, nface());
}