00001 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 #include "ParFUM.h"
00031 #include "ParFUM_internals.h"
00032 
00033 
00034 
00035 static void checkEquality(const char *what, 
00036               int v1,const char *src1, 
00037               int v2,const char *src2)
00038 {
00039   if (v1!=v2) {
00040     CkPrintf("FEM> %s value %d, from %d, doesn't match %d, from %d!\n",
00041          what, v1,src1, v2,src2);
00042     CkAbort("FEM Equality assertation failed");
00043   }
00044 }
00045 static void checkRange(const char *what,int v,int max)
00046 {
00047   if ((v<0)||(v>=max)) {
00048     CkPrintf("FEM> %s value %d should be between 0 and %d!\n",
00049          what,v,max);
00050     CkAbort("FEM Range assertation failed");
00051   }
00052 }
00053 
00054 static void checkArrayEntries(const int *arr,int nArr,int max,const char *what)
00055 {
00056 #if CMK_ERROR_CHECKING
00057   
00058   for (int e=0;e<nArr;e++) checkRange(what,arr[e],max);
00059 #endif
00060 }
00061 
00062 
00063 static void check(const FEM_Mesh *mesh) {
00064 #if 0 //FIXME
00065   for (int t=0;t<mesh->elem.size();t++) 
00066     if (mesh->elem.has(t)) {
00067       
00068       checkArrayEntries(mesh->elem[t].getConn().getData(),
00069             mesh->elem[t].size()*mesh->elem[t].getNodesPer(),
00070             mesh->node.size(), "element connectivity, from FEM_Set_Elem_Conn,");
00071     }
00072   for (int s=0;s<mesh->nSparse();s++) {
00073     
00074     const FEM_Sparse &src=mesh->getSparse(s);
00075     checkArrayEntries(src.getNodes(0),src.size()*src.getNodesPer(),
00076               mesh->node.size(), "sparse data nodes, from FEM_Set_Sparse,");
00077     if (src.getElem())
00078       checkArrayEntries(src.getElem(),src.size()*2,
00079             mesh->nElems(),"sparse data elements, from FEM_Set_Sparse_Elem,");
00080   }
00081 #endif
00082 }
00083 static void check(const FEM_Partition &partition,const FEM_Mesh *mesh) {
00084   const int *canon=partition.getCanon();
00085   if (canon!=NULL)
00086     checkArrayEntries(canon,mesh->node.size(),mesh->node.size(),
00087               "node canonicalization array, from FEM_Set_Symmetries");
00088 }
00089 
00091 void FEM_Ghost_Stencil::check(const FEM_Mesh &mesh) const {
00092   const FEM_Elem &elem=mesh.elem[mesh.chkET(elType)];
00093   checkEquality("number of elements",
00094         n,"FEM_Ghost_stencil",
00095         elem.size(),"mesh");
00096   int i,prevEnd=0;
00097   for (i=0;i<n;i++) {
00098     int nElts=ends[i]-prevEnd;
00099     checkRange("FEM_Ghost_stencil index array",nElts,n);
00100     prevEnd=ends[i];
00101   }
00102   int m=ends[n-1];
00103   for (i=0;i<m;i++) {
00104     int t=adj[2*i+0];
00105     mesh.chkET(t);
00106     checkRange("FEM_Ghost_stencil neighbor array",
00107            adj[2*i+1],mesh.elem[t].size());
00108   }
00109 }
00110 
00111 
00112 
00124 class dynChunk {
00125 public:
00126   typedef CkVec<int> dynList;
00127   NumberedVec<dynList> elem; 
00128   dynList node;
00129     
00130   
00131   int addRealElement(int type,int globalNo) {
00132     elem[type].push_back(globalNo);
00133     return elem[type].size()-1;
00134   }
00135   int addRealNode(int globalNo) {
00136     node.push_back(globalNo);
00137     return node.size()-1;
00138   }
00139 };
00140 
00145 class splitter {
00146   
00147   FEM_Mesh *mesh; 
00148   const int *elem2chunk; 
00149   int nChunks; 
00150   
00151   FEM_Mesh **chunks; 
00152 
00153   
00154   chunkList *gNode; 
00155   CkVec<chunkList *> gElem;
00156   dynChunk *dyn; 
00157     
00162   void renumberNodesLocal(int row, BasicTable2d<int> &table, 
00163               int chunk, FEM_Symmetries_t sym)
00164   {
00165     int *nodes=table.getRow(row);
00166     int nNodes=table.width();
00167     for (int i=0;i<nNodes;i++)
00168       nodes[i]=gNode[nodes[i]].localOnChunk(chunk,sym);
00169   }
00170 
00171   
00172   FEM_Sparse **sparseDest; 
00173     
00175   void copySparse(const FEM_Sparse &src,int s,int chunk,FEM_Symmetries_t sym) {
00176     FEM_Sparse *dest=sparseDest[chunk];
00177     int d=dest->push_back(src,s);
00178     renumberNodesLocal(d, dest->setConn(), chunk, sym);
00179     
00180     if (dest->hasElements()) {
00181       
00182       
00183       
00184     }
00185   }
00186     
00188   void copySparseChunks(const FEM_Sparse &src,int s,bool forGhost);
00189     
00190     
00191   
00192   unsigned char *ghostNode; 
00193   const int *canon; 
00194   const FEM_Symmetries_t *sym; 
00195   int curGhostLayerNo; 
00196   int totGhostElem,totGhostNode; 
00197 
00199   void addStencil(const FEM_Ghost_Stencil &s,const FEM_Partition &partition);
00200 
00202   void addLayer(const FEM_Ghost_Layer &g,const FEM_Partition &partition);
00203     
00205   bool hasGhostNodes(const int *conn,int nodesPer) 
00206   {
00207     for (int i=0;i<nodesPer;i++)
00208       if (ghostNode[conn[i]])
00209     return true;
00210     return false;
00211   }
00212 
00214   bool addTuple(int *dest,FEM_Symmetries_t *destSym,
00215         const int *elem2tuple,int nodesPerTuple,const int *conn) const;
00216 
00218   void addSymmetryGhost(const elemList &a);
00220   void addGlobalGhost(int srcType,int srcNum,  int destType,int destNum, bool addNodes);
00221     
00224   void addGhostPair(const elemList &src,const elemList &dest,bool addNodes);
00225 
00227   int addGhostElement(int t,int gNo,int srcChunk,int destChunk,FEM_Symmetries_t sym);
00228     
00230   int addGhostNode(int gnNo,int srcChunk,int destChunk,FEM_Symmetries_t sym);
00231     
00233   int addGhostInner(const FEM_Entity &gEnt,int gNo, chunkList &gDest,
00234             int srcChunk,FEM_Entity &srcEnt, int destChunk,FEM_Entity &destEnt,
00235             FEM_Symmetries_t sym, int isNode, int t);
00236     
00238   void addElemElems(const FEM_Partition &partition);
00239   void buildElemElemData(const FEM_ElemAdj_Layer &g,const FEM_Partition &partition);
00240   
00241 
00242 
00243   
00244   void bad(const char *why) {
00245     CkAbort(why);
00246   }
00247   void equal(int is,int should,const char *what) {
00248     if (is!=should) {
00249       CkPrintf("ERROR! Expected %s to be %d, got %d!\n",
00250            what,should,is);
00251       bad("Internal FEM data structure corruption! (unequal)\n");
00252     }
00253   }
00254   void range(int value,int lo,int hi,const char *what) {
00255     if (value<lo || value>=hi) {
00256       CkPrintf("ERROR! %s: %d is out of range (%d,%d)!\n",what,value,lo,hi);
00257       bad("Internal FEM data structure corruption! (out of range)\n");
00258     }
00259   }
00260   void nonnegative(int value,const char *what) {
00261     if (value<0) {
00262       CkPrintf("ERROR! Expected %s to be non-negative, got %d!\n",
00263            what,value);
00264       bad("Internal FEM data structure corruption! (negative)\n");
00265     }
00266   }
00267 
00268 public:
00269   splitter(FEM_Mesh *mesh_,const int *elem2chunk_,int nChunks_);
00270   ~splitter();
00271 
00272   
00273   void buildCommLists(void);
00274     
00275   
00276   void addGhosts(const FEM_Partition &partition);
00277     
00278   
00279   void separateSparse(bool forGhost);
00280     
00281   
00282   void aboutToCreate(void);
00283     
00284   
00285   FEM_Mesh *createMesh(int c);
00286     
00287   void consistencyCheck(void);
00288 
00289 };
00290 
00291 
00292 splitter::splitter(FEM_Mesh *mesh_,const int *elem2chunk_,int nChunks_)
00293   :mesh(mesh_), elem2chunk(elem2chunk_),nChunks(nChunks_)
00294 {
00295   chunks=new FEM_Mesh* [nChunks];
00296   dyn=new dynChunk[nChunks];
00297   int c;
00298   for (c=0;c<nChunks;c++) {
00299     chunks[c]=new FEM_Mesh; 
00300     chunks[c]->copyShape(*mesh);
00301     dyn[c].elem.makeLonger(mesh->elem.size()-1);
00302   }
00303     
00304   gNode=new chunkList[mesh->node.size()];
00305   gElem.resize(mesh->elem.size());
00306   for (int t=0;t<mesh->elem.size();t++) {
00307     if (mesh->elem.has(t))
00308       gElem[t]=new chunkList[mesh->elem[t].size()];
00309     else
00310       gElem[t]=NULL;
00311   }
00312     
00313   sparseDest=new FEM_Sparse* [nChunks];
00314   ghostNode=NULL;
00315   canon=NULL;
00316 }
00317 
00318 splitter::~splitter() {
00319   delete[] gNode;
00320   delete[] dyn;
00321   for (int t=0;t<mesh->elem.size();t++)
00322     delete[] gElem[t];
00323   for (int c=0;c<nChunks;c++)
00324     delete chunks[c];
00325   delete[] chunks;
00326   delete[] sparseDest;
00327 }
00328 
00329 void splitter::buildCommLists(void)
00330 {
00331   
00332   
00333   int t;
00334   int e;
00335   int n;
00336   for (t=0;t<mesh->elem.size();t++) 
00337     if (mesh->elem.has(t)) {
00338       int typeStart=mesh->nElems(t);
00339       const FEM_Elem &src=mesh->elem[t]; 
00340       for (e=0;e<src.size();e++) {
00341     int c=elem2chunk[typeStart+e];
00342     const int *srcConn=src.getConn().getRow(e);
00343     gElem[t][e].set(c,dyn[c].addRealElement(t,e),noSymmetries,-1);
00344     int lNo=dyn[c].node.size();
00345     for (n=0;n<src.getNodesPer();n++) {
00346       int gNo=srcConn[n];
00347       if (gNode[gNo].addchunk(c,lNo,noSymmetries,-1)) {
00348         
00349         dyn[c].addRealNode(gNo);
00350         lNo++;
00351       }
00352     }
00353       }
00354     }
00355     
00356   
00357   for (n=0;n<mesh->node.size();n++) {
00358     if (gNode[n].isShared()) 
00359       {
00360 
00361     int len=gNode[n].length();
00362     for (int bi=0;bi<len;bi++)
00363       for (int ai=0;ai<bi;ai++)
00364         {
00365           chunkList &a=gNode[n][ai];
00366           chunkList &b=gNode[n][bi];
00367           chunks[a.chunk]->node.shared.add(
00368                            a.chunk,a.localNo,
00369                            b.chunk,b.localNo,
00370                            chunks[b.chunk]->node.shared);
00371         }
00372       }
00373   }
00374 }
00375 
00376 
00377 
00378 void splitter::aboutToCreate() 
00379 {
00380   for (int t=0;t<mesh->elem.size();t++)
00381     {delete[] gElem[t];gElem[t]=NULL;}
00382 }
00383 
00384 
00385 
00386 
00387 FEM_Mesh *splitter::createMesh(int c)
00388 {
00389   int t;
00390   FEM_Mesh &dest=*chunks[c];
00391 
00392   dest.udata=mesh->udata;
00393     
00394   
00395   FEM_Node *destNode=&dest.node;
00396   const dynChunk::dynList &srcIdx=dyn[c].node;
00397   int nNode=srcIdx.size();
00398   destNode->setLength(nNode);
00399   for (int lNo=0;lNo<nNode;lNo++) {
00400     int gNo=srcIdx[lNo];
00401     
00402     destNode->copyEntity(lNo, mesh->node, gNo);
00403     destNode->setSymmetries(lNo,noSymmetries);
00404     
00405     chunkList *head=&gNode[gNo];
00406     const chunkList *cur=head->onChunk(c,noSymmetries);
00407     destNode->setPrimary(lNo,head==cur);
00408   }
00409 
00410   
00411   for (t=0;t<dest.elem.size();t++) 
00412     if (dest.elem.has(t)) 
00413       {
00414     FEM_Elem *destElem=&dest.elem[t];
00415     const dynChunk::dynList &srcIdx=dyn[c].elem[t];
00416     int nEl=srcIdx.size();
00417     destElem->setLength(nEl);
00418     for (int lNo=0;lNo<nEl;lNo++) {
00419       int gNo=srcIdx[lNo];
00420       
00421       destElem->copyEntity(lNo, mesh->elem[t], gNo);
00422       
00423       renumberNodesLocal(lNo, destElem->setConn(), c,noSymmetries);
00424     }
00425       }
00426     
00427   chunks[c]=NULL;
00428   dest.becomeGetting(); 
00429   return &dest;
00430 }
00431 
00432 
00433 
00434 
00435 
00436 void FEM_Mesh_split(FEM_Mesh *mesh,int nChunks,
00437             const FEM_Partition &partition,FEM_Mesh_Output *out)
00438 {
00439   const int *elem2chunk=partition.getPartition(mesh,nChunks);
00440   
00441   CkThresholdTimer time("FEM Split> Setting up",1.0);
00442   checkArrayEntries(elem2chunk,mesh->nElems(),nChunks,
00443             "elem2chunk, from FEM_Set_Partition or metis,");
00444   check(mesh);
00445   check(partition,mesh);
00446     
00447   mesh->setSymList(partition.getSymList());
00448   splitter s(mesh,elem2chunk,nChunks);
00449 
00450   time.start("FEM Split> Finding comm lists");
00451   s.buildCommLists();
00452     
00453   time.start("FEM Split> Finding ghosts");
00454   s.separateSparse(false); 
00455   s.addGhosts(partition);
00456   s.separateSparse(true); 
00457     
00458   time.start("FEM Split> Copying mesh data");
00459   
00460   s.aboutToCreate(); 
00461   for (int c=0;c<nChunks;c++)
00462     out->accept(c,s.createMesh(c));
00463 }
00464 
00465 
00466 
00468 void splitter::copySparseChunks(const FEM_Sparse &src,int s,bool forGhost)
00469 {
00470   if (src.hasElements()) 
00471     { 
00472       const int *elemRec=src.getElem().getRow(s);
00473       int t=elemRec[0];
00474       int e=elemRec[1];
00475       if (!forGhost) 
00476     { 
00477       copySparse(src,s,elem2chunk[mesh->getGlobalElem(t,e)],noSymmetries);
00478     } else { 
00479       chunkList *cur=&gElem[t][e]; 
00480       while (cur!=NULL) {
00481         if (FEM_Is_ghost_index(cur->localNo)) 
00482           copySparse(src,s,cur->chunk,cur->sym);
00483         cur=cur->next;
00484       }
00485     }
00486     }
00487   else
00488     { 
00489       int nNodes=src.getConn().width();
00490       if (nNodes==0) CkAbort("Registered an FEM sparse without nodes or elements");
00491       FEM_Symmetries_t sym=noSymmetries; 
00492       const int *nodes=src.getConn().getRow(s);
00493       int nCopied=0;
00494         
00495       
00496       for (const chunkList *cur=&gNode[nodes[0]];cur!=NULL;cur=cur->next)
00497     {
00498       int testchunk=cur->chunk;
00499       bool hasGhost=false; 
00500       for (int i=0;i<nNodes;i++) {
00501         const chunkList *li=gNode[nodes[i]].onChunk(testchunk,sym);
00502         if (li==NULL) 
00503           { testchunk=-1; break;  }
00504         if (FEM_Is_ghost_index(li->localNo))
00505           hasGhost=true;
00506       }
00507       if (testchunk==-1) continue; 
00508       if (forGhost && !hasGhost) continue; 
00509       copySparse(src,s,testchunk,sym);
00510       nCopied++;
00511     }
00512       if (nCopied==0 && !forGhost) FEM_Abort("copySparseChunks",
00513                          "Sparse record %d does not lie on any chunk!",s);
00514     }
00515 }
00516 
00517 
00518 
00519 void splitter::separateSparse(bool forGhost) 
00520 {
00521   for (int t=0;t<mesh->sparse.size();t++) 
00522     if (mesh->sparse.has(t))
00523       { 
00524     
00525     const FEM_Sparse &src=mesh->sparse.get(t);
00526     for (int c=0;c<nChunks;c++) 
00527       { 
00528         FEM_Sparse *d=&chunks[c]->sparse.set(t);
00529         if (forGhost) d=(FEM_Sparse *)d->getGhost();
00530         sparseDest[c]=d;
00531       }
00532         
00533     for (int s=0;s<src.size();s++) copySparseChunks(src,s,forGhost);
00534       }
00535 }
00536 
00537 
00538 
00539 
00540 
00541 
00542 
00543 
00544 
00545 
00546 
00547 
00548 
00549 
00550 
00551 
00552 
00553 
00554 
00555 
00556 
00557 
00558 
00559 
00560 
00561 
00562 
00563 CkHashCode CkHashFunction_ints(const void *keyData,size_t keyLen)
00564 {
00565   const int *d=(const int *)keyData;
00566   int l=keyLen/sizeof(int);
00567   CkHashCode ret=d[0];
00568   for (int i=1;i<l;i++)
00569     ret=ret^circleShift(d[i],i*23);
00570   return ret;
00571 }
00572 
00573 int CkHashCompare_ints(const void *k1,const void *k2,size_t keyLen)
00574 {
00575   const int *d1=(const int *)k1;
00576   const int *d2=(const int *)k2;
00577   int l=keyLen/sizeof(int);
00578   for (int i=0;i<l;i++) if (d1[i]!=d2[i]) return 0;
00579   return 1;
00580 }
00581 
00582 
00583 extern "C" int ck_fem_map_compare_int(const void *a, const void *b)
00584 {
00585   return (*(const int *)a)-(*(const int *)b);
00586 }
00587 
00588 
00589 void splitter::addGhosts(const FEM_Partition &partition)
00590 {
00591   if (partition.getRegions()==0) return; 
00592     
00593   
00594   ghostNode=new unsigned char[mesh->node.size()];
00595   int n,nNode=mesh->node.size();
00596   for (n=0;n<nNode;n++) {
00597     ghostNode[n]=(gNode[n].isShared());
00598   }
00599 
00600   
00601   canon=partition.getCanon();
00602   sym=partition.getSymmetries();
00603   if (sym!=NULL)
00604     for (n=0;n<nNode;n++)
00605       if (sym[n]!=(FEM_Symmetries_t)0)
00606     ghostNode[n]=1;
00607 
00608   
00609   curGhostLayerNo=0;
00610   for (int regNo=0;regNo<partition.getRegions();regNo++)
00611     {
00612       const FEM_Ghost_Region &r=partition.getRegion(regNo);
00613       totGhostElem=0,totGhostNode=0; 
00614       int thisLayer=curGhostLayerNo;
00615         
00616       if (r.layer!=0) {
00617     addLayer(*r.layer,partition);
00618     curGhostLayerNo++;
00619       }
00620       else if (r.stencil!=0) 
00621     { 
00622       addStencil(*r.stencil,partition);
00623     }
00624       else {
00625     curGhostLayerNo++;
00626       }
00627         
00628       if (totGhostElem>0)
00629     CkPrintf("FEM Ghost %s %d> %d new ghost elements, %d new ghost nodes\n",
00630          r.layer?"layer":"stencil",
00631          1+thisLayer,
00632          totGhostElem,totGhostNode);
00633     }
00634     
00635   delete[] ghostNode; ghostNode=NULL;
00636 }
00637 
00638 
00639 void splitter::addStencil(const FEM_Ghost_Stencil &s,const FEM_Partition &partition)
00640 {
00641   int t=s.getType();
00642   s.check(*mesh);
00643   int i,j,n=mesh->elem[t].size();
00644   for (i=0;i<n;i++) {
00645     const int *nbor;
00646     j=0;
00647     while (NULL!= (nbor=s.getNeighbor(i,j++))) {
00648       
00649 
00650       addGlobalGhost(nbor[0],nbor[1],t,i, s.wantNodes());
00651     }
00652   }
00653 }
00654 
00657 void splitter::addGlobalGhost(
00658                   int srcType,int srcNum,  int destType,int destNum, bool doAddNodes)
00659 {
00660   
00661   chunkList &srcC=gElem[srcType][srcNum];
00662   
00663   for (chunkList *destC=&gElem[destType][destNum];
00664        destC!=NULL;
00665        destC=destC->next)
00666     if (srcC.chunk!=destC->chunk 
00667     && destC->layerNo<curGhostLayerNo  
00668     )
00669       { 
00670     elemList src(srcC.chunk, srcC.localNo, srcType, (FEM_Symmetries_t)0);
00671     elemList dest(destC->chunk, destC->localNo, destType, (FEM_Symmetries_t)0);
00672     addGhostPair(src,dest,doAddNodes);
00673       }
00674 }
00675 
00676 
00677 void splitter::addLayer(const FEM_Ghost_Layer &g,const FEM_Partition &partition)
00678 {
00679   tupleTable table(g.nodesPerTuple);
00680     
00681   
00682   for (int t=0;t<mesh->elem.size();t++) 
00683     if (mesh->elem.has(t)) {
00684       if (!g.elem[t].add) continue; 
00685       
00686       int gElemCount=mesh->elem[t].size();
00687       for (int gNo=0;gNo<gElemCount;gNo++) 
00688     {
00689       const int *conn=mesh->elem[t].connFor(gNo);
00690       if (hasGhostNodes(conn,mesh->elem[t].getNodesPer()))
00691         { 
00692           for (chunkList *cur=&gElem[t][gNo];cur!=NULL;cur=cur->next)
00693         for (int u=0;u<g.elem[t].tuplesPerElem;u++)
00694           {
00695             int tuple[tupleTable::MAX_TUPLE];
00696             FEM_Symmetries_t allSym;
00697             if (addTuple(tuple,&allSym,
00698                  &g.elem[t].elem2tuple[u*g.nodesPerTuple],
00699                  g.nodesPerTuple,conn)) {
00700               table.addTuple(tuple,new elemList(cur->chunk,cur->localNo,t,allSym));
00701             }
00702           }
00703         }
00704     }
00705     }
00706     
00707   
00708   table.beginLookup();
00709   elemList *l;
00710   while (NULL!=(l=table.lookupNext())) {
00711     if (l->next==NULL) 
00712       addSymmetryGhost(*l);
00713     else { 
00714       
00715       for (const elemList *a=l;a!=NULL;a=a->next)
00716     for (const elemList *b=l;b!=NULL;b=b->next) 
00717       if (a!=b && a->localNo>=0) 
00718         addGhostPair(*a,*b,g.addNodes);
00719     }
00720   }
00721 }
00722 
00723 
00724 
00725 
00726 bool splitter::addTuple(int *dest,FEM_Symmetries_t *destSym,const int *elem2tuple,
00727             int nodesPerTuple,const int *conn) const
00728 {
00729   FEM_Symmetries_t allSym=(FEM_Symmetries_t)(~0);
00730   for (int i=0;i<nodesPerTuple;i++) {
00731     int eidx=elem2tuple[i];
00732     if (eidx==-1) { 
00733       dest[i]=-1; 
00734     } else { 
00735       int n=conn[eidx];
00736       if (!ghostNode[n]) 
00737     return false; 
00738       if (sym!=NULL) {
00739     allSym=allSym & sym[n]; 
00740     n=canon[n]; 
00741       }
00742       dest[i]=n;
00743     }
00744   }
00745   
00746   if (sym!=NULL) *destSym=allSym; else *destSym=0;
00747   return true;
00748 }
00749 
00750 
00751 void splitter::addSymmetryGhost(const elemList &a)
00752 {
00753   if (a.sym==0) return; 
00754   CkAbort("FEM map> Mirror symmetry ghosts not yet supported");
00755 }
00756 
00757 
00766 void splitter::addGhostPair(const elemList &src,const elemList &dest,bool addNodes)
00767 {
00768   
00769   int srcChunk=src.chunk;
00770   int destChunk=dest.chunk;
00771   int elemSym=dest.sym;
00772   bool isSymmetry=(dest.sym!=0);
00773     
00774   if ((!isSymmetry) && srcChunk==destChunk) 
00775     return; 
00776     
00777   int t=src.type;
00778   if (src.localNo<0) FEM_Abort("addGhostPair","Cannot add a ghost of a ghost (src num=%d)",src.localNo);
00779   int gNo=dyn[srcChunk].elem[t][src.localNo];
00780     
00781   int newNo=addGhostElement(t,gNo,srcChunk,destChunk,elemSym);
00782   if (newNo==-1) return; 
00783   
00784   
00785   
00786   int srcConnN=mesh->elem[t].getNodesPer();
00787   const int *srcConn=mesh->elem[t].connFor(gNo);
00788   
00789   int dt=dest.type;
00790   int destConnN=mesh->elem[dt].getNodesPer();
00791   const int *destConn=NULL; 
00792   FEM_Elem *destElemGhosts=(FEM_Elem *)chunks[destChunk]->elem[t].getGhost();
00793   int *newConn=destElemGhosts->connFor(newNo); 
00794   if (isSymmetry) { 
00795     destConn=mesh->elem[dt].connFor(dyn[destChunk].elem[dt][dest.localNo]); 
00796   }
00797   
00798   
00799   for (int sn=0;sn<srcConnN;sn++)
00800     {
00801       FEM_Symmetries_t nodeSym=noSymmetries;
00802       int gnNo=srcConn[sn];
00803       ghostNode[gnNo]=1; 
00804       if (isSymmetry) 
00805     { 
00806       
00807       
00808       nodeSym=dest.sym; 
00809       for (int dn=0;dn<destConnN;dn++) 
00810         if (canon[destConn[dn]]==canon[gnNo])
00811           { 
00812         gnNo=destConn[dn];
00813         
00814         nodeSym=noSymmetries; 
00815         break;
00816           }
00817     }
00818       if (addNodes)
00819     addGhostNode(gnNo,srcChunk,destChunk,nodeSym);
00820         
00821       
00822       newConn[sn]=gNode[gnNo].localOnChunk(destChunk,nodeSym);
00823     }
00824 }
00825 
00826 
00828 int splitter::addGhostElement(int t,int gNo,int srcChunk,int destChunk,FEM_Symmetries_t sym)
00829 {
00830   FEM_Elem &destEnt=*(FEM_Elem *)chunks[destChunk]->elem[t].getGhost();
00831   int destNo=addGhostInner(mesh->elem[t],gNo,gElem[t][gNo],
00832                srcChunk,chunks[srcChunk]->elem[t], 
00833                destChunk, destEnt,
00834                sym, 0, t);
00835   if (destNo!=-1)
00836     {
00837       totGhostElem++;
00838       return destNo;
00839     }
00840   return -1;
00841 }
00843 int splitter::addGhostNode(int gnNo,int srcChunk,int destChunk,FEM_Symmetries_t sym)
00844 {
00845   int destNo=addGhostInner(mesh->node,gnNo,gNode[gnNo],
00846                srcChunk,chunks[srcChunk]->node, 
00847                destChunk,*chunks[destChunk]->node.getGhost(),
00848                sym, 1, 0);
00849   if (destNo!=-1)
00850     {
00851       totGhostNode++;
00852       return destNo;
00853     }
00854   return -1;
00855 }
00856 
00867 int splitter::addGhostInner(const FEM_Entity &gEnt,int gNo, chunkList &gDest,
00868                 int srcChunk,FEM_Entity &srcEnt, int destChunk,FEM_Entity &destEnt,
00869                 FEM_Symmetries_t sym, int isNode, int t)
00870 {
00871   if (gDest.onChunk(destChunk,sym))
00872     return -1; 
00873   int srcNo=gDest.localOnChunk(srcChunk,noSymmetries);
00874   if (srcNo<0)
00875     return -1; 
00876   
00877   
00878   
00879   int destNo=destEnt.push_back(gEnt,gNo);
00880   destEnt.setSymmetries(destNo,sym);
00881   gDest.addchunk(destChunk,FEM_To_ghost_index(destNo),sym,curGhostLayerNo);
00882   chunkList *l = &gDest;
00883   while(l->next != NULL) {
00884     if(l->chunk != srcChunk && l->chunk != destChunk && l->localNo>=0) {
00885       if(isNode) 
00886     chunks[l->chunk]->node.setGhostSend().add(l->chunk,l->localNo,destChunk,destNo,destEnt.setGhostRecv());
00887       else 
00888     chunks[l->chunk]->elem[t].setGhostSend().add(l->chunk,l->localNo,destChunk,destNo,destEnt.setGhostRecv());
00889     }
00890     l = l->next;
00891   }
00892   srcEnt.setGhostSend().add(srcChunk,srcNo,destChunk,destNo,
00893                 destEnt.setGhostRecv());
00894   return destNo;
00895 }
00896 
00897 
00898 
00899 void splitter::consistencyCheck(void)
00900 {
00901 #if CMK_ERROR_CHECKING
00902   bool skipCheck=false; 
00903 #else
00904   bool skipCheck=true; 
00905 #endif
00906   if (skipCheck) return; 
00907 
00908   CkThresholdTimer time("FEM Split> Performing consistency check",1.0);
00909 
00910   int t,c;
00911   FEM_Symmetries_t sym=noSymmetries;
00912   
00913   for (c=0;c<nChunks;c++) {
00914     for (t=0;t<mesh->elem.size();t++)
00915       if (mesh->elem.has(t)) {
00916     const dynChunk::dynList &srcIdx=dyn[c].elem[t];
00917     int nEl=srcIdx.size();
00918     for (int lNo=0;lNo<nEl;lNo++) {
00919       int gNo=srcIdx[lNo];
00920       range(gNo,0,mesh->elem[t].size(),"global element number");
00921       equal(gElem[t][gNo].localOnChunk(c,sym),lNo,"gElem[t] local number");
00922     }
00923       } 
00924     const dynChunk::dynList &srcIdx=dyn[c].node;
00925     int nNo=srcIdx.size();
00926     for (int lNo=0;lNo<nNo;lNo++) {
00927       int gNo=srcIdx[lNo];
00928       range(gNo,0,mesh->node.size(),"global node number");
00929       equal(gNode[gNo].localOnChunk(c,sym),lNo,"gNode[] local number");
00930     }
00931   }
00932     
00933   
00934   for (int gNo=0;gNo<mesh->node.size();gNo++) {
00935     for (chunkList *l=&gNode[gNo];l!=NULL;l=l->next) {
00936       if (l->chunk<0) 
00937     FEM_Abort("partitioning","Global node %d (0-based) is not connected to any elements!",gNo);
00938       range(l->chunk,0,nChunks,"gNode chunk");
00939       if (!FEM_Is_ghost_index(l->localNo))
00940     equal(dyn[l->chunk].node[l->localNo],gNo,"chunk local node");
00941     }
00942   }
00943     
00944   for (t=0;t<mesh->elem.size();t++) 
00945     if (mesh->elem.has(t)) {
00946       for (int gNo=0;gNo<mesh->elem[t].size();gNo++) {
00947     for (chunkList *l=&gElem[t][gNo];l!=NULL;l=l->next) {
00948       range(l->chunk,0,nChunks,"gElem chunk");
00949       if (!FEM_Is_ghost_index(l->localNo))
00950         equal(dyn[l->chunk].elem[t][l->localNo],gNo,"chunk local element");
00951     }
00952       }
00953     }
00954 
00955   
00956 }
00957 
00958 
00959 
00960 
00961 
00962 
00963 
00964 
00965 
00966 
00967 
00968 
00969 
00971 class FEM_Entity_numberer {
00972   CkVec<unsigned char> occupied; 
00973   int occupiedBefore; 
00974     
00975   
00976   int nextUnoccupied(void) {
00977     while (occupiedBefore<occupied.size()) {
00978       if (occupied[occupiedBefore]==0) 
00979     return occupiedBefore;
00980       else occupiedBefore++;
00981     }
00982     
00983     occupied.push_back(1);
00984     return occupiedBefore;
00985   }
00986     
00987 public:
00988   FEM_Entity_numberer() { occupiedBefore=0; }
00989     
00991   void mark(FEM_Entity &src) {
00992     int l,len=src.size();
00993     for (l=0;l<len;l++) {
00994       int g=src.getGlobalno(l);
00995       if (g!=-1) {
00996     while (occupied.size()<=g) { 
00997       occupied.push_back(0);
00998     }
00999     
01000     
01001     occupied[g]=1;
01002       }
01003     }
01004   }
01005     
01007   void add(FEM_Entity &l_src,FEM_Entity &g_dest) {
01008     int l,len=l_src.size();
01009     for (l=0;l<len;l++) add(l_src,l,g_dest);
01010   }
01011     
01013   int add(FEM_Entity &l_src,int l,FEM_Entity &g_dest) {
01014     int g=l_src.getGlobalno(l);
01015     if (g==-1) { 
01016       g=nextUnoccupied();
01017       occupied[g]=1;
01018       
01019       l_src.setGlobalno(l,g);
01020     }
01021     if (g_dest.size()<=g) g_dest.setLength(g+1);
01022     g_dest.copyEntity(g,l_src,l);
01023     g_dest.setGlobalno(g,g);
01024     return g;
01025   }
01026 };
01027 
01028 
01029 static void renumberConn(const FEM_Elem &src_e,int l,FEM_Elem &dest_e,int g,
01030              const FEM_Mesh &mesh)
01031 {
01032   const int *srcConn=src_e.connFor(l);
01033   int *dstConn=dest_e.setConn().getRow(g);
01034   for (int n=0;n<src_e.getNodesPer();n++)
01035     dstConn[n]=mesh.node.getGlobalno(srcConn[n]);
01036 }
01037 
01038 FEM_Mesh *FEM_Mesh_assemble(int nChunks,FEM_Mesh **chunks)
01039 {
01040   int t,c;
01041   FEM_Mesh *m=new FEM_Mesh;
01042   for(c=0; c<nChunks;c++) 
01043     m->copyShape(*chunks[c]);
01044     
01045   m->udata=chunks[0]->udata;
01046     
01047   
01048   FEM_Entity_numberer nodeNum;
01049   for(c=0; c<nChunks;c++) nodeNum.mark(chunks[c]->node);
01050   for(c=0; c<nChunks;c++) nodeNum.add(chunks[c]->node,m->node);
01051     
01052   
01053   int nElemTypes=m->elem.size();
01054   for (t=0;t<nElemTypes;t++) {
01055     FEM_Entity_numberer elemNum;
01056     for(c=0; c<nChunks;c++) 
01057       if (chunks[c]->elem.has(t))
01058     elemNum.mark(chunks[c]->elem[t]);
01059         
01060     for(c=0; c<nChunks;c++) 
01061       if (chunks[c]->elem.has(t)) {
01062     FEM_Elem &src_e=chunks[c]->elem[t];
01063     if (!m->elem.has(t)) m->elem.set(t).copyShape(src_e);
01064     FEM_Elem &dest_e=m->elem[t];
01065     for (int l=0;l<src_e.size();l++) {
01066       int g=elemNum.add(src_e,l,dest_e);
01067       renumberConn(src_e,l,dest_e,g,*chunks[c]);
01068     }
01069       }
01070   }
01071 
01072   
01073   int nSparseTypes=m->sparse.size();
01074   for (t=0;t<nSparseTypes;t++) {
01075     FEM_Entity_numberer sparseNum;
01076     for(c=0; c<nChunks;c++) 
01077       if (chunks[c]->sparse.has(t))
01078     sparseNum.mark(chunks[c]->sparse[t]);
01079         
01080     for(c=0; c<nChunks;c++) 
01081       if (chunks[c]->sparse.has(t)) {
01082     FEM_Sparse &src_e=chunks[c]->sparse[t];
01083     if (!m->sparse.has(t)) m->sparse.set(t).copyShape(src_e);
01084     FEM_Sparse &dest_e=m->sparse[t];
01085     for (int l=0;l<src_e.size();l++) {
01086       int g=sparseNum.add(src_e,l,dest_e);
01087       renumberConn(src_e,l,dest_e,g,*chunks[c]);
01088       
01089     }
01090       }
01091   }
01092     
01093   m->becomeGetting(); 
01094   return m;
01095 }