00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "ParFUM.h"
00011 #include "ParFUM_internals.h"
00012
00013
00014
00015
00016
00017
00018 class unionFind : private CkNoncopyable {
00019 int n;
00020 int *parent;
00021 public:
00022 unionFind(int n_) {
00023 n=n_;
00024 parent=new int[n];
00025 for (int i=0;i<n;i++) parent[i]=i;
00026 }
00027 ~unionFind(void) {
00028 delete[] parent;
00029 }
00030
00031 int *detach(void) {
00032 int *ret=parent;
00033 parent=NULL;
00034 return ret;
00035 }
00036
00037
00038 int find(int i) const {
00039 while (i!=parent[i]) i=parent[i];
00040 return i;
00041 }
00042
00043
00044 void combine(int a,int b) {
00045 parent[find(a)]=find(b);
00046 }
00047
00048
00049
00050 void compress(void) {
00051 for (int i=0;i<n;i++) parent[i]=find(i);
00052 }
00053 };
00054
00055
00056
00057
00058
00059
00060
00061 class faceSet {
00062 int nFaces;
00063 int nPer;
00064 const int *idx;
00065 int idxBase;
00066 const CkVector3d *loc;
00067 CkVector3d *faceCen;
00068
00069
00070 CkVector3d calcFaceLoc(int faceNo) const
00071 {
00072 CkVector3d sum(0.0);
00073 int total=0;
00074 for (int i=0;i<nPer;i++) {
00075 int nodeNo=getNode(faceNo,i);
00076 if (nodeNo!=-1) {
00077 sum+=getNodeLoc(nodeNo);
00078 total++;
00079 }
00080 }
00081 return sum*(1.0/total);
00082 }
00083
00084 int findValid(int faceNo,int idx) const {
00085 while (getNode(faceNo,idx)==-1) {
00086 idx++;
00087 if (idx>=nPer) idx=0;
00088 }
00089 return idx;
00090 }
00091
00092 double calculateFaceLenSq(int faceNo,double minLenSq) const
00093 {
00094 for (int i=0;i<nPer;i++) {
00095 int l=findValid(faceNo,i);
00096 int r=findValid(faceNo,(l+1)%nPer);
00097 double curLenSq=getNodeLoc(getNode(faceNo,l)).distSqr(getNodeLoc(getNode(faceNo,r)));
00098 if (curLenSq<minLenSq) minLenSq=curLenSq;
00099 }
00100 return minLenSq;
00101 }
00102
00103 public:
00104 faceSet(int nFaces_,int nPer_,
00105 const int *idx_,int idxBase_,
00106 const CkVector3d *loc_)
00107 :nFaces(nFaces_),nPer(nPer_),idx(idx_),idxBase(idxBase_),loc(loc_)
00108 {
00109
00110 faceCen=new CkVector3d[nFaces];
00111 for (int f=0;f<nFaces;f++) faceCen[f]=calcFaceLoc(f);
00112 }
00113 ~faceSet() {delete[] faceCen;}
00114
00115
00116 double getMinEdgeLength(void) const {
00117 double minLenSq=1.0e30;
00118 for (int f=0;f<nFaces;f++) {
00119 minLenSq=calculateFaceLenSq(f,minLenSq);
00120 }
00121 return sqrt(minLenSq);
00122 }
00123
00124 int getFaces(void) const {return nFaces;}
00125 int getNodesPer(void) const {return nPer;}
00126
00127 inline int getNode(int faceNo,int nodeNo) const {
00128 return idx[faceNo*nPer+nodeNo]-idxBase;
00129 }
00130 inline const CkVector3d &getNodeLoc(int nodeNo) const {return loc[nodeNo];}
00131
00132
00133 inline CkVector3d getFaceLoc(int faceNo) const { return faceCen[faceNo];}
00134
00135
00136
00137 int getLocFace(const CkVector3d &loc,double minTol) const {
00138 double minTolSq=minTol*minTol;
00139 int min=-1;
00140 for (int f=0;f<nFaces;f++) {
00141 double distSq=loc.distSqr(faceCen[f]);
00142 if (distSq<minTolSq) {
00143
00144 if (min!=-1)
00145 CkAbort("FEM_Linear_Periodicity> Several 'closest' faces found!");
00146 min=f;
00147 }
00148 }
00149 if (min==-1)
00150 CkAbort("FEM_Linear_Periodicity> No matching face found!");
00151 return min;
00152 }
00153
00154
00155 int getLocNode(int faceNo,const CkVector3d &loc,double minTol) const {
00156 double minTolSq=minTol*minTol;
00157 int min=-1;
00158 for (int n=0;n<nPer;n++) {
00159 double distSq=loc.distSqr(getNodeLoc(getNode(faceNo,n)));
00160 if (distSq<minTolSq) {
00161
00162 if (min!=-1)
00163 CkAbort("FEM_Linear_Periodicity> Several 'closest' nodes found!");
00164 min=n;
00165 }
00166 }
00167 if (min==-1)
00168 CkAbort("FEM_Linear_Periodicity> No matching node found!");
00169 return getNode(faceNo,min);
00170 }
00171 };
00172
00173 class matchingDest {
00174 public:
00175 virtual void facesIdentical(int fa,int fb) =0;
00176 virtual void nodesIdentical(int na,int nb) =0;
00177 };
00178
00179 class linearOffsetMatcher {
00180 faceSet a;
00181 faceSet b;
00182 int nNodes;
00183 int nFaces;
00184 double minTol;
00185 CkVector3d a2b_del;
00186
00187 CkVector3d a2b(const CkVector3d &a_pos) const {
00188 return a_pos+a2b_del;
00189 }
00190 public:
00191 linearOffsetMatcher(
00192 int nFaces_,int nPer,const int *facesA,const int *facesB,int idxBase,
00193 int nNodes_,const CkVector3d *nodeLocs);
00194 void match(matchingDest &dest);
00195 CkVector3d getA2B(void) const {return a2b_del;}
00196 };
00197
00198 linearOffsetMatcher::linearOffsetMatcher(
00199 int nFaces_,int nPer,const int *facesA,const int *facesB,int idxBase,
00200 int nNodes_,const CkVector3d *nodeLocs):
00201 a(nFaces_,nPer,facesA,idxBase,nodeLocs),
00202 b(nFaces_,nPer,facesB,idxBase,nodeLocs),
00203 nNodes(nNodes_),nFaces(nFaces_)
00204 {
00205
00206 CkVector3d a_sum(0.0), b_sum(0.0);
00207 for (int f=0;f<nFaces;f++) {
00208 a_sum+=a.getFaceLoc(f);
00209 b_sum+=b.getFaceLoc(f);
00210 }
00211 a2b_del=(b_sum-a_sum)*(1.0/nFaces);
00212
00213
00214 minTol=a.getMinEdgeLength()*0.001;
00215 }
00216
00217 void linearOffsetMatcher::match(matchingDest &dest) {
00218 int nPer=a.getNodesPer();
00219
00220
00221
00222 CkPrintf("FEM_Add_Linear_Periodic> Performing O(n^2) face matching loop (n=%d), (tol=%.1g)\n",nFaces,minTol);
00223 for (int fa=0;fa<nFaces;fa++) {
00224 CkVector3d bfaceCen=a2b(a.getFaceLoc(fa));
00225 int fb=b.getLocFace(bfaceCen,minTol);
00226 dest.facesIdentical(fa,fb);
00227 for (int i=0;i<nPer;i++) {
00228 int na=a.getNode(fa,i);
00229 if (na!=-1) {
00230 int nb=b.getLocNode(fb,a2b(a.getNodeLoc(na)),minTol);
00231 dest.nodesIdentical(na,nb);
00232 }
00233 }
00234 }
00235 CkPrintf("FEM_Add_Linear_Periodic> Faces matched\n");
00236 }
00237
00238 class unionFindDest : public matchingDest {
00239 unionFind &dest;
00240 public:
00241 unionFindDest(unionFind &dest_) :dest(dest_) {}
00242 virtual void facesIdentical(int fa,int fb) { }
00243 virtual void nodesIdentical(int na,int nb) {
00244 dest.combine(na,nb);
00245 }
00246 };
00247
00248
00249
00250
00251
00252
00253 class FEM_Initial_Symmetries
00254 {
00255 int nNodes;
00256 public:
00257 ArrayPtrT<FEM_Symmetries_t> nodeSymmetries;
00258 intArrayPtr nodeCanon;
00259 unionFind *find;
00260
00261 FEM_Sym_List symList;
00262
00263
00264 void alloc(int nNodes_) {
00265 nNodes=nNodes_;
00266 if (nodeSymmetries==NULL) {
00267 nodeSymmetries=new FEM_Symmetries_t[nNodes];
00268 for (int i=0;i<nNodes;i++)
00269 nodeSymmetries[i]=(FEM_Symmetries_t)0;
00270 }
00271 }
00272 int nodeCheck(int n) {
00273 if (n<-1 || n>=nNodes) return -2;
00274 return n;
00275 }
00276
00277 FEM_Initial_Symmetries() {
00278 find=NULL;
00279 }
00280 ~FEM_Initial_Symmetries() {
00281 delete find;
00282 }
00283 };
00284
00285 void FEM_Partition::setSymmetries(int nNodes_,int *new_can,const int *sym_src)
00286 {
00287 if (sym!=NULL) CkAbort("Cannot call FEM_Set_Symmetries after adding other symmetries!");
00288 sym=new FEM_Initial_Symmetries;
00289 sym->nodeCanon=new_can;
00290 sym->alloc(nNodes_);
00291 for (int i=0;i<nNodes_;i++)
00292 sym->nodeSymmetries[i]=(FEM_Symmetries_t)sym_src[i];
00293 }
00294 void FEM_Partition::addLinearPeriodic(int nFaces,int nPer,
00295 const int *facesA,const int *facesB,int idxBase,
00296 int nNodes,const CkVector3d *nodeLocs)
00297 {
00298 if (sym==NULL) sym=new FEM_Initial_Symmetries;
00299 sym->alloc(nNodes);
00300 if (sym->find==NULL) sym->find=new unionFind(nNodes);
00301
00302
00303 linearOffsetMatcher matcher(nFaces,nPer,facesA,facesB,idxBase,nNodes,nodeLocs);
00304 CkVector3d a2b=matcher.getA2B();
00305
00306
00307 unionFindDest dest(*(sym->find));
00308 matcher.match(dest);
00309
00310
00311 FEM_Symmetries_t sa=sym->symList.add(new FEM_Sym_Linear(-a2b));
00312 FEM_Symmetries_t sb=sym->symList.add(new FEM_Sym_Linear(a2b));
00313 for (int f=0;f<nFaces;f++)
00314 for (int i=0;i<nPer;i++) {
00315 sym->nodeSymmetries[facesA[f*nPer+i]] |= sa;
00316 sym->nodeSymmetries[facesB[f*nPer+i]] |= sb;
00317 }
00318 }
00319
00320 const int *FEM_Partition::getCanon(void) const {
00321 if (sym==NULL) return NULL;
00322 if (sym->nodeCanon==NULL && sym->find!=NULL)
00323 {
00324 sym->find->compress();
00325 sym->nodeCanon=sym->find->detach();
00326 }
00327 return sym->nodeCanon;
00328 }
00329 const FEM_Symmetries_t *FEM_Partition::getSymmetries(void) const {
00330 if (sym==NULL) return NULL;
00331 return sym->nodeSymmetries;
00332 }
00333 const FEM_Sym_List &FEM_Partition::getSymList(void) const {
00334 if (sym==NULL) {
00335 const static FEM_Sym_List emptyList;
00336 return emptyList;
00337 }
00338 else return sym->symList;
00339 }
00340
00341
00342
00343
00344 FEM_Sym_List::FEM_Sym_List() {}
00345 void FEM_Sym_List::operator=(const FEM_Sym_List &src) {
00346 for (int i=0;i<src.sym.size();i++)
00347 sym.push_back((FEM_Sym_Desc *)src.sym[i]->clone());
00348 }
00349 void FEM_Sym_List::pup(PUP::er &p) {
00350 p|sym;
00351 }
00352 FEM_Sym_List::~FEM_Sym_List() {}
00353
00354
00355
00356 FEM_Symmetries_t FEM_Sym_List::add(FEM_Sym_Desc *desc)
00357 {
00358 int nSym=sym.size();
00359 sym.push_back(desc);
00360 return (FEM_Symmetries_t)(1<<nSym);
00361 }
00362
00363
00364 void FEM_Sym_List::applyLoc(CkVector3d *loc,FEM_Symmetries_t symToApply) const
00365 {
00366 int nSym=sym.size();
00367 for (int i=0;i<nSym;i++)
00368 if (symToApply&(1<<i))
00369 *loc=sym[i]->applyLoc(*loc);
00370 }
00371
00372
00373 void FEM_Sym_List::applyVec(CkVector3d *vec,FEM_Symmetries_t symToApply) const
00374 {
00375 int nSym=sym.size();
00376 for (int i=0;i<nSym;i++)
00377 if (symToApply&(1<<i))
00378 *vec=sym[i]->applyVec(*vec);
00379 }
00380
00381 FEM_Sym_Desc::~FEM_Sym_Desc() {}
00382
00383 void FEM_Sym_Linear::pup(PUP::er &p) {
00384 typedef PUP::able PUP_able;
00385 PUP_able::pup(p);
00386 p|shift;
00387 }
00388
00389
00390 CLINKAGE void FEM_Add_linear_periodicity(
00391 int nFaces,int nPer,
00392 const int *facesA,const int *facesB,
00393 int nNodes,const double *nodeLocs
00394 )
00395 {
00396 FEMAPI("FEM_Add_Linear_Periodicity");
00397 FEM_curPartition().addLinearPeriodic(nFaces,nPer,
00398 facesA,facesB,0,nNodes,(const CkVector3d *)nodeLocs);
00399 }
00400 FLINKAGE void FTN_NAME(FEM_ADD_LINEAR_PERIODICITY,fem_add_linear_periodicity)(
00401 int *nFaces,int *nPer,
00402 const int *facesA,const int *facesB,
00403 int *nNodes,const double *nodeLocs
00404 )
00405 {
00406 FEMAPI("fem_add_linear_periodicity");
00407 FEM_curPartition().addLinearPeriodic(*nFaces,*nPer,
00408 facesA,facesB,1,*nNodes,(const CkVector3d *)nodeLocs);
00409 }
00410
00411 CLINKAGE void FEM_Sym_coordinates(int elType,double *d_locs)
00412 {
00413 const char *caller="FEM_Sym_coordinates"; FEMAPI(caller);
00414
00415 const FEM_Mesh *m=FEM_chunk::get(caller)->getMesh(caller);
00416 const FEM_Entity &real_c=m->getCount(elType);
00417 const FEM_Entity &c=real_c.getGhost()[0];
00418 const FEM_Symmetries_t *sym=c.getSymmetries();
00419 if (sym==NULL) return;
00420 CkVector3d *locs=real_c.size()+(CkVector3d *)d_locs;
00421 int n=c.size();
00422 const FEM_Sym_List &sl=m->getSymList();
00423 for (int i=0;i<n;i++)
00424 if (sym[i]!=(FEM_Symmetries_t)0)
00425 sl.applyLoc(&locs[i],sym[i]);
00426 }
00427 FLINKAGE void FTN_NAME(FEM_SYM_COORDINATES,fem_sym_coordinates)
00428 (int *elType,double *locs)
00429 {
00430 FEM_Sym_coordinates(zeroToMinusOne(*elType),locs);
00431 }
00432
00433
00434
00435
00436 CLINKAGE void FEM_Set_sym_nodes(const int *canon,const int *sym)
00437 {
00438 const char *caller="FEM_Set_sym_nodes"; FEMAPI(caller);
00439 int n=FEM_chunk::get(caller)->setMesh(caller)->node.size();
00440 FEM_curPartition().setSymmetries(n,CkCopyArray(canon,n,0),sym);
00441 }
00442 FLINKAGE void FTN_NAME(FEM_SET_SYM_NODES,fem_set_sym_nodes)
00443 (const int *canon,const int *sym)
00444 {
00445 const char *caller="FEM_Set_sym_nodes"; FEMAPI(caller);
00446 int n=FEM_chunk::get(caller)->setMesh(caller)->node.size();
00447 FEM_curPartition().setSymmetries(n,CkCopyArray(canon,n,1),sym);
00448 }
00449
00450
00451 #if STANDALONE
00452
00453
00454 const int nFaces=10000;
00455 const int nPer=4;
00456 const int aPoints=10000;
00457 const int bPoints=aPoints;
00458 const int a2bPoints=aPoints;
00459
00460
00461 static CrnStream rs;
00462
00463 void print(const char *str) {
00464 printf("%s",str);
00465 }
00466 void print(const CkVector3d &src,int digits=3) {
00467 printf("(%.*f,%.*f,%.*f) ",digits,src.x,digits,src.y,digits,src.z);
00468 FEM_Print("");
00469 }
00470
00471
00472 double randVal(double max) {
00473 return max*CrnDouble(&rs);
00474 }
00475 CkVector3d randVec(const CkVector3d &scale) {
00476 return CkVector3d(randVal(scale.x),randVal(scale.y),randVal(scale.z));
00477 }
00478
00479 int randNo(int max) {
00480 return (int)(randVal(max-0.000001));
00481 }
00482
00483 class verbosematchingDest : public matchingDest {
00484 public:
00485 virtual void facesIdentical(int fa,int fb) {
00486 if (fa!=fb)
00487 CkPrintf("--------- ERROR! Face %d %d\n",fa,fb);
00488 }
00489 virtual void nodesIdentical(int na,int nb) {
00490 if (na+a2bPoints!=nb)
00491 CkPrintf("--------- ERROR! Node %d %d\n",na,nb);
00492 }
00493 };
00494
00495
00496 void makeFaces(int *facesA,int *facesB) {
00497 for (int f=0;f<nFaces;f++) {
00498 int *fa=&facesA[f*nPer];
00499 int *fb=&facesB[f*nPer];
00500
00501 bool doSkip=true;
00502 for (int i=0;i<nPer;i++) {
00503 int na=randNo(aPoints);
00504 bool repeat=true;
00505 do {
00506 repeat=false;
00507 for (int j=0;j<i;j++)
00508 if (na==fa[j]) {
00509 na=randNo(aPoints);
00510 repeat=true;
00511 break;
00512 }
00513 } while (repeat);
00514 if (doSkip && randVal(1.0)<0.1) {
00515 fa[i]=fb[i]=-1;
00516 doSkip=false;
00517 }
00518 else {
00519 fa[i]=na;
00520 fb[i]=na+a2bPoints;
00521 }
00522 }
00523 }
00524 }
00525
00526 void testUnion(int n,int *parent) {
00527 for (int i=0;i<n;i++) {
00528 if (parent[i]!=i)
00529 {
00530 if ((parent[i]+a2bPoints!=i) && (i+a2bPoints!=parent[i]))
00531 CkAbort("Union/Find mismatch!");
00532 }
00533 }
00534 delete[] parent;
00535 }
00536
00537 int main(int argc,char *argv[])
00538 {
00539 CkPrintf("init called\n");
00540 CrnInitStream(&rs,0,0);
00541 int facesA[nFaces*nPer],facesB[nFaces*nPer];
00542 const int nPoints=aPoints+bPoints;
00543 CkVector3d pts[nPoints];
00544 FEM_Print("Fabricating points:");
00545 CkVector3d a2bLocs(randVec(CkVector3d(10.0,90.0,50.0)));
00546 print("true offset vector "); print(a2bLocs,15);
00547 int i;
00548
00549 for (i=0;i<aPoints;i++) {
00550 pts[i]=randVec(CkVector3d(5.0,5.0,5.0));
00551 pts[i+a2bPoints]=pts[i]+a2bLocs;
00552 }
00553 makeFaces(facesA,facesB);
00554
00555
00556
00557 unionFind uf(nPoints); unionFindDest dest(uf);
00558 FEM_Print("Finding offset");
00559 linearOffsetMatcher matcher(nFaces,nPer,facesA,facesB,0, nPoints,pts);
00560 FEM_Print("Beginning match");
00561 matcher.match(dest);
00562 FEM_Print("Compressing paths");
00563 uf.compress();
00564 FEM_Print("Testing union");
00565 testUnion(nPoints,uf.detach());
00566 FEM_Print("Done");
00567 }
00568
00569 #endif