00001
00002
00003
00004
00005
00006
00007
00008 #include "fem_impl.h"
00009
00010 int femVersion = 1;
00011
00012
00013 #define FEM_TCHARM_SEMAID 0x00FE300
00014
00015 static CmiNodeLock femLock = 0;
00016
00017 void FEM_Abort(const char *msg) {
00018 CkAbort(msg);
00019 }
00020 void FEM_Abort(const char *caller,const char *sprintf_msg,
00021 int int0,int int1, int int2)
00022 {
00023 char userSprintf[1024];
00024 char msg[1024];
00025 sprintf(userSprintf,sprintf_msg,int0,int1,int2);
00026 sprintf(msg,"FEM Routine %s fatal error:\n %s",
00027 caller,userSprintf);
00028 FEM_Abort(msg);
00029 }
00030
00031
00032
00033
00034 enum {FEM_globalID=33};
00035
00036 CLINKAGE void pupFEM_Chunk(pup_er cp) {
00037 PUP::er &p=*(PUP::er *)cp;
00038 FEMchunk *c=(FEMchunk *)TCHARM_Get_global(FEM_globalID);
00039 if (c==NULL) {
00040 c=new FEMchunk((CkMigrateMessage *)0);
00041 TCHARM_Set_global(FEM_globalID,c,pupFEM_Chunk);
00042 }
00043 c->pup(p);
00044 if (p.isDeleting())
00045 delete c;
00046 }
00047 FEMchunk *FEMchunk::get(const char *caller) {
00048 FEMchunk *c=(FEMchunk *)TCHARM_Get_global(FEM_globalID);
00049 if(!c) FEM_Abort(caller,"FEM is not initialized");
00050 return c;
00051 }
00052
00053 CLINKAGE void FEM_Init(FEM_Comm_t defaultComm)
00054 {
00055 IDXL_Init(defaultComm);
00056 if (!femLock) femLock = CmiCreateLock();
00057 if (!TCHARM_Get_global(FEM_globalID)) {
00058 FEMchunk *c=new FEMchunk(defaultComm);
00059 TCHARM_Set_global(FEM_globalID,c,pupFEM_Chunk);
00060 }
00061 }
00062 FORTRAN_AS_C(FEM_INIT,FEM_Init,fem_init, (int *comm), (*comm))
00063
00064 #ifndef FEM_PARALLEL_PART
00065
00066 void _registerfem(void) {}
00067 #endif
00068
00069
00070
00071
00072 void FEM_Mesh_list::bad(int l,int bad_code,const char *caller) const {
00073 if (bad_code==0)
00074 FEM_Abort(caller,"Invalid FEM Mesh ID %d (should be like %d)",
00075 l,FEM_MESH_FIRST);
00076 else
00077 FEM_Abort(caller,"Re-used a deleted FEM Mesh ID %d",l);
00078 }
00079
00080 CLINKAGE int
00081 FEM_Mesh_allocate(void)
00082 {
00083 const char *caller="FEM_Mesh_allocate";FEMAPI(caller);
00084 FEMchunk *c=FEMchunk::get(caller);
00085 FEM_Mesh *m=new FEM_Mesh;
00086 m->becomeSetting();
00087 return c->meshes.put(m);
00088 }
00089 FORTRAN_AS_C_RETURN(int,
00090 FEM_MESH_ALLOCATE,FEM_Mesh_allocate,fem_mesh_allocate, (void),())
00091
00092
00093 template <class T>
00094 inline T *clonePointerViaPup(T *old) {
00095 int len=PUP::size(*old);
00096 char *buf=new char[len];
00097 PUP::toMemBuf(*old,buf,len);
00098 T *nu=new T;
00099 PUP::fromMemBuf(*nu,buf,len);
00100 return nu;
00101 }
00102
00103 CLINKAGE int
00104 FEM_Mesh_copy(int fem_mesh) {
00105 const char *caller="FEM_Mesh_copy";FEMAPI(caller);
00106 FEMchunk *c=FEMchunk::get(caller);
00107 return c->meshes.put(clonePointerViaPup(c->meshes.lookup(fem_mesh,caller)));
00108 }
00109 FORTRAN_AS_C_RETURN(int,
00110 FEM_MESH_COPY,FEM_Mesh_copy,fem_mesh_copy, (int *m),(*m))
00111
00112
00113 CLINKAGE void
00114 FEM_Mesh_deallocate(int fem_mesh)
00115 {
00116 if (fem_mesh!=-1) {
00117 const char *caller="FEM_Mesh_deallocate";FEMAPI(caller);
00118 FEMchunk *c=FEMchunk::get(caller);
00119 c->meshes.destroy(fem_mesh,caller);
00120 }
00121 }
00122 FORTRAN_AS_C(FEM_MESH_DEALLOCATE,FEM_Mesh_deallocate,fem_mesh_deallocate, (int *m),(*m))
00123
00124
00125 CLINKAGE int
00126 FEM_Mesh_read(const char *prefix,int partNo,int nParts)
00127 {
00128 const char *caller="FEM_Mesh_read";FEMAPI(caller);
00129 FEMchunk *c=FEMchunk::get(caller);
00130 return c->meshes.put(FEM_readMesh(prefix,partNo,nParts));
00131 }
00132 FLINKAGE int
00133 FTN_NAME(FEM_MESH_READ,fem_mesh_read)(const char *n,int *partNo,int *nParts,int len) {
00134 char *s=new char[len+1]; strncpy(s,n,len); s[len]=(char)0;
00135 int ret=FEM_Mesh_read(s,*partNo,*nParts);
00136 delete[] s;
00137 return ret;
00138 }
00139
00140 CLINKAGE void
00141 FEM_Mesh_write(int fem_mesh,const char *prefix,int partNo,int nParts)
00142 {
00143 const char *caller="FEM_Mesh_write";FEMAPI(caller);
00144 FEMchunk *c=FEMchunk::get(caller);
00145 FEM_writeMesh(c->meshes.lookup(fem_mesh,caller),prefix,partNo,nParts);
00146 }
00147 FLINKAGE void
00148 FTN_NAME(FEM_MESH_WRITE,fem_mesh_write)(int *m,const char *n,int *partNo,int *nParts,int len) {
00149 char *s=new char[len+1]; strncpy(s,n,len); s[len]=(char)0;
00150 FEM_Mesh_write(*m,s,*partNo,*nParts);
00151 delete[] s;
00152 }
00153
00154
00155 CLINKAGE int
00156 FEM_Mesh_assemble(int nParts,const int *srcMeshes) {
00157 const char *caller="FEM_Mesh_assemble";FEMAPI(caller);
00158 FEMchunk *c=FEMchunk::get(caller);
00159 FEM_Mesh **chunks=new FEM_Mesh*[nParts];
00160 for (int p=0;p<nParts;p++) chunks[p]=c->meshes.lookup(srcMeshes[p],caller);
00161 int ret=c->meshes.put(FEM_Mesh_assemble(nParts,chunks));
00162 delete[] chunks;
00163 return ret;
00164 }
00165 FORTRAN_AS_C_RETURN(int,FEM_MESH_ASSEMBLE,FEM_Mesh_assemble,fem_mesh_assemble,
00166 (int *nParts,const int *src),(*nParts,src))
00167
00168 static FEM_Partition *partition=NULL;
00169 FEM_Partition &FEM_curPartition(void) {
00170 if (partition==NULL) partition=new FEM_Partition();
00171 return *partition;
00172 }
00173 static void clearPartition(void) {delete partition; partition=NULL;}
00174
00175 FEM_Partition::FEM_Partition()
00176 {
00177 elem2chunk=NULL;
00178 sym=NULL;
00179 lastLayer=0;
00180 }
00181 FEM_Partition::~FEM_Partition() {
00182 if (elem2chunk) {delete[] elem2chunk;elem2chunk=NULL;}
00183 for (int i=0;i<getRegions();i++) {
00184 delete regions[i].layer;
00185 delete regions[i].stencil;
00186 }
00187 }
00188
00189 void FEM_Partition::setPartition(const int *e, int nElem, int idxBase) {
00190 if (elem2chunk) {delete[] elem2chunk;elem2chunk=NULL;}
00191 elem2chunk=CkCopyArray(e,nElem,idxBase);
00192 }
00193 const int *FEM_Partition::getPartition(FEM_Mesh *src,int nChunks) const {
00194 if (!elem2chunk) {
00195 int *e=new int[src->nElems()];
00196 FEM_Mesh_partition(src,nChunks,e);
00197 ((FEM_Partition *)this)->elem2chunk=e;
00198 }
00199 return elem2chunk;
00200 }
00201
00202 static void FEM_Mesh_partition(FEM_Mesh *src,int _nchunks,FEM_Mesh_Output *out) {
00203 src->setAscendingGlobalno();
00204 FEM_Mesh_split(src,_nchunks,FEM_curPartition(),out);
00205 clearPartition();
00206 }
00207
00208
00209 class FEM_Mesh_Partition_List : public FEM_Mesh_Output {
00210 FEMchunk *c;
00211 int *dest;
00212 public:
00213 FEM_Mesh_Partition_List(FEMchunk *c_, int *dest_)
00214 :c(c_), dest(dest_) {}
00215
00216 void accept(int chunkNo,FEM_Mesh *m) {
00217 dest[chunkNo]=c->meshes.put(m);
00218 }
00219 };
00220
00221 CLINKAGE void
00222 FEM_Mesh_partition(int fem_mesh,int nParts,int *destMeshes) {
00223 const char *caller="FEM_Mesh_partition"; FEMAPI(caller);
00224 FEMchunk *c=FEMchunk::get(caller);
00225 FEM_Mesh *m=c->lookup(fem_mesh,caller);
00226 FEM_Mesh_Partition_List l(c,destMeshes);
00227 if (m->node.size()>0) {
00228 FEM_Mesh_partition(m,nParts,&l);
00229 } else {
00230 for (int i=0;i<nParts;i++)
00231 destMeshes[i]=FEM_Mesh_copy(fem_mesh);
00232 }
00233 }
00234 FORTRAN_AS_C(FEM_MESH_PARTITION,FEM_Mesh_partition,fem_mesh_partition,
00235 (int *mesh,int *nParts,int *dest),(*mesh,*nParts,dest))
00236
00237
00238
00239 CLINKAGE int
00240 FEM_Mesh_recv(int fromRank,int tag,FEM_Comm_t comm_context)
00241 {
00242 const char *caller="FEM_Mesh_recv";FEMAPI(caller);
00243 FEMchunk *c=FEMchunk::get(caller);
00244 marshallNewHeapCopy<FEM_Mesh> m;
00245 MPI_Recv_pup(m,fromRank,tag,(MPI_Comm)comm_context);
00246 FEM_Mesh *msh=m;
00247 msh->becomeGetting();
00248 return c->meshes.put(msh);
00249 }
00250 FORTRAN_AS_C_RETURN(int,FEM_MESH_RECV,FEM_Mesh_recv,fem_mesh_recv,
00251 (int *from,int *tag,int *comm),(*from,*tag,*comm))
00252
00253 CLINKAGE void
00254 FEM_Mesh_send(int fem_mesh,int toRank,int tag,FEM_Comm_t comm_context)
00255 {
00256 const char *caller="FEM_Mesh_send";FEMAPI(caller);
00257 FEMchunk *c=FEMchunk::get(caller);
00258 marshallNewHeapCopy<FEM_Mesh> m(c->meshes.lookup(fem_mesh,caller));
00259 MPI_Send_pup(m,toRank,tag,(MPI_Comm)comm_context);
00260 }
00261 FORTRAN_AS_C(FEM_MESH_SEND,FEM_Mesh_send,fem_mesh_send,
00262 (int *mesh,int *to,int *tag,int *comm),(*mesh,*to,*tag,*comm))
00263
00264
00265 CLINKAGE int
00266 FEM_Mesh_reduce(int fem_mesh,int masterRank,FEM_Comm_t comm_context)
00267 {
00268 int tag=89374;
00269 int myRank; MPI_Comm_rank((MPI_Comm)comm_context,&myRank);
00270 if (myRank!=masterRank)
00271 {
00272 FEM_Mesh_send(fem_mesh,masterRank,tag,comm_context);
00273 return 0;
00274 }
00275 else
00276 {
00277 int p, nParts; MPI_Comm_size((MPI_Comm)comm_context,&nParts);
00278 int *parts=new int[nParts];
00279 for (p=0;p<nParts;p++)
00280 if (p!=masterRank)
00281 parts[p]=FEM_Mesh_recv(p,tag,comm_context);
00282 else
00283 parts[p]=fem_mesh;
00284 int new_mesh=FEM_Mesh_assemble(nParts,parts);
00285 for (p=0;p<nParts;p++)
00286 if (p!=masterRank)
00287 FEM_Mesh_deallocate(parts[p]);
00288 delete[] parts;
00289 return new_mesh;
00290 }
00291 }
00292 FORTRAN_AS_C_RETURN(int,FEM_MESH_REDUCE,FEM_Mesh_reduce,fem_mesh_reduce,
00293 (int *mesh,int *rank,int *comm),(*mesh,*rank,*comm))
00294
00295
00296 #ifdef FEM_PARALLEL_PART
00297 extern int FEM_Mesh_Parallel_broadcast(int fem_mesh,int masterRank,FEM_Comm_t comm_context);
00298 #endif
00299
00300 CLINKAGE int
00301 FEM_Mesh_broadcast(int fem_mesh,int masterRank,FEM_Comm_t comm_context)
00302 {
00303 #ifndef FEM_PARALLEL_PART
00304 int tag=89375;
00305 int myRank; MPI_Comm_rank((MPI_Comm)comm_context,&myRank);
00306 if (myRank==masterRank)
00307 {
00308 int p, nParts; MPI_Comm_size((MPI_Comm)comm_context,&nParts);
00309 int *parts=new int[nParts];
00310 FEM_Mesh_partition(fem_mesh,nParts,parts);
00311 int new_mesh=0;
00312 for (p=0;p<nParts;p++)
00313 if (p!=masterRank) {
00314 FEM_Mesh_send(parts[p],p,tag,comm_context);
00315 FEM_Mesh_deallocate(parts[p]);
00316 }
00317 else
00318 new_mesh=parts[p];
00319 return new_mesh;
00320 }
00321 else
00322 {
00323 return FEM_Mesh_recv(masterRank,tag,comm_context);
00324 }
00325 #else
00326 return FEM_Mesh_Parallel_broadcast(fem_mesh,masterRank,comm_context);
00327 #endif
00328 }
00329 FORTRAN_AS_C_RETURN(int,FEM_MESH_BROADCAST,FEM_Mesh_broadcast,fem_mesh_broadcast,
00330 (int *mesh,int *rank,int *comm),(*mesh,*rank,*comm))
00331
00332
00333 CLINKAGE void
00334 FEM_Mesh_copy_globalno(int src_mesh,int dest_mesh)
00335 {
00336 const char *caller="FEM_Mesh_copy_globalno";FEMAPI(caller);
00337 FEMchunk *c=FEMchunk::get(caller);
00338 c->lookup(dest_mesh,caller)->
00339 copyOldGlobalno(*c->lookup(src_mesh,caller));
00340 }
00341
00342
00343 CLINKAGE int FEM_Mesh_default_read(void)
00344 {
00345 return FEMchunk::get("FEM_Mesh_default_read")->default_read;
00346 }
00347 FORTRAN_AS_C_RETURN(int,
00348 FEM_MESH_DEFAULT_READ,FEM_Mesh_default_read,fem_mesh_default_read,
00349 (void),())
00350
00351 CLINKAGE int FEM_Mesh_default_write(void)
00352 {
00353 return FEMchunk::get("FEM_Mesh_default_write")->default_write;
00354 }
00355 FORTRAN_AS_C_RETURN(int,
00356 FEM_MESH_DEFAULT_WRITE,FEM_Mesh_default_write,fem_mesh_default_write,
00357 (void),())
00358
00359 CLINKAGE void FEM_Mesh_set_default_read(int fem_mesh)
00360 {
00361 FEMchunk::get("FEM_Mesh_set_default_read")->default_read=fem_mesh;
00362 }
00363 FORTRAN_AS_C(FEM_MESH_SET_DEFAULT_READ,FEM_Mesh_set_default_read,fem_mesh_set_default_read,
00364 (int *m),(*m))
00365 CLINKAGE void FEM_Mesh_set_default_write(int fem_mesh)
00366 {
00367 FEMchunk::get("FEM_Mesh_set_default_write")->default_write=fem_mesh;
00368 }
00369 FORTRAN_AS_C(FEM_MESH_SET_DEFAULT_WRITE,FEM_Mesh_set_default_write,fem_mesh_set_default_write,
00370 (int *m),(*m))
00371
00372
00373
00374
00375
00376 int *CkCopyArray(const int *src,int len,int indexBase)
00377 {
00378 int *ret=new int[len];
00379 for (int i=0;i<len;i++) ret[i]=src[i]-indexBase;
00380 return ret;
00381 }
00382
00383
00384
00385
00386 #if CMK_ERROR_CHECKING
00387 void FEMchunk::check(const char *where) {
00388
00389 }
00390 #endif
00391
00392 static FEM_Mesh *setMesh(void) {
00393 const char *caller="::setMesh";
00394 return FEMchunk::get(caller)->setMesh(caller);
00395 }
00396
00397 static const FEM_Mesh *getMesh(void) {
00398 const char *caller="::getMesh";
00399 return FEMchunk::get(caller)->getMesh(caller);
00400 }
00401
00402 FEM_Mesh *FEM_Mesh_lookup(int fem_mesh,const char *caller) {
00403 return FEMchunk::get(caller)->lookup(fem_mesh,caller);
00404 }
00405
00406
00407
00408
00409 CLINKAGE void FEM_Set_partition(int *elem2chunk) {
00410 FEMAPI("FEM_Set_partition");
00411 FEM_curPartition().setPartition(elem2chunk,setMesh()->nElems(),0);
00412 }
00413
00414
00415 FLINKAGE void FTN_NAME(FEM_SET_PARTITION,fem_set_partition)
00416 (int *elem2chunk)
00417 {
00418 FEMAPI("FEM_Set_partition");
00419 FEM_curPartition().setPartition(elem2chunk,setMesh()->nElems(),1);
00420 }
00421
00422
00423
00424
00425 FEMchunk::FEMchunk(FEM_Comm_t defaultComm_)
00426 :defaultComm(defaultComm_)
00427 {
00428 default_read=-1;
00429 default_write=-1;
00430 checkMPI(MPI_Comm_rank((MPI_Comm)defaultComm,&thisIndex));
00431 initFields();
00432 }
00433 FEMchunk::FEMchunk(CkMigrateMessage *msg)
00434 {
00435 initFields();
00436 }
00437
00438 void FEMchunk::pup(PUP::er &p)
00439 {
00440
00441
00442
00443 p|default_read;
00444 p|default_write;
00445 p|meshes;
00446
00447 p|defaultComm;
00448 p|thisIndex;
00449 }
00450
00451 PUPable_def(FEM_Sym_Linear)
00452
00453 void FEMchunk::initFields(void)
00454 {
00455 CmiLock(femLock);
00456 PUPable_reg(FEM_Sym_Linear);
00457 CmiUnlock(femLock);
00458 }
00459
00460 FEMchunk::~FEMchunk()
00461 {
00462 }
00463
00464
00465 void
00466 FEMchunk::reduce_field(int fid, const void *nodes, void *outbuf, int op)
00467 {
00468 check("reduce_field precondition");
00469
00470 const IDXL_Layout &dt = IDXL_Layout_List::get().get(fid,"FEM_Reduce_field");
00471 const unsigned char *src = (const unsigned char *)nodes;
00472 reduction_initialize(dt,outbuf,op);
00473 reduction_combine_fn fn=reduction_combine(dt,op);
00474 int nNodes=getMesh("reduce_field")->node.size();
00475 for(int i=0; i<nNodes; i++) {
00476 if(getPrimary(i)) {
00477 fn((unsigned char *)outbuf, src, &dt);
00478 }
00479 src += dt.userBytes();
00480 }
00481
00482 reduce(fid, outbuf, outbuf, op);
00483 check("reduce_field postcondition");
00484 }
00485
00486 void
00487 FEMchunk::reduce(int fid, const void *inbuf, void *outbuf, int op)
00488 {
00489 const char *caller="FEM_Reduce";
00490 check("reduce precondition");
00491 const IDXL_Layout &dt = IDXL_Layout_List::get().get(fid,caller);
00492 int len = dt.compressedBytes();
00493
00494 char *tmpbuf=new char[len];
00495 memcpy(tmpbuf,inbuf,len);
00496
00497 MPI_Datatype mpidt;
00498 switch (dt.type) {
00499 case IDXL_BYTE: mpidt=MPI_BYTE; break;
00500 case IDXL_INT: mpidt=MPI_INT; break;
00501 case IDXL_REAL: mpidt=MPI_FLOAT; break;
00502 case IDXL_DOUBLE: mpidt=MPI_DOUBLE; break;
00503 default: FEM_Abort(caller,"cannot map FEM datatype %d to MPI",dt.type); break;
00504 };
00505
00506 MPI_Op mpiop;
00507 switch (op) {
00508 case IDXL_SUM: mpiop=MPI_SUM; break;
00509 case IDXL_PROD: mpiop=MPI_PROD; break;
00510 case IDXL_MAX: mpiop=MPI_MAX; break;
00511 case IDXL_MIN: mpiop=MPI_MIN; break;
00512 default: FEM_Abort(caller,"cannot map FEM operation %d to MPI",op); break;
00513 };
00514 MPI_Comm comm=(MPI_Comm)defaultComm;
00515 MPI_Allreduce(tmpbuf,outbuf,dt.width,mpidt,mpiop,comm);
00516 delete[] tmpbuf;
00517 check("reduce postcondition");
00518 }
00519
00520 void
00521 FEMchunk::readField(int fid, void *nodes, const char *fname)
00522 {
00523 const IDXL_Layout &dt = IDXL_Layout_List::get().get(fid,"FEM_Read_field");
00524 int type = dt.type;
00525 int width = dt.width;
00526 int offset = dt.offset;
00527 int distance = dt.distance;
00528 int skew = dt.skew;
00529 FILE *fp = fopen(fname, "r");
00530 if(fp==0) {
00531 CkError("Cannot open file %s for reading.\n", fname);
00532 CkAbort("Exiting");
00533 }
00534 char str[80];
00535 char* pos;
00536 const char* fmt;
00537 int i, j, curline;
00538 #if FEM_FORTRAN
00539 curline = 1;
00540 #else
00541 curline = 0;
00542 #endif
00543 switch(type) {
00544 case FEM_INT: fmt = "%d%n"; break;
00545 case FEM_REAL: fmt = "%f%n"; break;
00546 case FEM_DOUBLE: fmt = "%lf%n"; break;
00547 default: CkAbort("FEM_Read_field doesn't support that data type");
00548 }
00549 FEM_Mesh *cur_mesh=getMesh("FEM_Read_field");
00550 int nNodes=cur_mesh->node.size();
00551 for(i=0;i<nNodes;i++) {
00552
00553
00554 int target=cur_mesh->node.getGlobalno(i);
00555 for(j=curline;j<target;j++)
00556 fgets(str,80,fp);
00557 curline = target+1;
00558 fgets(str,80,fp);
00559 int curnode, numchars;
00560 sscanf(str,"%d%n",&curnode,&numchars);
00561 pos = str + numchars;
00562 if(curnode != target) {
00563 CkError("Expecting info for node %d, got %d\n", target, curnode);
00564 CkAbort("Exiting");
00565 }
00566 for(j=0;j<width;j++) {
00567 sscanf(pos, fmt, &IDXL_LAYOUT_DEREF(unsigned char,nodes,i,j), &numchars);
00568 pos += numchars;
00569 }
00570 }
00571 fclose(fp);
00572 }
00573
00574
00575
00576 CLINKAGE int FEM_Register(void *_ud,FEM_PupFn _pup_ud)
00577 {
00578 FEMAPI("FEM_Register");
00579 return TCHARM_Register(_ud,_pup_ud);
00580 }
00581
00582 CLINKAGE void *FEM_Get_userdata(int n)
00583 {
00584 FEMAPI("FEM_Get_userdata");
00585 return TCHARM_Get_userdata(n);
00586 }
00587
00588 CLINKAGE void FEM_Barrier(void) {TCHARM_Barrier();}
00589 FLINKAGE void FTN_NAME(FEM_BARRIER,fem_barrier)(void) {TCHARM_Barrier();}
00590
00591 CLINKAGE void
00592 FEM_Migrate(void)
00593 {
00594
00595 AMPI_Migrate();
00596 }
00597
00598 CLINKAGE void
00599 FEM_Async_Migrate(void)
00600 {
00601 TCHARM_Async_Migrate();
00602 }
00603
00604 CLINKAGE void
00605 FEM_Done(void)
00606 {
00607 TCHARM_Done(0);
00608 }
00609
00610 CLINKAGE int
00611 FEM_Create_simple_field(int base_type, int vec_len)
00612 {
00613 return IDXL_Layout_create(base_type,vec_len);
00614 }
00615
00616 CLINKAGE int
00617 FEM_Create_field(int base_type, int vec_len, int init_offset, int distance)
00618 {
00619 return IDXL_Layout_offset(base_type,vec_len,init_offset,distance,0);
00620 }
00621
00622 CLINKAGE void
00623 FEM_Update_field(int fid, void *nodes)
00624 {
00625 int mesh=FEM_Mesh_default_read();
00626 IDXL_t list=FEM_Comm_shared(mesh,FEM_NODE);
00627 IDXL_Comm_sendsum(0,list,fid,nodes);
00628 }
00629
00630 CLINKAGE void
00631 FEM_Reduce_field(int fid, const void *nodes, void *outbuf, int op)
00632 {
00633 const char *caller="FEM_Reduce_field"; FEMAPI(caller);
00634 FEMchunk::get(caller)->reduce_field(fid, nodes, outbuf, op);
00635 }
00636
00637 CLINKAGE void
00638 FEM_Reduce(int fid, const void *inbuf, void *outbuf, int op)
00639 {
00640 const char *caller="FEM_Reduce";FEMAPI(caller);
00641 FEMchunk::get(caller)->reduce(fid, inbuf, outbuf, op);
00642 }
00643
00644 CLINKAGE void
00645 FEM_Read_field(int fid, void *nodes, const char *fname)
00646 {
00647 const char *caller="FEM_Read_field";FEMAPI(caller);
00648 FEMchunk::get(caller)->readField(fid, nodes, fname);
00649 }
00650
00651 CLINKAGE int
00652 FEM_My_partition(void)
00653 {
00654 return TCHARM_Element();
00655 }
00656
00657 CLINKAGE int
00658 FEM_Num_partitions(void)
00659 {
00660 return TCHARM_Num_elements();
00661 }
00662
00663 CLINKAGE double
00664 FEM_Timer(void)
00665 {
00666 return TCHARM_Wall_timer();
00667 }
00668
00669 CLINKAGE void
00670 FEM_Print(const char *str)
00671 {
00672 const char *caller="FEM_Print"; FEMAPI(caller);
00673 CkPrintf("[%d] %s\n", TCHARM_Element(), str);
00674 }
00675
00676 static void do_print_partition(int fem_mesh,int idxBase) {
00677
00678 const char *caller="FEM_Mesh_print"; FEMAPI(caller);
00679 FEMchunk *cptr = FEMchunk::get(caller);
00680 cptr->print(fem_mesh,idxBase);
00681 }
00682
00683 CLINKAGE void
00684 FEM_Mesh_print(int fem_mesh)
00685 {
00686 do_print_partition(fem_mesh,0);
00687 }
00688
00689 CLINKAGE void
00690 FEM_Print_partition(void) {
00691 do_print_partition(FEM_Mesh_default_read(),0);
00692 }
00693
00694 CLINKAGE int FEM_Get_comm_partners(void)
00695 {
00696 const char *caller="FEM_Get_Comm_Partners"; FEMAPI(caller);
00697 return FEMchunk::get(caller)->getComm().size();
00698 }
00699 CLINKAGE int FEM_Get_comm_partner(int partnerNo)
00700 {
00701 const char *caller="FEM_Get_Comm_Partner"; FEMAPI(caller);
00702 return FEMchunk::get(caller)->getComm().getLocalList(partnerNo).getDest();
00703 }
00704 CLINKAGE int FEM_Get_comm_count(int partnerNo)
00705 {
00706 const char *caller="FEM_Get_Comm_Count"; FEMAPI(caller);
00707 return FEMchunk::get(caller)->getComm().getLocalList(partnerNo).size();
00708 }
00709 CLINKAGE void FEM_Get_comm_nodes(int partnerNo,int *nodeNos)
00710 {
00711 const char *caller="FEM_Get_comm_nodes"; FEMAPI(caller);
00712 const int *nNo=FEMchunk::get(caller)->getComm().getLocalList(partnerNo).getVec();
00713 int len=FEM_Get_comm_count(partnerNo);
00714 for (int i=0;i<len;i++)
00715 nodeNos[i]=nNo[i];
00716 }
00717
00718
00719
00720 FLINKAGE int FTN_NAME(FEM_REGISTER,fem_register)
00721 (void *userData,FEM_PupFn _pup_ud)
00722 {
00723 return FEM_Register(userData,_pup_ud);
00724 }
00725
00726 FLINKAGE void FTN_NAME(FEM_MIGRATE,fem_migrate)
00727 (void)
00728 {
00729 FEM_Migrate();
00730 }
00731
00732 FLINKAGE void FTN_NAME(FEM_ASYNC_MIGRATE,fem_async_migrate)
00733 (void)
00734 {
00735 FEM_Async_Migrate();
00736 }
00737
00738 FLINKAGE int FTN_NAME(FEM_CREATE_SIMPLE_FIELD,fem_create_simple_field)
00739 (int *bt, int *vl)
00740 {
00741 return FEM_Create_simple_field(*bt, *vl);
00742 }
00743 FLINKAGE int FTN_NAME(FEM_CREATE_FIELD,fem_create_field)
00744 (int *bt, int *vl, int *io, int *d)
00745 {
00746 return FEM_Create_field(*bt, *vl, *io, *d);
00747 }
00748
00749 FLINKAGE void FTN_NAME(FEM_UPDATE_FIELD,fem_update_field)
00750 (int *fid, void *nodes)
00751 {
00752 FEM_Update_field(*fid, nodes);
00753 }
00754
00755 FLINKAGE void FTN_NAME(FEM_REDUCE_FIELD,fem_reduce_field)
00756 (int *fid, void *nodes, void *outbuf, int *op)
00757 {
00758 FEM_Reduce_field(*fid, nodes, outbuf, *op);
00759 }
00760
00761 FLINKAGE void FTN_NAME(FEM_REDUCE,fem_reduce)
00762 (int *fid, void *inbuf, void *outbuf, int *op)
00763 {
00764 FEM_Reduce(*fid, inbuf, outbuf, *op);
00765 }
00766
00767 FLINKAGE void FTN_NAME(FEM_READ_FIELD,fem_read_field)
00768 (int *fid, void *nodes, char *fname, int len)
00769 {
00770 char *tmp = new char[len+1]; CHK(tmp);
00771 memcpy(tmp, fname, len);
00772 tmp[len] = '\0';
00773 FEM_Read_field(*fid, nodes, tmp);
00774 delete[] tmp;
00775 }
00776
00777 FLINKAGE int FTN_NAME(FEM_MY_PARTITION,fem_my_partition)
00778 (void)
00779 {
00780 return FEM_My_partition()+1;
00781 }
00782
00783 FLINKAGE int FTN_NAME(FEM_NUM_PARTITIONS,fem_num_partitions)
00784 (void)
00785 {
00786 return FEM_Num_partitions();
00787 }
00788
00789 FLINKAGE double FTN_NAME(FEM_TIMER,fem_timer)
00790 (void)
00791 {
00792 return FEM_Timer();
00793 }
00794
00795
00796 FLINKAGE int FTN_NAME(FOFFSETOF,foffsetof)
00797 (void *first, void *second)
00798 {
00799 return (int)((char *)second - (char*)first);
00800 }
00801
00802 FLINKAGE void FTN_NAME(FEM_PRINT,fem_print)
00803 (char *str, int len)
00804 {
00805 char *tmpstr = new char[len+1]; CHK(tmpstr);
00806 memcpy(tmpstr,str,len);
00807 tmpstr[len] = '\0';
00808 FEM_Print(tmpstr);
00809 delete[] tmpstr;
00810 }
00811
00812 FLINKAGE void FTN_NAME(FEM_MESH_PRINT,fem_mesh_print)
00813 (int *m)
00814 {
00815 do_print_partition(*m,1);
00816 }
00817 FLINKAGE void FTN_NAME(FEM_PRINT_PARTITION,fem_print_partition)(void) {
00818 do_print_partition(FEM_Mesh_default_read(),0);
00819 }
00820
00821 FLINKAGE void FTN_NAME(FEM_DONE,fem_done)
00822 (void)
00823 {
00824 FEM_Done();
00825 }
00826
00827 FLINKAGE int FTN_NAME(FEM_GET_COMM_PARTNERS,fem_get_comm_partners)
00828 (void)
00829 {
00830 return FEM_Get_comm_partners();
00831 }
00832 FLINKAGE int FTN_NAME(FEM_GET_COMM_PARTNER,fem_get_comm_partner)
00833 (int *partnerNo)
00834 {
00835 return FEM_Get_comm_partner(*partnerNo-1)+1;
00836 }
00837 FLINKAGE int FTN_NAME(FEM_GET_COMM_COUNT,fem_get_comm_count)
00838 (int *partnerNo)
00839 {
00840 return FEM_Get_comm_count(*partnerNo-1);
00841 }
00842 FLINKAGE void FTN_NAME(FEM_GET_COMM_NODES,fem_get_comm_nodes)
00843 (int *pNo,int *nodeNos)
00844 {
00845 const char *caller="FEM_GET_COMM_NODES"; FEMAPI(caller);
00846 int partnerNo=*pNo-1;
00847 const int *nNo=FEMchunk::get(caller)->getComm().getLocalList(partnerNo).getVec();
00848 int len=FEM_Get_comm_count(partnerNo);
00849 for (int i=0;i<len;i++)
00850 nodeNos[i]=nNo[i]+1;
00851 }
00852
00853
00854
00866 FEM_Ghost_Stencil::FEM_Ghost_Stencil(int elType_, int n_,bool addNodes_,
00867 const int *userEnds,
00868 const int *userAdj,
00869 int idxBase)
00870 :elType(elType_), n(n_), addNodes(addNodes_),
00871 ends(new int[n]), adj(new int[2*userEnds[n-1]])
00872 {
00873 int i;
00874 int lastEnd=0;
00875 for (i=0;i<n;i++) {
00876 ends[i]=userEnds[i];
00877 if (ends[i]<lastEnd) {
00878 CkError("FEM_Ghost_Stencil> ends array not monotonic!\n"
00879 " ends[%d]=%d < previous value %d\n",
00880 i,ends[i],lastEnd);
00881 CkAbort("FEM_Ghost_Stencil> ends array not monotonic");
00882 }
00883 lastEnd=ends[i];
00884 }
00885 int m=ends[n-1];
00886 for (i=0;i<m;i++) {
00887 adj[2*i+0]=userAdj[2*i+0];
00888 adj[2*i+1]=userAdj[2*i+1]-idxBase;
00889 }
00890 }
00891
00892 CLINKAGE void FEM_Add_ghost_stencil_type(int elType,int nElts,int addNodes,
00893 const int *ends,const int *adj2)
00894 {
00895 FEMAPI("FEM_Add_ghost_stencil_type");
00896 FEM_Ghost_Stencil *s=new FEM_Ghost_Stencil(
00897 elType, nElts, addNodes==1, ends, adj2, 0);
00898 FEM_curPartition().addGhostStencil(s);
00899 }
00900 FLINKAGE void FTN_NAME(FEM_ADD_GHOST_STENCIL_TYPE,fem_add_ghost_stencil_type)(
00901 int *elType,int *nElts,int *addNodes,
00902 const int *ends,const int *adj2)
00903 {
00904 FEMAPI("FEM_Add_ghost_stencil_type");
00905 FEM_Ghost_Stencil *s=new FEM_Ghost_Stencil(
00906 *elType, *nElts, *addNodes==1, ends, adj2, 1);
00907 FEM_curPartition().addGhostStencil(s);
00908 }
00909
00910
00911 inline int globalElem2elType(const FEM_Mesh *m,int globalElem) {
00912 int curStart=0;
00913 for (int t=0;t<m->elem.size();t++) if (m->elem.has(t)) {
00914 int n=m->elem[t].size();
00915 if (globalElem>=curStart && globalElem<curStart+n)
00916 return t;
00917 curStart+=n;
00918 }
00919 CkError("FEM> Invalid global element number %d!\n",globalElem);
00920 CkAbort("FEM> Invalid global element number!");
00921 return 0;
00922 }
00923
00924
00925
00926
00927
00928
00929 CLINKAGE void FEM_Add_ghost_stencil(int nElts,int addNodes,
00930 const int *ends,const int *adj)
00931 {
00932 FEMAPI("FEM_Add_ghost_stencil");
00933 const FEM_Mesh *m=setMesh();
00934 int adjSrc=0, endsSrc=0;
00935 for (int t=0;t<m->elem.size();t++) if (m->elem.has(t)) {
00936 const FEM_Elem &el=m->elem[t];
00937 int n=el.size();
00938 int nAdjLocal=ends[endsSrc+n-1]-adjSrc;
00939 int *adjLocal=new int[2*nAdjLocal];
00940 int *endsLocal=new int[n];
00941 int adjDest=0, endsDest=0;
00942 while (endsDest<n) {
00943 while (adjSrc<ends[endsSrc]) {
00944
00945 int et=globalElem2elType(m,adj[adjSrc]);
00946 adjLocal[2*adjDest+0]=et;
00947 adjLocal[2*adjDest+1]=adj[adjSrc]-m->nElems(et);
00948 adjDest++; adjSrc++;
00949 }
00950
00951 endsLocal[endsDest]=adjDest;
00952 endsDest++; endsSrc++;
00953 }
00954 if (adjDest!=nAdjLocal)
00955 CkAbort("FEM_Add_ghost_stencil adjacency count mismatch!");
00956 FEM_Add_ghost_stencil_type(t,n,addNodes,endsLocal,adjLocal);
00957 delete []endsLocal;
00958 delete []adjLocal;
00959 }
00960 if (endsSrc!=nElts) {
00961 CkError("FEM_Add_ghost_stencil: FEM thinks there are %d elements, but nElts is %d!\n",endsSrc,nElts);
00962 CkAbort("FEM_Add_ghost_stencil elements mismatch!");
00963 }
00964 FEM_curPartition().markGhostStencilLayer();
00965 }
00966 FLINKAGE void FTN_NAME(FEM_ADD_GHOST_STENCIL,fem_add_ghost_stencil)(
00967 int *nElts,int *addNodes,
00968 const int *ends,int *adj)
00969 {
00970 FEMAPI("FEM_Add_ghost_stencil");
00971 int i, n=ends[*nElts-1];
00972 for (i=0;i<n;i++) adj[i]--;
00973 FEM_Add_ghost_stencil(*nElts,*addNodes,ends,adj);
00974 for (i=0;i<n;i++) adj[i]++;
00975 }
00976
00977
00978 CLINKAGE void FEM_Add_ghost_layer(int nodesPerTuple,int doAddNodes)
00979 {
00980 FEMAPI("FEM_Add_ghost_layer");
00981 FEM_Ghost_Layer *cur=FEM_curPartition().addLayer();
00982 cur->nodesPerTuple=nodesPerTuple;
00983 cur->addNodes=(doAddNodes!=0);
00984 }
00985 FLINKAGE void FTN_NAME(FEM_ADD_GHOST_LAYER,fem_add_ghost_layer)
00986 (int *nodesPerTuple,int *doAddNodes)
00987 { FEM_Add_ghost_layer(*nodesPerTuple,*doAddNodes); }
00988
00989 static void add_ghost_elem(int elType,int tuplesPerElem,const int *elem2tuple,int idxBase) {
00990 FEMAPI("FEM_Add_ghost_elem");
00991 FEM_Ghost_Layer *cur=FEM_curPartition().curLayer();
00992 if (elType>=FEM_ELEM) elType-=FEM_ELEM;
00993 if (elType>=FEM_GHOST) elType-=FEM_GHOST;
00994 if (elType>=FEM_MAX_ELTYPE) CkAbort("Element exceeds (stupid) hardcoded maximum element types\n");
00995 cur->elem[elType].add=true;
00996 cur->elem[elType].tuplesPerElem=tuplesPerElem;
00997 cur->elem[elType].elem2tuple=CkCopyArray(elem2tuple,
00998 tuplesPerElem*cur->nodesPerTuple,idxBase);
00999 }
01000
01001 CLINKAGE void FEM_Add_ghost_elem(int elType,int tuplesPerElem,const int *elem2tuple)
01002 { add_ghost_elem(elType,tuplesPerElem,elem2tuple,0); }
01003 FLINKAGE void FTN_NAME(FEM_ADD_GHOST_ELEM,fem_add_ghost_elem)
01004 (int *FelType,int *FtuplesPerElem,const int *elem2tuple)
01005 { add_ghost_elem(*FelType,*FtuplesPerElem,elem2tuple,1); }
01006
01007 CLINKAGE void FEM_Update_ghost_field(int fid, int elType, void *v_data)
01008 {
01009 int mesh=FEM_Mesh_default_read();
01010 int entity;
01011 if (elType==-1) entity=FEM_NODE;
01012 else entity=FEM_ELEM+elType;
01013 IDXL_t src=FEM_Comm_ghost(mesh,entity);
01014 int nReal=FEM_Mesh_get_length(mesh,entity);
01015 int bytesPerRec=IDXL_Get_layout_distance(fid);
01016 char *data=(char *)v_data;
01017 IDXL_Comm_t comm=IDXL_Comm_begin(1,0);
01018 IDXL_Comm_send(comm,src,fid,data);
01019 IDXL_Comm_recv(comm,src,fid,&data[nReal*bytesPerRec]);
01020 IDXL_Comm_wait(comm);
01021 }
01022 FLINKAGE void FTN_NAME(FEM_UPDATE_GHOST_FIELD,fem_update_ghost_field)
01023 (int *fid, int *elemType, void *data)
01024 {
01025 int fElType=*elemType;
01026 if (fElType==0)
01027 FEM_Update_ghost_field(*fid,-1,data);
01028 else
01029 FEM_Update_ghost_field(*fid,fElType,data);
01030 }
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042 void FEMchunk::exchangeGhostLists(int elemType,
01043 int inLen,const int *inList,int idxbase)
01044 {
01045 check("exchangeGhostLists");
01046 FEM_Mesh *cur_mesh=getMesh("exchangeGhostLists");
01047 const FEM_Entity &e=cur_mesh->getCount(elemType);
01048 const FEM_Comm &cnt=e.getGhostSend();
01049 int tag=89376;
01050 MPI_Comm comm=(MPI_Comm)defaultComm;
01051
01052
01053 int i,chk,nChk=cnt.size();
01054 CkVec<int> *outIdx=new CkVec<int>[nChk];
01055
01056 for (i=0;i<inLen;i++) {
01057 int localNo=inList[i]-idxbase;
01058 const FEM_Comm_Rec *rec=cnt.getRec(localNo);
01059 if (NULL==rec) continue;
01060
01061 for (int s=0;s<rec->getShared();s++) {
01062 int localChk=cnt.findLocalList(rec->getChk(s));
01063 outIdx[localChk].push_back(rec->getIdx(s));
01064 }
01065 }
01066
01067
01068 MPI_Request *sends=new MPI_Request[nChk];
01069 for (chk=0;chk<nChk;chk++) {
01070 checkMPI(MPI_Isend(outIdx[chk].getVec(),outIdx[chk].size(),MPI_INT,
01071 cnt.getLocalList(chk).getDest(),tag,comm,&sends[chk]));
01072 }
01073
01074
01075 int listStart=0;
01076 for (chk=0;chk<e.getGhostRecv().size();chk++) {
01077 int src=e.getGhostRecv().getLocalList(chk).getDest();
01078 int nRecv=MPI_Incoming_pup(MPI_INT,src,tag,comm);
01079 listTmp.resize(listStart+nRecv);
01080 int *list=&listTmp[listStart];
01081 MPI_Status sts;
01082 checkMPI(MPI_Recv(list,nRecv,MPI_INT,src,tag,comm,&sts));
01083
01084
01085 int firstGhost=e.size();
01086 const FEM_Comm_List &l=e.getGhostRecv().getLocalList(chk);
01087 for (i=0;i<nRecv;i++)
01088 list[i]=firstGhost+l[list[i]];
01089 listStart+=nRecv;
01090 }
01091
01092
01093 MPI_Status *sts=new MPI_Status[nChk];
01094 checkMPI(MPI_Waitall(nChk,sends,sts));
01095 delete[] sts;
01096 delete[] sends;
01097 delete[] outIdx;
01098 }
01099
01100
01101 CLINKAGE void FEM_Exchange_ghost_lists(int elemType,int nIdx,const int *localIdx)
01102 {
01103 const char *caller="FEM_Exchange_Ghost_Lists"; FEMAPI(caller);
01104 FEMchunk::get(caller)->exchangeGhostLists(elemType,nIdx,localIdx,0);
01105 }
01106 FLINKAGE void FTN_NAME(FEM_EXCHANGE_GHOST_LISTS,fem_exchange_ghost_lists)
01107 (int *elemType,int *nIdx,const int *localIdx)
01108 {
01109 const char *caller="FEM_exchange_ghost_lists"; FEMAPI(caller);
01110 FEMchunk::get(caller)->exchangeGhostLists(*elemType,*nIdx,localIdx,1);
01111 }
01112 CLINKAGE int FEM_Get_ghost_list_length(void)
01113 {
01114 const char *caller="FEM_Get_Ghost_List_Length"; FEMAPI(caller);
01115 return FEMchunk::get(caller)->getList().size();
01116 }
01117 FLINKAGE int FTN_NAME(FEM_GET_GHOST_LIST_LENGTH,fem_get_ghost_list_length)(void)
01118 { return FEM_Get_ghost_list_length();}
01119
01120 CLINKAGE void FEM_Get_ghost_list(int *dest)
01121 {
01122 const char *caller="FEM_Get_Ghost_List"; FEMAPI(caller);
01123 int i,len=FEM_Get_ghost_list_length();
01124 const int *src=FEMchunk::get(caller)->getList().getVec();
01125 for (i=0;i<len;i++) dest[i]=src[i];
01126 FEMchunk::get(caller)->emptyList();
01127 }
01128 FLINKAGE void FTN_NAME(FEM_GET_GHOST_LIST,fem_get_ghost_list)
01129 (int *dest)
01130 {
01131 const char *caller="FEM_get_ghost_list"; FEMAPI(caller);
01132 int i,len=FEM_Get_ghost_list_length();
01133 const int *src=FEMchunk::get(caller)->getList().getVec();
01134 for (i=0;i<len;i++) dest[i]=src[i]+1;
01135 FEMchunk::get(caller)->emptyList();
01136 }
01137
01138
01139
01140
01142 static void getRoccomPconn(IDXL_Side_t is,int bias,CkVec<int> &pconn,const int *paneFmChunk)
01143 {
01144 int p,np=IDXL_Get_partners(is);
01145 pconn.push_back(np);
01146 for (p=0;p<np;p++) {
01147 int chunk=IDXL_Get_partner(is,p);
01148 int pane=1+chunk;
01149 if(paneFmChunk) pane=paneFmChunk[chunk];
01150 pconn.push_back(pane);
01151 int n,nn=IDXL_Get_count(is,p);
01152 pconn.push_back(nn);
01153 for (n=0;n<nn;n++)
01154 pconn.push_back(IDXL_Get_index(is,p,n)+1+bias);
01155 }
01156 }
01157
01159 static CkVec<int> getRoccomPconn(int fem_mesh,int *ghost_len,const int *paneFmChunk)
01160 {
01161 CkVec<int> pconn;
01162
01163 getRoccomPconn(IDXL_Get_send(FEM_Comm_shared(fem_mesh,FEM_NODE)),0,pconn,paneFmChunk);
01164 int realLen=pconn.size();
01165
01166
01167 getRoccomPconn(IDXL_Get_send(FEM_Comm_ghost(fem_mesh,FEM_NODE)),0,pconn,paneFmChunk);
01168
01169 getRoccomPconn(IDXL_Get_recv(FEM_Comm_ghost(fem_mesh,FEM_NODE)),
01170 FEM_Mesh_get_length(fem_mesh,FEM_NODE),pconn,paneFmChunk);
01171
01172
01173
01174 int elems[1024];
01175 int e, ne=FEM_Mesh_get_entities(fem_mesh,elems);
01176 for (e=0;e<ne;e++)
01177 if (elems[e]<FEM_ELEM || elems[e]>=FEM_SPARSE)
01178 elems[e--]=elems[--ne];
01179
01180
01181 IDXL_t elghost=IDXL_Create();
01182 int out_r=0, out_g=0;
01183 for (e=0;e<ne;e++) {
01184 IDXL_Combine(elghost,FEM_Comm_ghost(fem_mesh,elems[e]), out_r,out_g);
01185 out_r+=FEM_Mesh_get_length(fem_mesh,elems[e]);
01186 out_g+=FEM_Mesh_get_length(fem_mesh,elems[e]+FEM_GHOST);
01187 }
01188
01189
01190 getRoccomPconn(IDXL_Get_send(elghost),0,pconn,paneFmChunk);
01191
01192 getRoccomPconn(IDXL_Get_recv(elghost),out_r,pconn,paneFmChunk);
01193 IDXL_Destroy(elghost);
01194
01195 if (ghost_len) *ghost_len=pconn.size()-realLen;
01196 return pconn;
01197 }
01198
01199 CLINKAGE void FEM_Get_roccom_pconn_size(int fem_mesh,int *total_len,int *ghost_len)
01200 {
01201 CkVec<int> pconn=getRoccomPconn(fem_mesh,ghost_len,NULL);
01202 *total_len=pconn.size();
01203 }
01204 FORTRAN_AS_C(FEM_GET_ROCCOM_PCONN_SIZE,FEM_Get_roccom_pconn_size,fem_get_roccom_pconn_size,
01205 (int *mesh,int *tl,int *gl), (*mesh,tl,gl)
01206 )
01207
01208 CLINKAGE void FEM_Get_roccom_pconn(int fem_mesh,const int *paneFmChunk,int *dest)
01209 {
01210 CkVec<int> pconn=getRoccomPconn(fem_mesh,NULL,paneFmChunk);
01211 for (unsigned int i=0;i<pconn.size();i++)
01212 dest[i]=pconn[i];
01213 }
01214 FORTRAN_AS_C(FEM_GET_ROCCOM_PCONN,FEM_Get_roccom_pconn,fem_get_roccom_pconn,
01215 (int *mesh,int *paneFmChunk,int *dest), (*mesh,paneFmChunk,dest)
01216 )
01217
01218 int findChunk(int paneID,const int *paneFmChunk)
01219 {
01220 for (int c=0;paneFmChunk[c]>0;c++)
01221 if (paneFmChunk[c]==paneID)
01222 return c;
01223 CkError("Can't find chunk for pconn paneID %d!\n",paneID);
01224 CmiAbort("Bad pconn array");
01225 return -1;
01226 }
01227
01228 const int* makeIDXLside(const int *src,const int *paneFmChunk,IDXL_Side &s) {
01229 int nPartner=*src++;
01230 for (int p=0;p<nPartner;p++) {
01231 int paneID=*src++;
01232 int chunk=findChunk(paneID,paneFmChunk);
01233 int nComm=*src++;
01234 for (int i=0;i<nComm;i++)
01235 s.addNode(*src++ - 1,chunk);
01236 }
01237 return src;
01238 }
01239
01240 CLINKAGE void FEM_Set_roccom_pconn(int fem_mesh,const int *paneFmChunk,const int *src,int total_len,int ghost_len)
01241 {
01242 const char *caller="FEM_Set_roccom_pconn"; FEMAPI(caller);
01243 FEM_Mesh *m=FEM_Mesh_lookup(fem_mesh,caller);
01245 makeIDXLside(src,paneFmChunk,m->node.shared);
01246 }
01247 FORTRAN_AS_C(FEM_SET_ROCCOM_PCONN,FEM_Set_roccom_pconn,fem_set_roccom_pconn,
01248 (int *mesh,const int *paneFmChunk,const int *src,int *tl,int *gl), (*mesh,paneFmChunk,src,*tl,*gl)
01249 )
01250
01251 enum {comm_unshared, comm_shared, comm_primary};
01252 int commState(int entityNo,const IDXL_Side &s)
01253 {
01254 const IDXL_Rec *r=s.getRec(entityNo);
01255 if (r==NULL || r->getShared()==0) return comm_unshared;
01256 int thisChunk=FEM_My_partition();
01257 for (int p=0;p<r->getShared();p++) {
01258 if (r->getChk(p)<thisChunk)
01259 return comm_shared;
01260
01261 }
01262
01263
01264 return comm_primary;
01265 }
01266
01271 CLINKAGE void FEM_Make_node_globalno(int fem_mesh,FEM_Comm_t comm_context)
01272 {
01273 const char *caller="FEM_Make_node_globalno"; FEMAPI(caller);
01274 FEM_Mesh *m=FEM_Mesh_lookup(fem_mesh,caller);
01275 int n, nNo=m->node.size();
01276 const IDXL_Side &shared=m->node.shared;
01277 CkVec<int> globalNo(nNo);
01278 CkVec<char> nodePrimary(nNo);
01279
01280
01281 int nLocal=0;
01282 for (n=0;n<nNo;n++) {
01283 switch (commState(n,shared)) {
01284 case comm_unshared:
01285 nodePrimary[n]=0;
01286 globalNo[n]=nLocal++;
01287 break;
01288 case comm_shared:
01289 nodePrimary[n]=0;
01290 globalNo[n]=-1;
01291 break;
01292 case comm_primary:
01293 nodePrimary[n]=1;
01294 globalNo[n]=nLocal++;
01295 break;
01296 };
01297 }
01298
01299
01300
01301 MPI_Comm comm=(MPI_Comm)comm_context;
01302 int firstGlobal=0;
01303 MPI_Scan(&nLocal,&firstGlobal, 1,MPI_INT, MPI_SUM,comm);
01304 firstGlobal-=nLocal;
01305 for (n=0;n<nNo;n++) {
01306 if (globalNo[n]==-1) globalNo[n]=0;
01307 else globalNo[n]+=firstGlobal;
01308 }
01309
01310
01311 IDXL_Layout_t l=IDXL_Layout_create(IDXL_INT,1);
01312 IDXL_Comm_t c=IDXL_Comm_begin(72173841,comm_context);
01313 IDXL_Comm_sendsum(c,FEM_Comm_shared(fem_mesh,FEM_NODE),l,&globalNo[0]);
01314 IDXL_Comm_wait(c);
01315 IDXL_Layout_destroy(l);
01316
01317
01318 FEM_Mesh_set_data(fem_mesh,FEM_NODE, FEM_GLOBALNO,
01319 &globalNo[0], 0,nNo, FEM_INDEX_0,1);
01320 FEM_Mesh_set_data(fem_mesh,FEM_NODE, FEM_NODE_PRIMARY,
01321 &nodePrimary[0], 0,nNo, FEM_BYTE,1);
01322 }
01323
01324 FORTRAN_AS_C(FEM_MAKE_NODE_GLOBALNO,FEM_Make_node_globalno,fem_make_node_globalno,
01325 (int *mesh,int *comm), (*mesh,*comm)
01326 )
01327
01328
01329
01330 class localToGlobal : public IDXL_Print_Map {
01331 FEM_Entity &e;
01332 public:
01333 int idxBase;
01334 localToGlobal(FEM_Entity &e_, int idxBase_)
01335 :e(e_), idxBase(idxBase_) {}
01336
01337 void map(int l) const {
01338 if (l<0) CkPrintf("(%d) ",l+idxBase);
01339 else {
01340 int g=e.getGlobalno(l);
01341 if (g==-1) CkPrintf("(%d) ",l+idxBase);
01342 else CkPrintf("%d ",g+idxBase);
01343 }
01344 }
01345 };
01346
01347 void FEM_Entity::print(const char *type,const IDXL_Print_Map &l2g)
01348 {
01349 CkPrintf("\nLength of %s = %d", type, size());
01350 if (ghost->size()>0) CkPrintf(" (and %d ghosts)\n",ghost->size());
01351 else CkPrintf("\n");
01352
01353
01354 }
01355
01356 void FEM_Node::print(const char *type,const IDXL_Print_Map &l2g)
01357 {
01358 super::print(type,l2g);
01359 CkPrintf("Node global numbers: * marks primary, () surrounds local-only:\n");
01360 for(int i=0;i<size();i++) {
01361 if (getPrimary(i)) CkPrintf("*");
01362 l2g.map(i);
01363 }
01364 CkPrintf("\n");
01365 }
01366
01367
01368
01369 void FEM_Elem::print(const char *type,const IDXL_Print_Map &l2g)
01370 {
01371 super::print(type,l2g);
01372
01373 localToGlobal *src_l2g=(localToGlobal *)&l2g;
01374 localToGlobal elt_l2g(*this,src_l2g->idxBase);
01375
01376 CkPrintf("%s Connectivity: \n",type);
01377 for (int r=0;r<size();r++) {
01378 CkPrintf(" Entry "); elt_l2g.map(r); CkPrintf("| ");
01379 for (int c=0;c<getNodesPer();c++)
01380 l2g.map(conn->get()(r,c));
01381 CkPrintf("\n");
01382 }
01383 }
01384
01385 void FEM_Mesh::print(int idxBase)
01386 {
01387 localToGlobal l2g(node,idxBase);
01388 node.print("FEM_NODE",l2g);
01389 int t;
01390 for (t=0;t<elem.size();t++)
01391 if (elem.has(t)) {
01392 char name[50]; sprintf(name,"FEM_ELEM+%d",t);
01393 elem[t].print(name,l2g);
01394 }
01395 for (t=0;t<sparse.size();t++)
01396 if (sparse.has(t)) {
01397 char name[50]; sprintf(name,"FEM_SPARSE+%d",t);
01398 sparse[t].print(name,l2g);
01399 }
01400 }
01401
01402 void
01403 FEMchunk::print(int fem_mesh,int idxBase)
01404 {
01405 CkPrintf("-------------------- Chunk %d --------------------\n",thisIndex);
01406 lookup(fem_mesh,"FEM_Mesh_print")->print(idxBase);
01407 CkPrintf("\n\n");
01408 }
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422 CLINKAGE void FEM_Add_elem2face_tuples(int fem_mesh, int elem_type, int nodesPerTuple, int tuplesPerElem,const int *elem2tuple)
01423 {
01424 FEMAPI("FEM_Add_elem2face_tuples");
01425 FEM_Mesh *m = FEM_Mesh_lookup(fem_mesh,"FEM_Add_elem2face_tuples");
01426 FEM_ElemAdj_Layer *cur=m->getElemAdjLayer();
01427 cur->initialized = 1;
01428
01429 if(cur->elem[elem_type].tuplesPerElem != 0)
01430 CkPrintf("FEM> WARNING: Don't call FEM_Add_elem2face_tuples() repeatedly with the same element type\n");
01431
01432 int idxBase=0;
01433 cur->nodesPerTuple=nodesPerTuple;
01434 cur->elem[elem_type].tuplesPerElem=tuplesPerElem;
01435 cur->elem[elem_type].elem2tuple=CkCopyArray(elem2tuple,
01436 tuplesPerElem*cur->nodesPerTuple,idxBase);
01437
01438 }
01439 FORTRAN_AS_C(FEM_ADD_ELEM2FACE_TUPLES,FEM_Add_elem2face_tuples,fem_add_elem2face_tuples,
01440 (int *fem_mesh,int *elem_type,int *nodesPerTuple, int *tuplesPerElem, int *elem2tuple),
01441 (*fem_mesh, *elem_type, *nodesPerTuple, *tuplesPerElem, elem2tuple)
01442 )