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