00001 #ifdef FEM_PARALLEL_PART
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 #include <assert.h>
00013 #include <parmetis.h>
00014 #include "fem_impl.h"
00015 #include "fem.h"
00016 #include "fem.decl.h"
00017 #include "msa/msa.h"
00018 #include "cklists.h"
00019 #include "pup.h"
00020 #include "parallel_part.h"
00021 
00022 
00023 int FEM_Mesh_Parallel_broadcast(int fem_mesh,int masterRank,FEM_Comm_t comm_context){
00024   int myRank;
00025   MPI_Comm_rank((MPI_Comm)comm_context,&myRank);
00026   printf("[%d] FEM_Mesh_Parallel_broadcast called for mesh %d\n",myRank,fem_mesh);
00027   int new_mesh;
00028   if(myRank == masterRank){
00029     
00030     
00031     printf("[%d] Memory usage on vp 0 at the begining of partition %d \n",CkMyPe(),CmiMemoryUsage());
00032     new_mesh=FEM_master_parallel_part(fem_mesh,masterRank,comm_context);
00033         
00034   }else{
00035     new_mesh=FEM_slave_parallel_part(fem_mesh,masterRank,comm_context);
00036   }
00037   
00038   MPI_Barrier((MPI_Comm)comm_context);
00039   printf("[%d] Partitioned mesh number %d \n",myRank,new_mesh);
00040   return new_mesh;
00041 }
00042 
00043 int FEM_master_parallel_part(int fem_mesh,int masterRank,FEM_Comm_t comm_context){
00044   const char *caller="FEM_Create_connmsa"; 
00045   FEMAPI(caller);
00046   FEMchunk *c=FEMchunk::get(caller);
00047   FEM_Mesh *m=c->lookup(fem_mesh,caller);
00048   m->setAbsoluteGlobalno();
00049   int nelem = m->nElems();
00050   int numChunks;
00051   MPI_Comm_size((MPI_Comm)comm_context,&numChunks);
00052   printf("master -> number of elements %d \n",nelem);
00053   DEBUG(m->print(0));
00054 
00055 
00056   
00057 
00058 
00059   MSA1DINT eptr(nelem,numChunks);
00060   MSA1DINT eind(nelem*10,numChunks);
00061   
00062 
00063 
00064 
00065   struct conndata data;
00066   data.nelem = nelem;
00067   data.nnode = m->node.size();
00068   data.arr1 = eptr;
00069   data.arr2 = eind;
00070   MPI_Bcast_pup(data,masterRank,(MPI_Comm)comm_context);
00071 
00072   eptr.enroll(numChunks);
00073   eind.enroll(numChunks);
00074   int indcount=0,ptrcount=0;
00075   for(int t=0;t<m->elem.size();t++){
00076     if(m->elem.has(t)){
00077       FEM_Elem &k=m->elem[t];
00078       for(int e=0;e<k.size();e++){
00079     eptr.set(ptrcount)=indcount;
00080     ptrcount++;
00081     for(int n=0;n<k.getNodesPer();n++){
00082       eind.set(indcount)=k.getConn(e,n);
00083       indcount++;
00084     }
00085       }
00086     }
00087   }
00088   eptr.set(ptrcount) = indcount;
00089   printf("master -> ptrcount %d indcount %d \n",ptrcount,indcount);
00090   
00091 
00092 
00093 
00094 
00095 
00096 
00097   FEM_Mesh *mesh_array=FEM_break_mesh(m,ptrcount,numChunks);
00098   
00099 
00100 
00101   sendBrokenMeshes(mesh_array,comm_context);
00102   delete [] mesh_array;
00103   FEM_Mesh mypiece;
00104   MPI_Recv_pup(mypiece,masterRank,MESH_CHUNK_TAG,(MPI_Comm)comm_context);
00105     
00106   
00107 
00108 
00109   struct partconndata *partdata = FEM_call_parmetis(data,comm_context);
00110 
00111   printf("done with parmetis \n");
00112     
00113   
00114 
00115 
00116 
00117   int totalNodes = m->node.size();
00118   MSA1DINTLIST nodepart(totalNodes,numChunks);
00119   MPI_Bcast_pup(nodepart,masterRank,(MPI_Comm)comm_context);
00120   nodepart.enroll(numChunks);
00121     
00122   FEM_write_nodepart(nodepart,partdata);
00123     
00124   
00125 
00126 
00127   MSA1DNODELIST part2node(numChunks,numChunks);
00128   MPI_Bcast_pup(part2node,masterRank,(MPI_Comm)comm_context);
00129   part2node.enroll(numChunks);
00130 
00131   FEM_write_part2node(nodepart,part2node,partdata,(MPI_Comm)comm_context);
00132 
00133   
00134 
00135 
00136   MSA1DINTLIST part2elem(numChunks,numChunks);
00137   MPI_Bcast_pup(part2elem,masterRank,(MPI_Comm)comm_context);
00138   part2elem.enroll(numChunks);
00139     
00140   FEM_write_part2elem(part2elem,partdata,(MPI_Comm)comm_context);
00141     
00142   
00143 
00144 
00145   NodeList lnodes = part2node.get(masterRank);
00146   IntList lelems = part2elem.get(masterRank);
00147     
00148 
00149   
00150 
00151 
00152   MSA1DFEMMESH part2mesh(numChunks,numChunks);
00153   MPI_Bcast_pup(part2mesh,masterRank,(MPI_Comm)comm_context);
00154   part2mesh.enroll(numChunks);
00155   FEM_write_part2mesh(part2mesh,partdata, &data,nodepart,numChunks,masterRank,&mypiece);
00156   
00157 
00158 
00159   MeshElem me = part2mesh.get(masterRank);
00160   printf("[%d] Number of elements in my partitioned mesh %d number of nodes %d \n",masterRank,me.m->nElems(),me.m->node.size());
00161     
00162   addIDXLists(me.m,lnodes,masterRank);
00163     
00164   
00165 
00166 
00167   DEBUG(printf("[%d] Length of udata vector in master %d \n",masterRank,m->udata.size()));
00168   MPI_Bcast_pup(m->udata,masterRank,(MPI_Comm)comm_context);
00169   me.m->udata = m->udata;
00170     
00171     
00172   delete partdata;
00173   
00174 
00175 
00176   struct ghostdata *gdata = gatherGhosts();
00177   printf("[%d] number of ghost layers %d \n",masterRank,gdata->numLayers);
00178   MPI_Bcast_pup(*gdata,masterRank,(MPI_Comm)comm_context);
00179 
00180   
00181 
00182 
00183   makeGhosts(me.m,(MPI_Comm)comm_context,masterRank,gdata->numLayers,gdata->layers);
00184   delete gdata;
00185     
00186   me.m->becomeGetting();
00187   FEMchunk *chunk = FEMchunk::get("FEM_Mesh_Parallel_broadcast");
00188   int tempMeshNo = chunk->meshes.put(me.m);
00189   int new_mesh = FEM_Mesh_copy(tempMeshNo);
00190     
00191   FEM_Mesh *nmesh = c->lookup(new_mesh,"master_parallel_broadcast");
00192   DEBUG(printf("[%d] Length of udata vector in master new_mesh %d \n",masterRank,nmesh->udata.size()));
00193         
00194   return new_mesh;
00195 };
00196 
00197 int FEM_slave_parallel_part(int fem_mesh,int masterRank,FEM_Comm_t comm_context){
00198   int myRank;
00199   MPI_Comm_rank((MPI_Comm)comm_context,&myRank);
00200   int numChunks;
00201   MPI_Comm_size((MPI_Comm)comm_context,&numChunks);
00202         
00203   
00204 
00205   struct conndata data;
00206   MPI_Bcast_pup(data,masterRank,(MPI_Comm)comm_context);        
00207   data.arr1.enroll(numChunks);
00208   data.arr2.enroll(numChunks);
00209   DEBUG(printf("Recv -> %d \n",data.nelem));
00210   
00211 
00212 
00213 
00214 
00215     
00216   FEM_Mesh mypiece;
00217   MPI_Recv_pup(mypiece,masterRank,MESH_CHUNK_TAG,(MPI_Comm)comm_context);
00218     
00219   
00220 
00221 
00222   struct partconndata *partdata = FEM_call_parmetis(data,comm_context);
00223     
00224   
00225 
00226 
00227   MSA1DINTLIST nodepart;
00228   MPI_Bcast_pup(nodepart,masterRank,(MPI_Comm)comm_context);
00229   nodepart.enroll(numChunks);
00230     
00231   FEM_write_nodepart(nodepart,partdata);
00232     
00233   
00234 
00235 
00236 
00237   MSA1DNODELIST part2node;
00238   MPI_Bcast_pup(part2node,masterRank,(MPI_Comm)comm_context);
00239   part2node.enroll(numChunks);
00240         
00241   FEM_write_part2node(nodepart,part2node,partdata,(MPI_Comm)comm_context);
00242 
00243   
00244 
00245 
00246   MSA1DINTLIST part2elem;
00247   MPI_Bcast_pup(part2elem,masterRank,(MPI_Comm)comm_context);
00248   part2elem.enroll(numChunks);
00249     
00250   FEM_write_part2elem(part2elem,partdata,(MPI_Comm)comm_context);
00251   
00252 
00253 
00254   NodeList lnodes = part2node.get(myRank);
00255   IntList lelems = part2elem.get(myRank);
00256 
00257   
00258 
00259 
00260   MSA1DFEMMESH part2mesh;
00261   MPI_Bcast_pup(part2mesh,masterRank,(MPI_Comm)comm_context);
00262   part2mesh.enroll(numChunks);
00263   FEM_write_part2mesh(part2mesh,partdata,&data,nodepart,numChunks,myRank,&mypiece);
00264     
00265   
00266 
00267 
00268   MeshElem me = part2mesh.get(myRank);
00269   printf("[%d] Number of elements in my partitioned mesh %d number of nodes %d \n",myRank,me.m->nElems(),me.m->node.size());
00270     
00271   addIDXLists(me.m,lnodes,myRank);
00272     
00273   
00274 
00275 
00276   MPI_Bcast_pup(me.m->udata,masterRank,(MPI_Comm)comm_context);
00277   DEBUG(printf("[%d] Length of udata vector %d \n",myRank,me.m->udata.size()));
00278     
00279   delete partdata;
00280     
00281   struct ghostdata *gdata = new ghostdata;
00282   MPI_Bcast_pup(*gdata,masterRank,(MPI_Comm)comm_context);
00283   printf("[%d] number of ghost layers %d \n",myRank,gdata->numLayers);
00284     
00285   
00286 
00287 
00288   makeGhosts(me.m,(MPI_Comm )comm_context,masterRank,gdata->numLayers,gdata->layers);
00289     
00290   me.m->becomeGetting();
00291   FEMchunk *chunk = FEMchunk::get("FEM_Mesh_Parallel_broadcast");
00292   int tempMeshNo = chunk->meshes.put(me.m);
00293   int new_mesh = FEM_Mesh_copy(tempMeshNo);
00294     
00295   delete gdata;
00296   return new_mesh;
00297 }
00298 
00299 
00300 
00301 
00302 
00303 
00304 struct partconndata * FEM_call_parmetis(struct conndata &data,FEM_Comm_t comm_context){
00305   int myRank,numChunks;
00306   MPI_Comm_size((MPI_Comm)comm_context,&numChunks);
00307   MPI_Comm_rank((MPI_Comm)comm_context,&myRank);
00308     
00309   int nelem = data.nelem;
00310   
00311 
00312 
00313 
00314 
00315 
00316 
00317   int *elmdist = new int[numChunks+1];
00318   DEBUG(printf("[%d] elmdist \n",myRank));
00319   for(int i=0;i<=numChunks;i++){
00320     elmdist[i] = (i*nelem)/numChunks;
00321     DEBUG(printf(" %d ",elmdist[i]));
00322   }
00323   DEBUG(printf("\n"));
00324   int startindex = elmdist[myRank];
00325   int endindex = elmdist[myRank+1]; 
00326   data.arr1.sync();
00327   data.arr2.sync();
00328   int numindices = endindex - startindex;
00329   int *eptr = new int[numindices+1];
00330   
00331 
00332 
00333 
00334   int startConn = data.arr1.get(startindex);
00335   int endConn = data.arr1.get(endindex);
00336   int numConn = endConn - startConn;
00337   int *eind = new int[numConn];
00338   DEBUG(printf("%d startindex %d endindex %d startConn %d endConn %d \n",myRank,startindex,endindex,startConn,endConn));
00339   for(int i=startindex;i<endindex;i++){
00340     int conn1 = data.arr1.get(i);
00341     int conn2 = data.arr1.get(i+1);
00342     eptr[i-startindex] = conn1 - startConn;
00343     for(int j=conn1;j<conn2;j++){
00344       eind[j-startConn] = data.arr2.get(j);
00345     }
00346   }
00347   eptr[numindices] = endConn - startConn;
00348   
00349 
00350 
00351 
00352 
00353 
00354 
00355 
00356 
00357 
00358 
00359 
00360 
00361   data.arr1.sync();
00362   data.arr2.sync();
00363   int wgtflag=0,numflag=0,ncon=1,ncommonnodes=2,options[5],edgecut=0;
00364   double ubvec = 1.05;
00365   double *tpwgts = new double[numChunks];
00366   int *parts = new int[numindices+1];
00367   for(int i=0;i<numChunks;i++){
00368     tpwgts[i]=1/(double)numChunks;
00369   }
00370   options[0]=0;
00371   MPI_Barrier((MPI_Comm)comm_context);
00372   ParMETIS_V3_PartMeshKway (elmdist,eptr,eind,NULL,&wgtflag,&numflag,&ncon,&ncommonnodes,&numChunks,tpwgts,&ubvec,options,&edgecut,parts,(MPI_Comm *)&comm_context);
00373   DEBUG(CkPrintf("%d partition ",myRank);)
00374     for(int i=0;i<numindices;i++){
00375       DEBUG(CkPrintf(" <%d %d> ",i+startindex,parts[i]));
00376     }
00377   DEBUG(CkPrintf("\n"));
00378   delete []elmdist;
00379   delete []tpwgts;
00380   struct partconndata *retval = new struct partconndata;
00381   retval->nelem = numindices;
00382   retval->eind = eind;
00383   retval->eptr = eptr;
00384   retval->part = parts;
00385   retval->startindex = startindex;
00386   return retval;
00387 }
00388 
00389 
00390 
00391 
00392 
00393 void FEM_write_nodepart(MSA1DINTLIST    &nodepart,struct partconndata *data){
00394   nodepart.sync();
00395   for(int i=0;i<data->nelem;i++){
00396     int start=data->eptr[i];
00397     int end = data->eptr[i+1];
00398     for(int j=start;j<end;j++){
00399       nodepart.accumulate(data->eind[j],data->part[i]);
00400       
00401     }
00402   }
00403   nodepart.sync();
00404 }
00405 
00406 
00407 
00408 
00409 
00410 void FEM_write_part2node(MSA1DINTLIST   &nodepart,MSA1DNODELIST &part2node,struct partconndata *data,MPI_Comm comm_context){
00411   int nodes = nodepart.length();
00412   int myRank,numChunks;
00413   
00414 
00415 
00416 
00417   MPI_Comm_rank(comm_context,&myRank);
00418   MPI_Comm_size(comm_context,&numChunks);
00419   int start = (nodes*myRank)/numChunks;
00420   int end = (nodes*(myRank+1))/numChunks;
00421   part2node.sync();
00422   for(int i=start;i<end;i++){
00423     IntList t = nodepart.get(i);
00424     int num=0;
00425     if(t.vec->size()>1){
00426       num = t.vec->size();
00427     }
00428     NodeElem n(i,num);
00429     if(num != 0){
00430       for(int k=0;k<t.vec->size();k++){
00431     n.shared[k] =(*t.vec)[k];
00432       }
00433     }   
00434 
00435     for(int j=0;j<t.vec->size();j++){
00436       ElemList <NodeElem> en(n);
00437       part2node.accumulate((*t.vec)[j],en);
00438     }
00439   }
00440   part2node.sync();
00441   DEBUG(printf("done write_part2node\n"));
00442 }
00443 
00444 
00445 
00446 
00447 void FEM_write_part2elem(MSA1DINTLIST &part2elem,struct partconndata *data,MPI_Comm comm_context){
00448   part2elem.sync();
00449   for(int i=0;i<data->nelem;i++){
00450     part2elem.accumulate(data->part[i],data->startindex+i);
00451   }
00452   part2elem.sync();
00453 }
00454 
00455 
00456 
00457 
00458 
00459 FEM_Mesh * FEM_break_mesh(FEM_Mesh *m,int numElements,int numChunks){
00460   FEM_Mesh *mesh_array = new FEM_Mesh[numChunks];
00461   int *elmdist = new int[numChunks+1];
00462   int *nodedist = new int[numChunks+1];
00463   int numNodes = m->node.size();
00464     
00465   for(int i=0;i<=numChunks;i++){
00466     elmdist[i] = (i*numElements)/numChunks;
00467     nodedist[i] = (i*numNodes)/numChunks;
00468   }
00469 
00470   int elcount=0;
00471   int mcount=0;
00472   mesh_array[mcount].copyShape(*m);
00473   for(int t=0;t<m->elem.size();t++){
00474     if(m->elem.has(t)){
00475       FEM_Elem &k=m->elem[t];
00476       for(int e=0;e<k.size();e++){
00477     mesh_array[mcount].elem[t].push_back(k,e);
00478     elcount++;
00479     if(elcount == elmdist[mcount+1]){
00480       mcount++;
00481       if(mcount != numChunks){
00482         mesh_array[mcount].copyShape(*m);
00483       }
00484     }
00485 
00486       }
00487     }
00488   }
00489   mcount=0;
00490   for(int i=0;i<m->node.size();i++){
00491     if(i == nodedist[mcount+1]){
00492       mcount++;
00493     }
00494     mesh_array[mcount].node.push_back(m->node,i);
00495   }
00496   delete [] elmdist;
00497   delete [] nodedist;
00498   return mesh_array;
00499 }
00500 
00501 
00502 
00503 void sendBrokenMeshes(FEM_Mesh *mesh_array,FEM_Comm_t comm_context){
00504   int numChunks;
00505   MPI_Comm_size((MPI_Comm)comm_context,&numChunks);
00506   for(int i=0;i<numChunks;i++){
00507     MPI_Send_pup(mesh_array[i],i,MESH_CHUNK_TAG,(MPI_Comm)comm_context);
00508   }
00509 }
00510 void    FEM_write_part2mesh(MSA1DFEMMESH &part2mesh,struct partconndata *partdata,struct conndata *data,MSA1DINTLIST &nodepart,int numChunks,int myChunk,FEM_Mesh *m){
00511   part2mesh.sync();
00512   int count=0;
00515   for(int t=0;t<m->elem.size();t++){
00516     if(m->elem.has(t)){
00517       const FEM_Elem &k=(m)->elem[t];
00518       for(int e=0;e<k.size();e++){
00519     int chunkID = partdata->part[count];
00520     MeshElem &myme=part2mesh.accumulate(chunkID);
00521     (myme.m->elem[t]).copyShape(m->elem[t]);
00522     (myme.m->elem[t]).push_back(m->elem[t],e);
00523     count++;
00524       }
00525     }
00526   }
00527   nodepart.sync();
00529   int startnode=(myChunk * data->nnode)/numChunks;
00530   for(int i=0;i<m->node.size();i++){
00531     IntList chunks = nodepart.get(i+startnode);
00532     for(int j=0;j<chunks.vec->size();j++){
00533       MeshElem &myme = part2mesh.accumulate((*(chunks.vec))[j]);
00534       (myme.m->node).copyShape(m->node);
00535       (myme.m->node).push_back(m->node,i);
00536     }
00537   }
00538   part2mesh.sync();
00539 }
00540 
00541 
00542 
00543 void sortNodeList(NodeList &lnodes){
00544   CkVec<NodeElem> *vec = lnodes.vec;
00545   for(int i=0;i<vec->size();i++){
00546     for(int j=i+1;j<vec->size();j++){
00547       if((*vec)[i].global > (*vec)[j].global){
00548     NodeElem t = (*vec)[i];
00549     (*vec)[i] = (*vec)[j];
00550     (*vec)[j] = t;
00551       }
00552     }
00553   }
00554 }
00555 
00556 
00557 void addIDXLists(FEM_Mesh *m,NodeList &lnodes,int myChunk){
00558   
00559 
00560 
00561   sortNodeList(lnodes);
00562     
00563   CkVec<NodeElem> *vec = lnodes.vec;
00564   
00565 
00566 
00567   CkHashtableT<CkHashtableAdaptorT<int>,int> global2local;
00568   for(int i=0;i<m->node.size();i++){
00569     int nodeno = m->node.getGlobalno(i);
00570     global2local.put(nodeno)=i;
00571   }
00572   
00573 
00574 
00575 
00576 
00577 
00578 
00580   for(int i=0;i<vec->size();i++){
00582     int global = (*vec)[i].global;
00584     int local = global2local.get(global);
00585     
00586     m->node.setPrimary(local,true);
00587     
00588     if(((*vec)[i]).numShared > 0){
00590       int *shared = (*vec)[i].shared;
00591             
00592       for(int j=0;j<((*vec)[i]).numShared;j++){
00593     if(shared[j] != myChunk){
00594       
00595       m->node.shared.addList(shared[j]).push_back(local);
00596     }
00597     if(shared[j] < myChunk){
00598       m->node.setPrimary(local,false);
00599     }
00600       }
00601     }
00602   }
00603   DEBUG(m->node.shared.print());
00604 
00605   
00606 
00607 
00608 
00609   for(int i=0;i<m->elem.size();i++){
00610     if(m->elem.has(i)){
00611       FEM_Elem &el=m->elem[i];
00612       for(int j=0;j<el.size();j++){
00613     int *conn = el.connFor(j);
00614     for(int k=0;k<el.getNodesPer();k++){
00615       int gnode = conn[k];
00616       int lnode = global2local.get(gnode);
00617       conn[k] = lnode;
00618     }
00619       }
00620     }
00621   }
00622 }
00623 
00624 
00625 
00626 
00627 
00628 
00629 struct ghostdata *gatherGhosts(){
00630   struct ghostdata *res = new struct ghostdata;
00631   FEM_Partition &part = FEM_curPartition();
00632   res->numLayers = part.getRegions();
00633   res->layers = new FEM_Ghost_Layer *[res->numLayers];
00634   int count=0;
00635     
00636   for(int i=0;i<res->numLayers;i++){
00637     const FEM_Ghost_Region ®ion = part.getRegion(i);
00638     if(region.layer != NULL){
00639       res->layers[count]=region.layer;
00640       count++;
00641     }
00642   } 
00643   res->numLayers = count;
00644   return res;
00645 }
00646 
00647 
00648 
00649 
00650 
00651 
00652 
00653 
00654 
00655 
00656 
00657 void makeGhosts(FEM_Mesh *m,MPI_Comm comm,int masterRank,int numLayers,FEM_Ghost_Layer **layers){
00658   int myChunk;
00659   int numChunks;
00660   MPI_Comm_rank((MPI_Comm)comm,&myChunk);
00661   MPI_Comm_size((MPI_Comm)comm,&numChunks);
00662     
00663   if(numChunks == 1){
00664     return;
00665   }
00666     
00667   
00668 
00669 
00670 
00671   FEM_Comm *shared = &m->node.shared;
00672   int count=0;
00673   CkHashtableT<CkHashtableAdaptorT<int>,char>   countedSharedNode;
00674   for(int i=0;i<shared->size();i++){
00675     const FEM_Comm_List &list = shared->getLocalList(i);
00676     
00677 
00678 
00679 
00680 
00681 
00682 
00683     if(list.getDest() > myChunk){
00684       for(int j=0;j<list.size();j++){
00685     if(countedSharedNode.get(list[j]) == 0){
00686       count++;
00687       countedSharedNode.put(list[j]) = 1;
00688     }
00689       } 
00690     }else{
00691       for(int j=0;j<list.size();j++){
00692     if(countedSharedNode.get(list[j]) == 1){
00693       count--;
00694     }
00695     countedSharedNode.put(list[j]) = 2;
00696       }
00697     }
00698   }
00699   int totalShared; 
00700   MPI_Allreduce(&count, &totalShared,1, MPI_INT,
00701         MPI_SUM, comm);
00702   printf("[%d] Total number of shared nodes %d \n",myChunk,totalShared);
00703   
00704 
00705 
00706   FEM_IndexAttribute *nchunkattr = (FEM_IndexAttribute *)m->node.lookup(FEM_CHUNK,"makeGhosts");
00707   int *nchunk = nchunkattr->get().getData();
00708   for(int i=0;i<nchunkattr->getLength();i++){
00709     nchunk[i] = myChunk;
00710   }
00711   for(int e = 0; e < m->elem.size();e++){
00712     if(m->elem.has(e)){
00713       FEM_IndexAttribute *echunkattr = (FEM_IndexAttribute *)m->elem[e].lookup(FEM_CHUNK,"makeGhosts");
00714       int *echunk = echunkattr->get().getData();
00715       for(int i=0;i<echunkattr->getLength();i++){
00716     echunk[i] = myChunk;
00717       }
00718     }
00719   }
00720     
00721   
00722 
00723 
00724 
00725 
00726     
00727   CkHashtableT<CkHashtableAdaptorT<int>,int> global2local;
00728   for(int i=0;i<m->node.size();i++){
00729     global2local.put(m->node.getGlobalno(i))=i+1;
00730   }
00731 
00732   for(int i=0;i<numLayers;i++){
00733     printf("[%d] Making ghost layer %d \n",myChunk,i);
00734     makeGhost(m,comm,masterRank,totalShared,layers[i],countedSharedNode,global2local); 
00735   }
00736 };
00737 
00738 
00739 
00740 
00741 bool listContains(FEM_Comm_List &list,int entry){
00742   for(int i=0;i<list.size();i++){
00743     if(entry == list[i]){
00744       return true;
00745     }
00746   }
00747   return false;
00748 };
00749 
00750 void makeGhost(FEM_Mesh *m,MPI_Comm comm,int masterRank,int totalShared,FEM_Ghost_Layer *layer, CkHashtableT<CkHashtableAdaptorT<int>,char> &sharedNode,CkHashtableT<CkHashtableAdaptorT<int>,int> &global2local){
00751   int myChunk;
00752   int numChunks;
00753   MPI_Comm_rank((MPI_Comm)comm,&myChunk);
00754   MPI_Comm_size((MPI_Comm)comm,&numChunks);
00755 
00756   
00757 
00758 
00759 
00760   MsaHashtable *distTab;
00761   if(myChunk == masterRank){
00762     distTab = new MsaHashtable(totalShared,numChunks);  
00763   }else{
00764     distTab = new MsaHashtable;
00765   }
00766   printf("[%d] starting ghost generation \n",myChunk);
00767   MPI_Bcast_pup(*distTab,masterRank,comm);
00768   distTab->table.enroll(numChunks);
00769   DEBUG(printf("[%d] distributed table calling sync \n",myChunk));
00770   
00771   distTab->table.sync();
00772     
00773   DEBUG(printf("Chunk %d Mesh: *********************************** \n",myChunk));
00774   DEBUG(m->print(0));
00775   DEBUG(printf("**********************************\n"));
00776     
00777   printf("Chunk %d Ghost layer nodesPerTuple %d numSlots %d \n",myChunk,layer->nodesPerTuple,distTab->numSlots);
00778   
00779 
00780 
00781 
00782 
00783   CkVec<Hashnode::tupledata> tupleVec; 
00784   CkVec<int> indexVec; 
00785   CkVec<int> elementVec; 
00786 
00787   for(int i=0;i<m->elem.size();i++){
00788     if(m->elem.has(i)){
00789       
00790       if(layer->elem[i].add){
00791     
00792     for(int e=0;e<m->elem[i].size();e++){
00793       const int *conn = m->elem[i].connFor(e);
00794       
00795       for(int t=0;t< layer->elem[i].tuplesPerElem;t++){
00796         bool possibleGhost=true;
00797         
00798         int globalNodeTuple[Hashnode::tupledata::MAX_TUPLE]; 
00799                         
00800         
00801         
00802         
00803         
00804         int nodesPerTuple = layer->nodesPerTuple;
00805         for(int n = 0;n<layer->nodesPerTuple;n++){
00806           int nodeindex=(layer->elem[i].elem2tuple)[t*layer->nodesPerTuple+n];
00807           
00808 
00809 
00810 
00811           if(nodeindex == -1){
00812         nodesPerTuple--;
00813         globalNodeTuple[n] =-1;
00814         continue;
00815           }
00816           int node=conn[nodeindex];
00817           globalNodeTuple[n]=m->node.getGlobalno(node);
00818           if(sharedNode.get(node) == 0){
00819         possibleGhost = false;
00820         break;
00821           }
00822         }
00823         
00824         if(possibleGhost){
00825           int index=distTab->addTuple(globalNodeTuple,nodesPerTuple,myChunk,m->nElems(i)+e);
00826           tupleVec.push_back(Hashnode::tupledata(globalNodeTuple));
00827           indexVec.push_back(index);
00828           elementVec.push_back(i);
00829           elementVec.push_back(e);
00830         }
00831       }
00832     }
00833       }
00834     }
00835   }
00836   
00837   
00838   
00839 
00840   int ghostcount=0;
00841   for(int i=0;i<m->elem.size();i++){
00842     if(m->elem.has(i)){
00843       if(layer->elem[i].add){
00844     FEM_Elem *ghostElems = (FEM_Elem *)m->elem[i].getGhost();
00845     for(int e=0;e<ghostElems->size();e++){
00846       ghostcount++;
00847       const int *conn = ghostElems->connFor(e);
00848       for(int t=0;t<layer->elem[i].tuplesPerElem;t++){
00849         int globalNodeTuple[Hashnode::tupledata::MAX_TUPLE];
00850         FEM_Node *ghostNodes = (FEM_Node *)m->node.getGhost();
00851         int nodesPerTuple = layer->nodesPerTuple;
00852         for(int n=0;n<layer->nodesPerTuple;n++){
00853           int nodeindex=(layer->elem[i].elem2tuple)[t*layer->nodesPerTuple+n];
00854           if(nodeindex == -1){
00855         nodesPerTuple--;
00856         globalNodeTuple[n] = -1;
00857         continue;
00858           }
00859           int node=conn[nodeindex];
00860           if(FEM_Is_ghost_index(node)){
00861         globalNodeTuple[n]=ghostNodes->getGlobalno(FEM_From_ghost_index(node));
00862           }else{
00863         globalNodeTuple[n]=m->node.getGlobalno(node);
00864           }
00865         }
00866         
00867         distTab->addTuple(globalNodeTuple,nodesPerTuple,myChunk,ghostcount);
00868       }
00869     }
00870       }
00871     }
00872   }
00873   distTab->table.sync();
00874   
00875   
00876   if(myChunk == masterRank){
00877     DEBUG(distTab->print());
00878   }
00879   distTab->sync();
00880   
00881   MSA1DFEMMESH *ghostmeshes;
00882   if(myChunk == masterRank){
00883     ghostmeshes = new MSA1DFEMMESH(numChunks,numChunks);    
00884   }else{
00885     ghostmeshes = new MSA1DFEMMESH; 
00886   }
00887   MPI_Bcast_pup(*ghostmeshes,masterRank,comm);
00888   ghostmeshes->enroll(numChunks);
00889   ghostmeshes->sync();
00890   
00891 
00892 
00893 
00894 
00895 
00896   char str[100];
00897   for(int i=0;i<tupleVec.size();i++){
00898     const Hashtuple &listTuple = distTab->get(indexVec[i]);
00899     
00900     int elType = elementVec[2*i];
00901     int elNo = elementVec[2*i+1];
00902     for(int j=0;j<listTuple.vec->size();j++){
00903             
00904       
00905       if((*listTuple.vec)[j].equals(tupleVec[i])){
00906     int destChunk=(*listTuple.vec)[j].chunk;
00907     
00908                 
00909     
00910     if(destChunk != myChunk){
00911       
00912       
00913       
00914                     
00915       FEM_Comm &sendGhostSide = m->elem[elType].setGhostSend();
00916       FEM_Comm_List &sendGhostList = sendGhostSide.addList(destChunk);
00917       if(listContains(sendGhostList,elNo)){
00918         
00919         
00920         
00921         
00922         continue;
00923       }
00924 
00925       
00926       sendGhostList.push_back(elNo);
00927 
00928                     
00929       
00930       MeshElem &myme = ghostmeshes->accumulate(destChunk);
00931       myme.m->elem[elType].copyShape(m->elem[elType]);
00932       int index=myme.m->elem[elType].push_back(m->elem[elType],elNo);
00933       int globalelem = m->elem[elType].getGlobalno(elNo);
00934       DEBUG(printf("[%d] For chunk %d ghost element global no %d \n",myChunk,destChunk,globalelem));
00935 
00936                     
00937       
00938       
00939       int *conn = myme.m->elem[elType].connFor(index);
00940       for(int k=0;k<m->elem[elType].getNodesPer();k++){
00941         int lnode = conn[k];
00942         
00943         if(lnode < 0){
00944           continue;
00945         }
00946         
00947         
00948         
00949         if(sharedNode.get(lnode) ==  0){
00950           sharedNode.put(lnode)=3;
00951         }
00952         int globalnode = m->node.getGlobalno(lnode);
00953         conn[k] = globalnode;
00954         assert(conn[k] >= 0);
00955             
00956         
00957         
00958         
00959         if(layer->addNodes && lnode >= 0){
00960                         
00961           
00962           
00963           
00964           
00965           if(!sharedWith(lnode,(*listTuple.vec)[j].chunk,m)){
00966         FEM_Comm &sendNodeGhostSide = m->node.setGhostSend();
00967         FEM_Comm_List &sendNodeGhostList = sendNodeGhostSide.addList((*listTuple.vec)[j].chunk); 
00968         if(!listContains(sendNodeGhostList,lnode)){
00969           myme.m->node.copyShape(m->node);
00970           myme.m->node.push_back(m->node,lnode);
00971           DEBUG(printf("[%d] Ghost node (send) global no %d \n",myChunk,globalnode));
00972           
00973           sendNodeGhostList.push_back(lnode);
00974         }   
00975           } 
00976         }    
00977       }
00978     }
00979       }
00980     }
00981     
00982   }
00983   CmiMemoryCheck();
00984   DEBUG(printf("[%d] finished creating ghost mesh \n",myChunk));
00985   ghostmeshes->sync();
00986   
00987 
00988 
00989 
00990 
00991     
00992   FEM_Mesh *gmesh = ghostmeshes->get(myChunk).m;
00993   DEBUG(printf("[%d] my ghost mesh is at %p \n",myChunk,gmesh));
00994     
00995   FEM_Node *gnodes = (FEM_Node *)m->node.getGhost();
00996   gnodes->copyShape(m->node);
00997   FEM_IndexAttribute *nodeSrcChunkAttr = (FEM_IndexAttribute *)gmesh->node.lookup(FEM_CHUNK,"makeGhosts");
00998   int *nodeSrcChunkNo = nodeSrcChunkAttr->get().getData();
00999     
01000   DEBUG(printf("[%d] gmesh->node.size() = %d \n",myChunk,gmesh->node.size()));
01001   for(int i=0;i<gmesh->node.size();i++){
01002     int gnum = gmesh->node.getGlobalno(i);
01003     int lindex = global2local.get(gnum);
01004         
01005     if(lindex == 0){
01006       int countgnodes = gnodes->push_back(gmesh->node,i);
01007       global2local.put(gnum) = -(countgnodes+1);
01008       lindex = -(countgnodes+1);            
01009     }
01010     DEBUG(CkPrintf("[%d] Ghost node (recv) global node %d lindex %d \n",myChunk,gnum,lindex));
01011     
01012     FEM_Comm &recvNodeGhostSide = m->node.setGhostRecv();
01013     FEM_Comm_List &recvNodeGhostList = recvNodeGhostSide.addList(nodeSrcChunkNo[i]); 
01014     recvNodeGhostList.push_back(-lindex-1);
01015 
01016   }
01017     
01018   
01019 
01020 
01021 
01022 
01023 
01024 
01025   for(int elType = 0;elType < gmesh->elem.size();elType++){
01026     if(gmesh->elem.has(elType)){
01027       FEM_IndexAttribute *elemSrcChunkAttr = (FEM_IndexAttribute *)gmesh->elem[elType].lookup(FEM_CHUNK,"makeGhosts");
01028       int *elemSrcChunkNo = elemSrcChunkAttr->get().getData();
01029 
01030       for(int e=0;e<gmesh->elem[elType].size();e++){
01031     m->elem[elType].getGhost()->copyShape(gmesh->elem[elType]);
01032     int lghostelem = m->elem[elType].getGhost()->push_back(gmesh->elem[elType],e);
01033     int *conn = ((FEM_Elem *)m->elem[elType].getGhost())->connFor(lghostelem);
01034     for(int n=0;n<gmesh->elem[elType].getNodesPer();n++){
01035       int gnode = conn[n];
01036       assert(gnode>=0);
01037       if(gnode >= 0){
01038         int lnode = global2local.get(gnode);
01039         
01040         if(lnode == 0){
01041           if(layer->addNodes){
01042         CkPrintf("[%d]Unknown global number %d \n",myChunk,gnode);
01043         CkAbort("Unknown global number for node in ghost element connectivity");
01044           } 
01045           conn[n] = -1;
01046         }
01047         
01048         if(lnode > 0){
01049           conn[n] = lnode -1;
01050         }
01051         
01052         if(lnode < 0){
01053           conn[n] = FEM_To_ghost_index((-lnode-1));
01054         }
01055       }else{
01056         conn[n] = -1;
01057       }
01058     }
01059     FEM_Comm &recvGhostSide = m->elem[elType].setGhostRecv();
01060     FEM_Comm_List &recvGhostList = recvGhostSide.addList(elemSrcChunkNo[e]); 
01061     recvGhostList.push_back(lghostelem);
01062 
01063       }
01064     }
01065   }
01066   DEBUG(printf("[%d] Send ghost nodes \n",myChunk));
01067   DEBUG(m->node.getGhostSend().print());
01068   DEBUG(printf("[%d] Recv ghost nodes \n",myChunk));
01069   DEBUG(m->node.getGhostRecv().print());
01070     
01071   delete distTab;   
01072   delete ghostmeshes;
01073   MPI_Barrier(comm);
01074 }
01075 
01076 
01077 
01078 bool sharedWith(int lnode,int chunk,FEM_Mesh *m){
01079   int lindex = m->node.shared.findLocalList(chunk);
01080   if(lindex != -1){
01081     const IDXL_List & llist = m->node.shared.getLocalList(lindex);
01082     for(int i=0;i<llist.size();i++){
01083       if(llist[i] == lnode){
01084     return true;
01085       }
01086     }
01087     return false;
01088   }else{
01089     return false;
01090   }
01091 }
01092 #include "fem.def.h"
01093 #endif