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 }