00001 
00002 
00003 
00004 
00005 
00006 
00011 #include "ParFUM.h"
00012 #include "ParFUM_internals.h"
00013 
00014 
00015 #define MINAREA 1.0e-18
00016 #define MAXAREA 1.0e12
00017 
00018 #define GRADATION 1.2
00019 
00020 
00021 CtvDeclare(FEM_Adapt_Algs *, _adaptAlgs);
00022 
00023 FEM_Adapt_Algs::FEM_Adapt_Algs(FEM_Mesh *m, femMeshModify *fm) 
00024 { 
00025   theMesh = m; 
00026   theMod = fm; 
00027   
00028   theAdaptor = theMod->fmAdaptL;
00029 }
00030 FEM_Adapt_Algs::FEM_Adapt_Algs(femMeshModify *fm) {
00031   theMesh = NULL;
00032   theMod = fm;
00033   theAdaptor = theMod->fmAdaptL;
00034 }
00035 
00036 FEM_Adapt_Algs::~FEM_Adapt_Algs() {
00037 }
00038 
00039 
00040 
00047 void FEM_Adapt_Algs::FEM_Refine(int qm, int method, double factor, 
00048                 double *sizes)
00049 {
00050   SetMeshSize(method, factor, sizes);
00051   GradateMesh(GRADATION);
00052   (void)Refine(qm, method, factor, sizes);
00053 }
00054 
00057 int FEM_Adapt_Algs::Refine(int qm, int method, double factor, double *sizes)
00058 {
00059   
00060   int elId, mods=0, iter_mods=1;
00061   int elemWidth = theMesh->elem[0].getConn().width();
00062   refineElements = refineStack = NULL;
00063   refineTop = refineHeapSize = 0;
00064   int elemConn[3];
00065   int count = 0;
00066   while (iter_mods != 0 && count<20) {
00067     count++;
00068     iter_mods=0;
00069     numNodes = theMesh->node.size();
00070     numElements = theMesh->elem[0].size();
00071     
00072     if (refineStack) delete [] refineStack;
00073     refineStack = new elemHeap[numElements];
00074     if (refineElements) delete [] refineElements;
00075     refineElements = new elemHeap[numElements+1];
00076     for (int i=0; i<numElements; i++) { 
00077       if (theMesh->elem[0].is_valid(i)) {
00078     
00079     double tmpLen, avgEdgeLength=0.0, maxEdgeLength = 0.0;
00080     theMesh->e2n_getAll(i, elemConn);
00081     bool notclear = false;
00082     for(int j=0; j<elemWidth; j++) {
00083       int nd = elemConn[j];
00084       if(nd>=0) notclear = theMod->fmLockN[nd].haslocks();
00085       
00086       
00087     }
00088     if(notclear) continue;
00089     for (int j=0; j<elemWidth-1; j++) {
00090       for (int k=j+1; k<elemWidth; k++) {
00091         tmpLen = length(elemConn[j], elemConn[k]);
00092         if(tmpLen < -1.0) {notclear = true;}
00093         avgEdgeLength += tmpLen;
00094         if (tmpLen > maxEdgeLength) maxEdgeLength = tmpLen;
00095       }
00096     }
00097     if(notclear) continue;
00098     avgEdgeLength /= 3.0;
00099     double qFactor=getAreaQuality(i);
00100     if (theMesh->elem[0].getMeshSizing(i) <= 0.0) 
00101       CkPrintf("WARNING: mesh element %d has no sizing!\n", i);
00102     if ((theMesh->elem[0].getMeshSizing(i) > 0.0) &&
00103         (avgEdgeLength > (theMesh->elem[0].getMeshSizing(i)*REFINE_TOL))){
00104         
00105       Insert(i, qFactor*(1.0/maxEdgeLength), 0);
00106     }
00107       }
00108     }
00109     while (refineHeapSize>0 || refineTop > 0) { 
00110       int n1, n2;
00111       if (refineTop>0) {
00112     refineTop--;
00113     elId=refineStack[refineTop].elID;
00114       }
00115       else  elId=Delete_Min(0);
00116       if ((elId != -1) && (theMesh->elem[0].is_valid(elId))) {
00117     int n1, n2;
00118     double tmpLen, avgEdgeLength=0.0, maxEdgeLength = 0.0;
00119     int maxEdgeIdx=0;
00120     theMesh->e2n_getAll(elId, elemConn);
00121     bool notclear = false;
00122     for(int j=0; j<elemWidth; j++) {
00123       int nd = elemConn[j];
00124       if(nd>=0) notclear = theMod->fmLockN[nd].haslocks();
00125       
00126       
00127     }
00128     if(notclear) continue;
00129     for (int j=0; j<elemWidth-1; j++) {
00130       for (int k=j+1; k<elemWidth; k++) {
00131         tmpLen = length(elemConn[j], elemConn[k]);
00132         if(tmpLen < -1.0) {notclear = true;}
00133         avgEdgeLength += tmpLen;
00134         if (tmpLen > maxEdgeLength) { 
00135           maxEdgeLength = tmpLen;
00136           if(k==elemWidth-1) {
00137         maxEdgeIdx = j+1;
00138           }
00139           else maxEdgeIdx = j;
00140           n1 = elemConn[j]; n2 = elemConn[k];
00141         }
00142       }
00143     }
00144     if(notclear) continue;
00145     avgEdgeLength /= 3.0;
00146     
00147     if ((theMesh->elem[0].getMeshSizing(elId) > 0.0) &&
00148         (avgEdgeLength>(theMesh->elem[0].getMeshSizing(elId)*REFINE_TOL))){
00149       
00150       
00151       bool flag = flipOrBisect(elId,n1,n2,maxEdgeIdx,maxEdgeLength);
00152       if(flag) {
00153 #ifdef DEBUG_FLIP
00154         if(theAdaptor->edge_flip(n1, n2) > 0)  iter_mods++;
00155 #endif
00156       }
00157       else {
00158         if(theAdaptor->edge_bisect(n1, n2) > 0)  iter_mods++;
00159       }
00160     }
00161       }
00162       CthYield(); 
00163     }
00164     mods += iter_mods;
00165 #ifdef ADAPT_VERBOSE
00166     CkPrintf("[%d]ParFUM_Refine: %d modifications in last pass.\n",theMod->idx,iter_mods);
00167 #endif
00168 #ifdef DEBUG_QUALITY
00169     tests(false);
00170 #endif
00171   }
00172 #ifdef ADAPT_VERBOSE
00173   CkPrintf("[%d]ParFUM_Refine: %d total modifications.\n",theMod->idx,mods);
00174 #endif
00175   delete[] refineStack;
00176   delete[] refineElements;
00177   return mods;
00178 }
00179 
00186 void FEM_Adapt_Algs::FEM_Coarsen(int qm, int method, double factor, 
00187                  double *sizes)
00188 {
00189   SetMeshSize(method, factor, sizes);
00190   GradateMesh(GRADATION);
00191   (void)Coarsen(qm, method, factor, sizes);
00192 }
00193 
00196 int FEM_Adapt_Algs::Coarsen(int qm, int method, double factor, double *sizes)
00197 {
00198   
00199   int elId, mods=0, iter_mods=1, pass=0;
00200   int elemWidth = theMesh->elem[0].getConn().width();
00201   double qFactor;
00202   coarsenElements = NULL;
00203   coarsenHeapSize = 0;
00204   int elemConn[3];
00205   while (iter_mods != 0) {
00206     iter_mods=0;
00207     pass++;
00208     numNodes = theMesh->node.size();
00209     numElements = theMesh->elem[0].size();
00210     
00211     if (coarsenElements) delete [] coarsenElements;
00212     coarsenElements = new elemHeap[numElements+1];
00213     coarsenElements[0].len=-2.0;
00214     coarsenElements[0].elID=-1;
00215     for (int i=0; i<numElements; i++) { 
00216       if (theMesh->elem[0].is_valid(i)) {
00217     
00218     theMesh->e2n_getAll(i, elemConn);
00219     bool notclear = false;
00220     for(int j=0; j<elemWidth; j++) {
00221       int nd = elemConn[j];
00222       if(nd>=0) notclear = theMod->fmLockN[nd].haslocks();
00223       
00224       
00225     }
00226     if(notclear) continue;
00227     double tmpLen, avgEdgeLength=0.0, 
00228       minEdgeLength = length(elemConn[0], elemConn[1]);
00229     for (int j=0; j<elemWidth-1; j++) {
00230       for (int k=j+1; k<elemWidth; k++) {
00231         tmpLen = length(elemConn[j], elemConn[k]);
00232         if(tmpLen < -1.0) {notclear = true;}
00233         avgEdgeLength += tmpLen;
00234         if (tmpLen < minEdgeLength) minEdgeLength = tmpLen;
00235       }
00236     }
00237     if(notclear) continue;
00238     avgEdgeLength /= 3.0;
00239     qFactor=getAreaQuality(i);
00240     if (((theMesh->elem[0].getMeshSizing(i) > 0.0) &&
00241          (avgEdgeLength < (theMesh->elem[0].getMeshSizing(i)*COARSEN_TOL)))
00242          || (qFactor < QUALITY_MIN)) {
00243         
00244       
00245       Insert(i, qFactor*minEdgeLength, 1);
00246     }
00247       }
00248     }
00249     while (coarsenHeapSize>0) { 
00250       elId=Delete_Min(1);
00251       if ((elId != -1) && (theMesh->elem[0].is_valid(elId))) {
00252     theMesh->e2n_getAll(elId, elemConn);
00253     bool notclear = false;
00254     for(int j=0; j<elemWidth; j++) {
00255       int nd = elemConn[j];
00256       if(nd>=0) notclear = theMod->fmLockN[nd].haslocks();
00257       
00258       
00259     }
00260     if(notclear) continue;
00261     int n1=elemConn[0], n2=elemConn[1];
00262     double tmpLen, avgEdgeLength=0.0, 
00263       minEdgeLength = length(n1, n2);
00264     for (int j=0; j<elemWidth-1; j++) {
00265       for (int k=j+1; k<elemWidth; k++) {
00266         tmpLen = length(elemConn[j], elemConn[k]);
00267         if(tmpLen < -1.0) {notclear = true;}
00268         avgEdgeLength += tmpLen;
00269         if (tmpLen < minEdgeLength) {
00270           minEdgeLength = tmpLen;
00271           n1 = elemConn[j]; n2 = elemConn[k];
00272         }
00273       }
00274     }
00275     if(notclear) continue;
00276     CkAssert(n1!=-1 && n2!=-1);
00277     avgEdgeLength /= 3.0;
00278     qFactor=getAreaQuality(elId);
00279     
00280     if (((theMesh->elem[0].getMeshSizing(elId) > 0.0) &&
00281          (avgEdgeLength < (theMesh->elem[0].getMeshSizing(elId)*COARSEN_TOL)))
00282           || (qFactor < QUALITY_MIN)) {
00283       
00284 
00285       int eNbr = theMesh->e2e_getNbr(elId, theMesh->e2n_getIndex(elId,n1)+
00286                      theMesh->e2n_getIndex(elId,n2)-1, 0);
00287       
00288       if ((eNbr >= 0) && (theMesh->elem[0].is_valid(eNbr))) {
00289         theMesh->e2n_getAll(eNbr, elemConn);
00290         avgEdgeLength=0.0;
00291         for (int j=0; j<elemWidth-1; j++) {
00292           for (int k=j+1; k<elemWidth; k++) {
00293         avgEdgeLength += length(elemConn[j], elemConn[k]);
00294           }
00295         }
00296         avgEdgeLength /= 3.0;
00297         qFactor=getAreaQuality(eNbr);
00298         if (((theMesh->elem[0].getMeshSizing(eNbr) > 0.0) &&
00299          (avgEdgeLength < (theMesh->elem[0].getMeshSizing(eNbr))))
00300         || (qFactor < QUALITY_MIN)) {
00301           
00302           if (theAdaptor->edge_contraction(n1, n2) > 0)  iter_mods++;
00303         }
00304       }
00305       else {
00306         
00307         if (theAdaptor->edge_contraction(n1, n2) > 0)  iter_mods++;
00308       }
00309     }
00310       }
00311       CthYield(); 
00312     }
00313     mods += iter_mods;
00314 #ifdef ADAPT_VERBOSE
00315     CkPrintf("[%d]ParFUM_Coarsen: %d modifications in pass %d.\n",theMod->idx,iter_mods,pass);
00316 #endif
00317 #ifdef DEBUG_QUALITY
00318     tests(false);
00319 #endif
00320   }
00321 #ifdef ADAPT_VERBOSE
00322   CkPrintf("[%d]ParFUM_Coarsen: %d total modifications over %d passes.\n",theMod->idx,mods,pass);
00323 #endif
00324   delete[] coarsenElements;
00325   return mods;
00326 }
00327 
00331 void FEM_Adapt_Algs::FEM_AdaptMesh(int qm, int method, double factor, 
00332                    double *sizes)
00333 {
00334   MPI_Comm comm=(MPI_Comm)FEM_chunk::get("FEM_Update_mesh")->defaultComm;
00335   MPI_Barrier(comm);
00336 #ifdef ADAPT_VERBOSE
00337   CkPrintf("[%d]BEGIN: FEM_AdaptMesh...\n",theMod->idx);
00338 #endif
00339 #ifdef DEBUG_QUALITY
00340   tests(true);
00341 #endif
00342   SetMeshSize(method, factor, sizes);
00343   MPI_Barrier(comm);
00344   GradateMesh(GRADATION);
00345   MPI_Barrier(comm);
00346   (void)Refine(qm, method, factor, sizes);
00347   MPI_Barrier(comm);
00348   GradateMesh(GRADATION);
00349   MPI_Barrier(comm);
00350   (void)Coarsen(qm, method, factor, sizes);
00351 #ifdef DEBUG_QUALITY
00352   MPI_Barrier(comm);
00353 #endif
00354   FEM_Repair(qm);
00355   MPI_Barrier(comm);
00356 #ifdef DEBUG_QUALITY
00357   tests(true);
00358   MPI_Barrier(comm);
00359 #endif
00360 #ifdef ADAPT_VERBOSE
00361   CkPrintf("[%d]...END: FEM_AdaptMesh.\n",theMod->idx);
00362 #endif
00363 }
00364 
00367 void FEM_Adapt_Algs::FEM_Smooth(int qm, int method)
00368 {
00369   CkPrintf("WARNING: ParFUM_Smooth: Not yet implemented.\n");
00370 }
00371 
00382 void  FEM_Adapt_Algs::FEM_mesh_smooth(FEM_Mesh *meshP, int *nodes, int nNodes, int attrNo) {
00383   vector2d newPos, *coords, *ghostCoords;
00384   int idx, nNod, nGn, gIdxN, *boundVals, nodesInChunk, mesh;
00385   int *adjnodes;
00386 
00387   mesh=FEM_Mesh_default_read();
00388   nodesInChunk = FEM_Mesh_get_length(mesh,FEM_NODE);
00389   nGn = FEM_Mesh_get_length(mesh, FEM_GHOST + FEM_NODE);
00390   
00391   boundVals = new int[nodesInChunk];
00392   coords = new vector2d[nodesInChunk+nGn];
00393 
00394   FEM_Mesh_data(mesh, FEM_NODE, FEM_BOUNDARY, (int*) boundVals, 0, nodesInChunk, FEM_INT, 1);    
00395 
00396   FEM_Mesh_data(mesh, FEM_NODE, attrNo, (double*)coords, 0, nodesInChunk, FEM_DOUBLE, 2);
00397 
00398   IDXL_Layout_t coord_layout = IDXL_Layout_create(IDXL_DOUBLE, 2);
00399   FEM_Update_ghost_field(coord_layout,-1, coords); 
00400   ghostCoords = &(coords[nodesInChunk]);
00401   for (int i=0; i<nNodes; i++)
00402   {
00403     if (nodes==NULL) idx=i;
00404     else idx=nodes[i];
00405     newPos.x=0;
00406     newPos.y=0;
00407     CkAssert(idx<nodesInChunk);  
00408     if (FEM_is_valid(mesh, FEM_NODE, idx) && boundVals[idx]==0) 
00409     {
00410       meshP->n2n_getAll(idx, adjnodes, nNod);
00411       for (int j=0; j<nNod; j++) { 
00412     if (adjnodes[j]<-1) {
00413       gIdxN = FEM_From_ghost_index(adjnodes[j]);
00414       newPos.x += ghostCoords[gIdxN].x;
00415       newPos.y += ghostCoords[gIdxN].y;
00416     }
00417     else {
00418       newPos.x += coords[adjnodes[j]].x;
00419       newPos.y += coords[adjnodes[j]].y;
00420     }     
00421       }
00422       newPos.x/=nNod;
00423       newPos.y/=nNod;
00424       FEM_set_entity_coord2(mesh, FEM_NODE, idx, newPos.x, newPos.y);
00425       delete [] adjnodes;
00426     }
00427   }
00428 
00429   delete [] coords;
00430   delete [] boundVals;
00431 }
00432 
00436 void FEM_Adapt_Algs::FEM_Repair(int qm)
00437 {
00438   double avgQual = 0.0, minQual = getAreaQuality(0);
00439   int numBadElems = 0;
00440   int elemConn[3];
00441 #ifdef ADAPT_VERBOSE
00442   CkPrintf("[%d]WARNING: ParFUM_Repair: Under construction.\n",theMod->idx);
00443   numElements = theMesh->elem[0].size();
00444   for (int i=0; i<numElements; i++) { 
00445     if (theMesh->elem[0].is_valid(i)) {
00446       double qFactor=getAreaQuality(i);
00447       avgQual += qFactor;
00448       if (qFactor <  QUALITY_MIN) {
00449     numBadElems++;
00450     if (qFactor < minQual) minQual = qFactor;
00451       }
00452     }
00453   }
00454   avgQual /= numElements;
00455   CkPrintf("BEFORE FEM_Repair: Average Element Quality = %2.6f, Min = %2.6f (1.0 is perfect)\n", avgQual, minQual);
00456   
00457 #endif
00458 
00459   int elemWidth = theMesh->elem[0].getConn().width();
00460   int changes=1, totalChanges=0;
00461   int count=0;
00462   while (changes!=0 && count<4) {
00463     count++;
00464     changes = 0;
00465     numElements = theMesh->elem[0].size();
00466     for (int i=0; i<numElements; i++) { 
00467       if (theMesh->elem[0].is_valid(i)) {
00468     double qFactor=getAreaQuality(i);
00469     if (qFactor <  0.75*QUALITY_MIN) {
00470       int elId = i;
00471       theMesh->e2n_getAll(elId, elemConn);
00472       bool notclear = false;
00473       for(int j=0; j<elemWidth; j++) {
00474         int nd = elemConn[j];
00475         if(nd>=0) notclear = theMod->fmLockN[nd].haslocks();
00476         
00477         
00478       }
00479       if(notclear) continue;
00480       int n1=elemConn[0], n2=elemConn[1];
00481       
00482       
00483       double len1 = length(elemConn[0],elemConn[1]);
00484       double len2 = length(elemConn[1],elemConn[2]);
00485       double len3 = length(elemConn[2],elemConn[0]);
00486       if(len1<-1.0 || len2<-1.0 || len3<-1.0) continue;
00487       double avglen=(len1+len2+len3)/3.0;
00488       int maxn1=0, maxn2=1;
00489       int minn1=0, minn2=1;
00490       double maxlen=len1;
00491       int maxed=0;
00492       if(len2>maxlen) {
00493         maxlen = len2;
00494         maxn1 = 1;
00495         maxn2 = 2;
00496         maxed = 1;
00497       }
00498       if(len3>maxlen) {
00499         maxlen = len3;
00500         maxn1 = 2;
00501         maxn2 = 0;
00502         maxed = 2;
00503       }
00504       double minlen = len1;
00505       if(len2<minlen) {
00506         minlen = len2;
00507         minn1 = 1;
00508         minn2 = 2;
00509       }
00510       if(len3<minlen) {
00511         minlen = len3;
00512         minn1 = 2;
00513         minn2 = 0;
00514       }
00515       double otherlen = 3*avglen - maxlen - minlen;
00516       if (maxlen > 0.95*(minlen+otherlen)) { 
00517         
00518         
00519         
00520         int nbrEl = theMesh->e2e_getNbr(i,maxed);
00521         double len4=0.0, len5=0.0;
00522         if(nbrEl!=-1) {
00523           int con1[3];
00524           theMesh->e2n_getAll(nbrEl,con1);
00525           int nbrnode=-1;
00526           for(int j=0; j<3; j++) {
00527         if(con1[j]!=elemConn[maxn1] && con1[j]!=elemConn[maxn2]) {
00528           nbrnode = con1[j];
00529           break;
00530         }
00531           }
00532           len4 = length(elemConn[maxn1],nbrnode);
00533           len5 = length(elemConn[maxn2],nbrnode);
00534         }
00535         int success = -1;
00536         if(len4>maxlen || len5>maxlen) {
00537 #ifdef DEBUG_FLIP
00538           success = theAdaptor->edge_flip(elemConn[maxn1], elemConn[maxn2]);
00539 #endif
00540         }
00541         else {
00542           success = theAdaptor->edge_bisect(elemConn[maxn1], elemConn[maxn2]);
00543         }
00544         if (success >= 0) {
00545           
00546           changes++;
00547         }
00548       }
00549       else if (minlen < 0.10*(maxlen+otherlen)) { 
00550         int success = theAdaptor->edge_contraction(elemConn[minn1], elemConn[minn2]);
00551         if (success >= 0) { 
00552           
00553           changes++;
00554         }
00555       }
00556       else {
00557         
00558       }
00559     }
00560       }
00561     }
00562     totalChanges += changes;
00563   }
00564 
00565 #ifdef ADAPT_VERBOSE
00566   numElements = theMesh->elem[0].size();
00567   numBadElems = 0;
00568   avgQual = 0.0;
00569   minQual = getAreaQuality(0);
00570   for (int i=0; i<numElements; i++) { 
00571     if (theMesh->elem[0].is_valid(i)) {
00572       double qFactor=getAreaQuality(i);
00573       avgQual += qFactor;
00574       if (qFactor <  QUALITY_MIN) {
00575     numBadElems++;
00576     if (qFactor < minQual) minQual = qFactor;
00577       }
00578     }
00579   }
00580   avgQual /= numElements;
00581   CkPrintf("[%d]AFTER FEM_Repair: Average Element Quality = %2.6f, Min = %2.6f (1.0 is perfect) No. of repairs %d\n",theMod->idx,avgQual, minQual,totalChanges);
00582 #ifdef DEBUG_QUALITY
00583     tests(false);
00584 #endif
00585   
00586 #endif
00587 }
00588 
00594 void FEM_Adapt_Algs::FEM_Remesh(int qm, int method, double factor, 
00595                 double *sizes)
00596 {
00597   CkPrintf("WARNING: ParFUM_Remesh: Under construction.\n");
00598 }
00599 
00600 
00601 
00604 void FEM_Adapt_Algs::SetReferenceMesh()
00605 {
00606   
00607   double avgLength = 0.0;
00608   int width = theMesh->elem[0].getConn().width();
00609   int numElements = theMesh->elem[0].size();
00610   int elemConn[3];
00611   
00612   for (int i=0; i<numElements; ++i, avgLength=0) {
00613     if(theMesh->elem[0].is_valid(i)) {
00614       theMesh->e2n_getAll(i, elemConn);
00615       for (int j=0; j<width-1; ++j) {
00616     avgLength += length(elemConn[j], elemConn[j+1]);
00617       }
00618       avgLength += length(elemConn[0], elemConn[width-1]);
00619       avgLength /= width;
00620       theMesh->elem[0].setMeshSizing(i, avgLength);      
00621     }
00622   }
00623 }
00624 
00630 void FEM_Adapt_Algs::GradateMesh(double smoothness)
00631 {
00632     const double beta = smoothness;
00633 
00634     double maxShock, minShock;
00635     int iteration = 0, updates = 0;
00636 
00637     int* adjNodes, *boundNodes;
00638     int nadjNodes, nnodes;
00639     int meshNum = FEM_Mesh_default_read();
00640     
00641       
00642     
00643 
00644     nnodes = theMesh->node.size();
00645     boundNodes = new int[nnodes];
00646     FEM_Mesh_data(meshNum, FEM_NODE, FEM_BOUNDARY, 
00647             boundNodes, 0, nnodes, FEM_INT, 1);
00648 
00649 
00650     
00651     fflush(NULL);
00652 
00653 #ifndef GRADATION_ITER_LIMIT
00654 #define GRADATION_ITER_LIMIT    10
00655 #endif
00656     
00657     do {
00658         maxShock = 0;
00659         minShock = 1e10;
00660         
00661         for (int node=0; node<nnodes; ++node) {
00662             if (boundNodes[node]!= 0 || !FEM_is_valid(meshNum, FEM_NODE, node))
00663                continue;
00664             
00665             
00666             
00667             theMesh->n2n_getAll(node, adjNodes, nadjNodes);
00668             for (int adjNode=0; adjNode<nadjNodes; ++adjNode) {
00669                 double edgelen = length(node, adjNodes[adjNode]);
00670                 
00671                 
00672                 int e1, e2;
00673                 theMesh->get2ElementsOnEdge(node, adjNodes[adjNode], &e1, &e2);
00674                 if (e1 <= -1 || e2 <= -1) continue; 
00675                 
00676                 double s1, s2;
00677                 s1 = theMesh->elem[0].getMeshSizing(e1);
00678                 s2 = theMesh->elem[0].getMeshSizing(e2);
00679                 if (s1 <= 0 || s2 <= 0) continue;
00680                 
00681                 
00682                 CkAssert(s1 >= 0 && s2 >= 0 && "Bad size");
00683                 
00684                 CkAssert(edgelen == edgelen && "Length inf edge");
00685 
00686                 double ratio = (s1 > s2) ? s1/s2 : s2/s1;
00687                 CkAssert (ratio >= 1.0 && ratio == ratio && "Bad ratio");
00688                 
00689                 
00690                 
00691                 if (ratio > beta) {
00692                     if (s1 > s2) {
00693                         theMesh->elem[0].setMeshSizing(e1, s1 - (s1-s2)/3);
00694                         theMesh->elem[0].setMeshSizing(e2, s2 + (s1-s2)/3);
00695                     } else {
00696                         theMesh->elem[0].setMeshSizing(e2, s2 - (s2-s1)/3);
00697                         theMesh->elem[0].setMeshSizing(e1, s1 + (s2-s1)/3);
00698                     }
00699                     updates++;
00700                 }
00701                 if (ratio > maxShock) maxShock = ratio;
00702                 if (ratio < minShock) minShock = ratio;
00703                 
00704                 
00706                 
00707                 
00708                 
00709                 
00710 
00715                 
00716                 
00717                 
00718                 
00719 
00720                 
00721                 
00722                 
00723                 
00724                 
00725                 
00726                 
00727                 
00728                 
00729                 
00730                 
00731                 
00732                 
00733             }
00734             free(adjNodes);
00735         } 
00736         
00737     
00738         
00739         
00740         
00741         
00742     } while (maxShock > beta && ++iteration < GRADATION_ITER_LIMIT);
00743 
00744     
00745     fflush(NULL);
00746 
00747     delete[] boundNodes;
00748 
00749     return;
00750 }
00751 
00753 void FEM_Adapt_Algs::SetMeshSize(int method, double factor, double *sizes)
00754 {
00755   numNodes = theMesh->node.size();
00756   numElements = theMesh->elem[0].size();
00757   int elemConn[3];
00758 
00759   if (method == 0) { 
00760 
00761     for (int i=0; i<numElements; i++) {
00762       theMesh->elem[0].setMeshSizing(i, factor);
00763     }
00764     
00765   }
00766   else if (method == 1) { 
00767     for (int i=0; i<numElements; i++) {
00768       if (sizes[i] > 0.0) {
00769     theMesh->elem[0].setMeshSizing(i, sizes[i]);
00770       }
00771     }
00772     
00773   }
00774   else if (method == 2) { 
00775     double avgEdgeLength = 0.0;
00776     int width = theMesh->elem[0].getConn().width();
00777     int numEdges=3;
00778     if (dim==3) numEdges=6;
00779     for (int i=0; i<numElements; i++) {
00780       if(theMesh->elem[0].is_valid(i)) {
00781     theMesh->e2n_getAll(i, elemConn);
00782     for (int j=0; j<width-1; j++) {
00783       for (int k=j+1; k<width; k++) {
00784         avgEdgeLength += length(elemConn[j], elemConn[k]);
00785       }
00786     }
00787     avgEdgeLength += length(elemConn[0], elemConn[width-1]);
00788     avgEdgeLength /= (double)numEdges;
00789     theMesh->elem[0].setMeshSizing(i, factor*avgEdgeLength);
00790       }
00791     }
00792     
00793   }
00794   else if (method == 3) { 
00795     for (int i=0; i<numElements; i++) {
00796       if (sizes[i] > 0.0) {
00797     theMesh->elem[0].setMeshSizing(i, sizes[i]*theMesh->elem[0].getMeshSizing(i));
00798       }
00799     }
00800   }
00801   else if (method == 4) { 
00802     for (int i=0; i<numElements; i++) {
00803       theMesh->elem[0].setMeshSizing(i, factor*theMesh->elem[0].getMeshSizing(i));
00804     }
00805   }
00806   else if (method == 5) { 
00807     
00808   }
00809   
00810   
00811   
00812   
00813 }
00814 
00817 void FEM_Adapt_Algs::Insert(int eIdx, double len, int cFlag)
00818 {
00819   int i;
00820   if (cFlag) {
00821     i = ++coarsenHeapSize; 
00822     while ((coarsenElements[i/2].len>=len) && (i != 1)) {
00823       coarsenElements[i].len=coarsenElements[i/2].len;
00824       coarsenElements[i].elID=coarsenElements[i/2].elID;
00825       i/=2;
00826     }
00827     coarsenElements[i].elID=eIdx;
00828     coarsenElements[i].len=len; 
00829   }
00830   else {
00831     i = ++refineHeapSize; 
00832     while ((refineElements[i/2].len>=len) && (i != 1)) {
00833       refineElements[i].len=refineElements[i/2].len;
00834       refineElements[i].elID=refineElements[i/2].elID;
00835       i/=2;
00836     }
00837     refineElements[i].elID=eIdx;
00838     refineElements[i].len=len; 
00839   }
00840 }
00841 
00844 int FEM_Adapt_Algs::Delete_Min(int cflag)
00845 {
00846   int Child, i, Min_ID; 
00847   if (cflag) {
00848     Min_ID=coarsenElements[1].elID;
00849     for (i=1; i*2 <= coarsenHeapSize-1; i=Child) { 
00850       Child = i*2; 
00851       if (Child != coarsenHeapSize)  
00852     if (coarsenElements[Child+1].len < coarsenElements[Child].len)
00853       Child++; 
00854       
00855       if (coarsenElements[coarsenHeapSize].len >= coarsenElements[Child].len) {
00856     coarsenElements[i].elID = coarsenElements[Child].elID;
00857     coarsenElements[i].len = coarsenElements[Child].len;
00858       }
00859       else break; 
00860     }
00861     coarsenElements[i].elID = coarsenElements[coarsenHeapSize].elID;
00862     coarsenElements[i].len = coarsenElements[coarsenHeapSize].len; 
00863     coarsenHeapSize--;
00864     return Min_ID; 
00865   }
00866   else {
00867     Min_ID=refineElements[1].elID;
00868     for (i=1; i*2 <= refineHeapSize-1; i=Child) { 
00869       Child = i*2;       
00870       if (Child !=refineHeapSize)  
00871     if (refineElements[Child+1].len < refineElements[Child].len)
00872       Child++; 
00873       
00874       if (refineElements[refineHeapSize].len >= refineElements[Child].len){  
00875     refineElements[i].elID = refineElements[Child].elID;   
00876     refineElements[i].len = refineElements[Child].len;
00877       }
00878       else break; 
00879     }
00880     refineElements[i].elID = refineElements[refineHeapSize].elID;
00881     refineElements[i].len = refineElements[refineHeapSize].len; 
00882     refineHeapSize--;
00883     return Min_ID; 
00884   }
00885 }
00886 
00887 
00888 
00889 
00899 int FEM_Adapt_Algs::refine_element_leb(int e) {
00900   int fixNode, otherNode, opNode, longEdge, nbr; 
00901   double eLens[3], longEdgeLen = 0.0;
00902   int elemConn[3];
00903 
00904   if(e==-1) {
00905     return -1;
00906   }
00907 
00908   theMesh->e2n_getAll(e, elemConn);
00909   eLens[0] = length(elemConn[0], elemConn[1]);
00910   eLens[1] = length(elemConn[1], elemConn[2]);
00911   eLens[2] = length(elemConn[2], elemConn[0]);
00912   for (int i=0; i<3; i++) {
00913     if (eLens[i] > longEdgeLen) {
00914       longEdgeLen = eLens[i];
00915       longEdge = i;
00916       fixNode = elemConn[i];
00917       otherNode = elemConn[(i+1)%3];
00918       opNode = elemConn[(i+2)%3];
00919     }
00920   }
00921 
00922   nbr = theMesh->e2e_getNbr(e, longEdge);
00923   if (nbr == -1) 
00924     return theAdaptor->edge_bisect(fixNode, otherNode);
00925   int nbrOpNode = theAdaptor->e2n_getNot(nbr, fixNode, otherNode);
00926   double fixEdgeLen = length(fixNode, nbrOpNode);
00927   double otherEdgeLen = length(otherNode, nbrOpNode);
00928   if ((fixEdgeLen > longEdgeLen) || (otherEdgeLen > longEdgeLen)) { 
00929     
00930     int newNode = theAdaptor->edge_bisect(fixNode, otherNode);
00931     if(newNode==-1) return -1;
00932     int propElem, propNode; 
00933     if (fixEdgeLen > otherEdgeLen) {
00934       propElem = theAdaptor->findElementWithNodes(newNode, fixNode, nbrOpNode);
00935       propNode = fixNode;
00936     }
00937     else {
00938       propElem = theAdaptor->findElementWithNodes(newNode,otherNode,nbrOpNode);
00939       propNode = otherNode;
00940     }
00941 
00942     
00943     if(!FEM_Is_ghost_index(propElem)) {
00944       refine_flip_element_leb(propElem,propNode,newNode,nbrOpNode,longEdgeLen);
00945     }
00946     else {
00947       int localChk, nbrChk;
00948       localChk = theMod->getfmUtil()->getIdx();
00949       nbrChk = theMod->getfmUtil()->getRemoteIdx(theMesh,propElem,0);
00950       int propNodeT = theAdaptor->getSharedNodeIdxl(propNode, nbrChk);
00951       int newNodeT = theAdaptor->getSharedNodeIdxl(newNode, nbrChk);
00952       int nbrghost = (nbrOpNode>=0)?0:1;
00953       int nbrOpNodeT = (nbrOpNode>=0)?(theAdaptor->getSharedNodeIdxl(nbrOpNode, nbrChk)):(theAdaptor->getGhostNodeIdxl(nbrOpNode, nbrChk));
00954       int propElemT = theAdaptor->getGhostElementIdxl(propElem, nbrChk);
00955       meshMod[nbrChk].refine_flip_element_leb(localChk, propElemT, propNodeT, newNodeT,nbrOpNodeT,nbrghost,longEdgeLen);
00956     }
00957     return newNode;
00958   }
00959   else return theAdaptor->edge_bisect(fixNode, otherNode); 
00960 }
00961 
00966 void FEM_Adapt_Algs::refine_flip_element_leb(int e, int p, int n1, int n2, 
00967                          double le) 
00968 {
00969   int newNode = refine_element_leb(e);
00970   if(newNode == -1) return;
00971   (void) theAdaptor->edge_flip(n1, n2);
00972   if (length(p, newNode) > le) {
00973     int localChk = theMod->getfmUtil()->getIdx();
00974     int newElem = theAdaptor->findElementWithNodes(newNode, n1, p);
00975     refine_flip_element_leb(newElem, p, n1, newNode, le);
00976   }
00977 }
00978 
00979 
00980 
00981 
00984 int FEM_Adapt_Algs::simple_refine(double targetA, double xmin, double ymin, double xmax, double ymax) {
00985   bool adapted = true;
00986   refineElements = refineStack = NULL;
00987   refineTop = refineHeapSize = 0;
00988   int elemConn[3];
00989   double coordsn1[2], coordsn2[2], coordsn3[2];
00990   int elemWidth=3;
00991 
00992   while(adapted) {
00993     adapted = false;
00994     int noEle = theMesh->elem[0].size();
00995     refineElements = new elemHeap[noEle+1];
00996     for(int i=0; i<noEle; i++) {
00997       if(theMesh->elem[0].is_valid(i)) {
00998     theMesh->e2n_getAll(i,elemConn,0);
00999     bool notclear = false;
01000     for(int j=0; j<elemWidth; j++) {
01001       int nd = elemConn[j];
01002       if(nd>=0) notclear = theMod->fmLockN[nd].haslocks();
01003       
01004       
01005     }
01006     if(notclear) continue;
01007     getCoord(elemConn[0], coordsn1);
01008     getCoord(elemConn[1], coordsn2);
01009     getCoord(elemConn[2], coordsn3);
01010     if(coordsn1[0]<-1.0 ||coordsn1[1]<-1.0 || coordsn2[0]<-1.0 ||coordsn2[1]<-1.0 || coordsn3[0]<-1.0 ||coordsn3[1]<-1.0) continue;
01011     
01012     if((coordsn1[0]<xmax && coordsn1[0]>xmin && coordsn1[1]<ymax && coordsn1[1]>ymin) || (coordsn2[0]<xmax && coordsn2[0]>xmin && coordsn2[1]<ymax && coordsn2[1]>ymin) || (coordsn3[0]<xmax && coordsn3[0]>xmin && coordsn3[1]<ymax && coordsn3[1]>ymin)) {
01013       Insert(i,-getArea(coordsn1, coordsn2, coordsn3),0); 
01014       
01015     }
01016     else {
01017       Insert(i,-MINAREA,0); 
01018     }
01019       } else {
01020     Insert(i,-MINAREA,0);
01021       }
01022     }
01023 
01024     
01025     
01026 
01027 
01028 
01029 
01030 
01031 
01032 
01033 
01034 
01035 
01036 
01037     
01038     
01039 
01040 
01041 
01042 
01043 
01044 
01045 
01046 
01047 
01048 
01049     while(refineHeapSize>0) {
01050       int tmp = Delete_Min(0);
01051       if(tmp!=-1 && theMesh->elem[0].is_valid(tmp)) {
01052     
01053     theMesh->e2n_getAll(tmp,elemConn,0);
01054     bool notclear = false;
01055     for(int j=0; j<3; j++) {
01056       int nd = elemConn[j];
01057       if(nd>=0) notclear = theMod->fmLockN[nd].haslocks();
01058       
01059       
01060     }
01061     if(notclear) continue;
01062     getCoord(elemConn[0], coordsn1);
01063     getCoord(elemConn[1], coordsn2);
01064     getCoord(elemConn[2], coordsn3);
01065     if(coordsn1[0]<-1.0 ||coordsn1[1]<-1.0 || coordsn2[0]<-1.0 ||coordsn2[1]<-1.0 || coordsn3[0]<-1.0 ||coordsn3[1]<-1.0) continue;
01066     if(getArea(coordsn1, coordsn2, coordsn3) > targetA) {
01067       double len1 = length(coordsn1,coordsn2);
01068       double len2 = length(coordsn2,coordsn3);
01069       double len3 = length(coordsn3,coordsn1);
01070       int n1=elemConn[0], n2=elemConn[1];
01071       double max=len1;
01072       if(len2>max) {
01073         max = len2; n1 = elemConn[1]; n2 = elemConn[2];
01074       }
01075       if(len3>max) {
01076         max = len3; n1 = elemConn[2]; n2 = elemConn[0];
01077       }
01078       
01079       int ret = theAdaptor->edge_bisect(n1,n2);
01080       if(ret!=-1) adapted = true;
01081     }
01082       }
01083       
01084     }
01085     delete[] refineElements;
01086     
01087   }
01088 
01089   if(adapted) return -1;
01090   else return 1;
01091 }
01092 
01095 int FEM_Adapt_Algs::simple_coarsen(double targetA, double xmin, double ymin, double xmax, double ymax) {
01096   int noEle = theMesh->elem[0].size();
01097   int *shortestEdge = (int *)malloc(2*sizeof(int));
01098   bool adapted = true;
01099   coarsenElements = NULL;
01100   coarsenHeapSize = 0;
01101   int elemConn[3];
01102   double coordsn1[2], coordsn2[2], coordsn3[2];
01103   int elemWidth=3;
01104 
01105   while(adapted) {
01106     adapted = false;
01107     coarsenElements = new elemHeap[noEle+1];
01108     coarsenElements[0].len=-2.0;
01109     coarsenElements[0].elID=-1;
01110     for(int i=0; i<noEle; i++) {
01111       if(theMesh->elem[0].is_valid(i)) {
01112     theMesh->e2n_getAll(i,elemConn,0);
01113     bool notclear = false;
01114     for(int j=0; j<elemWidth; j++) {
01115       int nd = elemConn[j];
01116       if(nd>=0) notclear = theMod->fmLockN[nd].haslocks();
01117       
01118       
01119     }
01120     if(notclear) continue;
01121     getCoord(elemConn[0], coordsn1);
01122     getCoord(elemConn[1], coordsn2);
01123     getCoord(elemConn[2], coordsn3);
01124     if(coordsn1[0]<-1.0 ||coordsn1[1]<-1.0 || coordsn2[0]<-1.0 ||coordsn2[1]<-1.0 || coordsn3[0]<-1.0 ||coordsn3[1]<-1.0) continue;
01125     
01126     if((coordsn1[0]<xmax && coordsn1[0]>xmin && coordsn1[1]<ymax && coordsn1[1]>ymin) || (coordsn2[0]<xmax && coordsn2[0]>xmin && coordsn2[1]<ymax && coordsn2[1]>ymin) || (coordsn3[0]<xmax && coordsn3[0]>xmin && coordsn3[1]<ymax && coordsn3[1]>ymin)) {
01127       Insert(i,getArea(coordsn1, coordsn2, coordsn3),1);
01128     } 
01129     else {
01130       Insert(i,MAXAREA,1); 
01131     }
01132       } else {
01133     Insert(i,MAXAREA,1);
01134       }
01135     }
01136     
01137     
01138 
01139 
01140 
01141 
01142 
01143 
01144 
01145 
01146 
01147 
01148 
01149     
01150     
01151 
01152 
01153 
01154 
01155 
01156 
01157 
01158 
01159 
01160 
01161 
01162     while(coarsenHeapSize>0) {
01163       int tmp = Delete_Min(1);
01164       if(tmp!=-1 && theMesh->elem[0].is_valid(tmp)) {
01165     theMesh->e2n_getAll(tmp,elemConn,0);
01166     bool notclear = false;
01167     for(int j=0; j<3; j++) {
01168       int nd = elemConn[j];
01169       if(nd>=0) notclear = theMod->fmLockN[nd].haslocks();
01170       
01171       
01172     }
01173     if(notclear) continue;
01174     getCoord(elemConn[0], coordsn1);
01175     getCoord(elemConn[1], coordsn2);
01176     getCoord(elemConn[2], coordsn3);
01177     if(coordsn1[0]<-1.0 ||coordsn1[1]<-1.0 || coordsn2[0]<-1.0 ||coordsn2[1]<-1.0 || coordsn3[0]<-1.0 ||coordsn3[1]<-1.0) continue;
01178     if(getArea(coordsn1, coordsn2, coordsn3) < targetA) {
01179       getShortestEdge(elemConn[0], elemConn[1], elemConn[2], shortestEdge);
01180       int ret = theAdaptor->edge_contraction(shortestEdge[0], shortestEdge[1]);
01181       if(ret != -1) adapted = true;
01182     }
01183       }
01184       
01185     }
01186     delete[] coarsenElements;
01187     
01188   }
01189   free(shortestEdge);
01190 
01191   if(adapted) return -1;
01192   else return 1;
01193 }
01194 
01195 
01196 
01197 
01198 double FEM_Adapt_Algs::length(int n1, int n2)
01199 {
01200   double coordsn1[2], coordsn2[2];
01201   getCoord(n1, coordsn1);
01202   getCoord(n2, coordsn2);
01203 
01204   double ret = length(coordsn1, coordsn2);
01205   return ret;
01206 }
01207 
01208 double FEM_Adapt_Algs::length(double *n1_coord, double *n2_coord) { 
01209   double d, ds_sum=0.0;
01210 
01211   for (int i=0; i<dim; i++) {
01212     if(n1_coord[i]<-1.0 || n2_coord[i]<-1.0) return -2.0;
01213     d = n1_coord[i] - n2_coord[i];
01214     ds_sum += d*d;
01215   }
01216   return (sqrt(ds_sum));
01217 }
01218 
01219 double FEM_Adapt_Algs::getArea(int n1, int n2, int n3)
01220 {
01221   double coordsn1[2], coordsn2[2], coordsn3[2];
01222   getCoord(n1, coordsn1);
01223   getCoord(n2, coordsn2);
01224   getCoord(n3, coordsn3);
01225 
01226   double ret = getArea(coordsn1, coordsn2, coordsn3);
01227   return ret;
01228 }
01229 
01230 double FEM_Adapt_Algs::getArea(double *n1_coord, double *n2_coord, double *n3_coord) {
01231   double area=0.0;
01232   double aLen, bLen, cLen, sLen, d, ds_sum;
01233 
01234   ds_sum = 0.0;
01235   for (int i=0; i<2; i++) {
01236     d = n1_coord[i] - n2_coord[i];
01237     ds_sum += d*d;
01238   }
01239   aLen = sqrt(ds_sum);
01240   ds_sum = 0.0;
01241   for (int i=0; i<2; i++) {
01242     d = n2_coord[i] - n3_coord[i];
01243     ds_sum += d*d;
01244   }
01245   bLen = sqrt(ds_sum);
01246   ds_sum = 0.0;
01247   for (int i=0; i<2; i++) {
01248     d = n3_coord[i] - n1_coord[i];
01249     ds_sum += d*d;
01250   }
01251   cLen = sqrt(ds_sum);
01252   sLen = (aLen+bLen+cLen)/2;
01253   if(sLen-aLen < 0) return 0.0;
01254   else if(sLen-bLen < 0) return 0.0;
01255   else if(sLen-cLen < 0) return 0.0; 
01256   return (sqrt(sLen*(sLen-aLen)*(sLen-bLen)*(sLen-cLen)));
01257 }
01258 
01259 double FEM_Adapt_Algs::getSignedArea(int n1, int n2, int n3) {
01260   double coordsn1[2], coordsn2[2], coordsn3[2];
01261   getCoord(n1, coordsn1);
01262   getCoord(n2, coordsn2);
01263   getCoord(n3, coordsn3);
01264 
01265   double ret = getSignedArea(coordsn1, coordsn2, coordsn3);
01266   return ret;
01267 }
01268 
01269 double FEM_Adapt_Algs::getSignedArea(double *n1_coord, double *n2_coord, double *n3_coord) {
01270   double area=0.0;
01271   double vec1_x, vec1_y, vec2_x, vec2_y;
01272 
01273   vec1_x = n1_coord[0] - n2_coord[0];
01274   vec1_y = n1_coord[1] - n2_coord[1];
01275   vec2_x = n3_coord[0] - n2_coord[0];
01276   vec2_y = n3_coord[1] - n2_coord[1];
01277 
01278   area = vec1_x*vec2_y - vec2_x*vec1_y;
01279   return area;
01280 }
01281 
01282 int FEM_Adapt_Algs::getCoord(int n1, double *crds) {
01283   if(!FEM_Is_ghost_index(n1)) {
01284     FEM_Mesh_dataP(theMesh, FEM_NODE, coord_attr, (void *)crds, n1, 1, FEM_DOUBLE, dim);
01285   }
01286   else {
01287     int numchunks;
01288     IDXL_Share **chunks1;
01289     theMod->fmUtil->getChunkNos(0,n1,&numchunks,&chunks1);
01290     int index = theMod->idx;
01291     for(int j=0; j<numchunks; j++) {
01292       int chk = chunks1[j]->chk;
01293       if(chk==index) continue;
01294       int ghostidx = theMod->fmUtil->exists_in_IDXL(theMesh,n1,chk,2);
01295       double2Msg *d = meshMod[chk].getRemoteCoord(index,ghostidx);
01296       crds[0] = d->i;
01297       crds[1] = d->j;
01298       for(int j=0; j<numchunks; j++) {
01299     delete chunks1[j];
01300       }
01301       if(numchunks != 0) free(chunks1);
01302       delete d;
01303       break;
01304     }
01305   }
01306   return 1;
01307 }
01308 
01309 int FEM_Adapt_Algs::getShortestEdge(int n1, int n2, int n3, int* shortestEdge) {
01310   
01311   
01312   
01313   double coordsn1[2], coordsn2[2], coordsn3[2];
01314   getCoord(n1, coordsn1);
01315   getCoord(n2, coordsn2);
01316   getCoord(n3, coordsn3);
01317 
01318   double aLen = length(coordsn1, coordsn2);
01319   int shortest = 0;
01320 
01321   double bLen = length(coordsn2, coordsn3);
01322   if(bLen < aLen) shortest = 1;
01323 
01324   double cLen = length(coordsn3, coordsn1);
01325   if((cLen < aLen) && (cLen < bLen)) shortest = 2;
01326 
01327   if(shortest==0) {
01328     shortestEdge[0] = n1;
01329     shortestEdge[1] = n2;
01330   }
01331   else if (shortest==1) {
01332     shortestEdge[0] = n2;
01333     shortestEdge[1] = n3;
01334   }
01335   else {
01336     shortestEdge[0] = n3;
01337     shortestEdge[1] = n1;
01338   }
01339   return 1;
01340 }
01341 
01342 
01343 
01347 double FEM_Adapt_Algs::getAreaQuality(int elem)
01348 {
01349   double f, q, len[3];
01350   int n[3];
01351   double currentArea;
01352   double coordsn1[2], coordsn2[2], coordsn3[2];
01353 
01354   theMesh->e2n_getAll(elem, n);
01355   getCoord(n[0], coordsn1);
01356   getCoord(n[1], coordsn2);
01357   getCoord(n[2], coordsn3);
01358 
01359   currentArea = getArea(coordsn1, coordsn2, coordsn3);
01360 
01361   len[0] = length(coordsn1, coordsn2);
01362   len[1] = length(coordsn2, coordsn3);
01363   len[2] = length(coordsn3, coordsn1);
01364   f = 4.0*sqrt(3.0); 
01365   q = (f*currentArea)/(len[0]*len[0]+len[1]*len[1]+len[2]*len[2]);
01366   return q;
01367 }
01368 
01373 void FEM_Adapt_Algs::ensureQuality(int n1, int n2, int n3) {
01374   double coordsn1[2], coordsn2[2], coordsn3[2];
01375   getCoord(n1, coordsn1);
01376   getCoord(n2, coordsn2);
01377   getCoord(n3, coordsn3);
01378   double area = getSignedArea(coordsn1, coordsn2, coordsn3);
01379   double len1 = length(coordsn1, coordsn2);
01380   double len2 = length(coordsn2, coordsn3);
01381   double len3 = length(coordsn3, coordsn1);
01382   double max = len1;
01383   if(len2>max) max = len2;
01384   if(len3>max) max = len3;
01385   
01386   double min = len1;
01387   if(len2<min) min = len2;
01388   if(len3<min) min = len3;
01389   double shortest_al = fabs(area/max);
01390   double largestR = max/shortest_al;
01391   CkAssert(largestR<=100.0 && -area > SLIVERAREA);
01392 }
01393 
01396 bool FEM_Adapt_Algs::controlQualityF(int n1, int n2, int n3, int n4) {
01397   
01398   double coordsn1[2], coordsn2[2], coordsn3[2], coordsn4[2];
01399   if(n4==-1) return false;
01400   getCoord(n1, coordsn1);
01401   getCoord(n2, coordsn2);
01402   getCoord(n3, coordsn3);
01403   getCoord(n4, coordsn4);
01404   bool flag = false;
01405   if(!flag) flag = controlQualityC(coordsn3,coordsn1,coordsn2,coordsn4);
01406   if(!flag) flag = controlQualityC(coordsn4,coordsn2,coordsn1,coordsn3);
01407   return flag;
01408 }
01409 
01412 bool FEM_Adapt_Algs::controlQualityR(int n1, int n2, int n3, int n4) {
01413   
01414   double coordsn1[2], coordsn2[2], coordsn3[2], coordsn4[2], coordsn5[2];
01415   if(n4==-1) return false;
01416   getCoord(n1, coordsn1);
01417   getCoord(n2, coordsn2);
01418   getCoord(n3, coordsn3);
01419   getCoord(n4, coordsn4);
01420   coordsn5[0] = (coordsn1[0]+coordsn2[0])*0.5;
01421   coordsn5[1] = (coordsn1[1]+coordsn2[1])*0.5;
01422   bool flag = false;
01423   if(!flag) flag = theMod->fmAdaptAlgs->controlQualityR(coordsn1,coordsn3,coordsn5);
01424   if(!flag) flag = theMod->fmAdaptAlgs->controlQualityR(coordsn2,coordsn3,coordsn5);
01425   if(!flag) flag = theMod->fmAdaptAlgs->controlQualityR(coordsn1,coordsn4,coordsn5);
01426   if(!flag) flag = theMod->fmAdaptAlgs->controlQualityR(coordsn2,coordsn4,coordsn5);
01427   return flag;
01428 }
01429 
01430 bool FEM_Adapt_Algs::controlQualityR(double *coordsn1, double *coordsn2, double *coordsn3) {
01431   double area = getArea(coordsn1, coordsn2, coordsn3);
01432   
01433   double len1 = length(coordsn1, coordsn2);
01434   double len2 = length(coordsn2, coordsn3);
01435   double len3 = length(coordsn3, coordsn1);
01436   
01437   double max = len1;
01438   if(len2>max) max = len2;
01439   if(len3>max) max = len3;
01440   double shortest_al = area/max;
01441   double largestR = max/shortest_al;
01442   if(largestR>50.0) return true;
01443   else return false;
01444 }
01445 
01450 bool FEM_Adapt_Algs::controlQualityC(int n1, int n2, int n3, double *n4_coord) {
01451   
01452   double coordsn1[2], coordsn2[2], coordsn3[2];
01453   getCoord(n1, coordsn1);
01454   getCoord(n2, coordsn2);
01455   getCoord(n3, coordsn3);
01456   return controlQualityC(coordsn1,coordsn2,coordsn3,n4_coord);
01457 }
01458 
01459 bool FEM_Adapt_Algs::controlQualityC(double *coordsn1, double *coordsn2, double *coordsn3, double *n4_coord) {
01460   double ret_old = getSignedArea(coordsn1, coordsn2, coordsn3);
01461   double ret_new = getSignedArea(coordsn1, coordsn2, n4_coord);
01462   
01463   double len1 = length(coordsn1, coordsn2);
01464   double len2 = length(coordsn2, n4_coord);
01465   double len3 = length(n4_coord, coordsn1);
01466   
01467   double max = len1;
01468   if(len2>max) max = len2;
01469   if(len3>max) max = len3;
01470   
01471   double min = len1;
01472   if(len2<min) min = len2;
01473   if(len3<min) min = len3;
01474   double shortest_al = ret_new/max;
01475   double largestR = max/shortest_al;
01476   if(ret_old > SLIVERAREA && ret_new < -SLIVERAREA) return true; 
01477   else if(ret_old < -SLIVERAREA && ret_new > SLIVERAREA) return true; 
01478   else if(fabs(ret_new) < SLIVERAREA) return true; 
01479   
01480   
01481   else if(fabs(largestR)>50.0) return true;
01482   else return false;
01483 }
01484 
01485 
01486 
01492 bool FEM_Adapt_Algs::flipOrBisect(int elId, int n1, int n2, int maxEdgeIdx, double maxlen) {
01493   
01494   int nbrEl = theMesh->e2e_getNbr(elId,maxEdgeIdx);
01495   double len4=0.0, len5=0.0;
01496   if(nbrEl!=-1) {
01497     int con1[3];
01498     theMesh->e2n_getAll(nbrEl,con1);
01499     int nbrnode=-1;
01500     for(int j=0; j<3; j++) {
01501       if(con1[j]!=n1 && con1[j]!=n2) {
01502     nbrnode = con1[j];
01503     break;
01504       }
01505     }
01506     len4 = length(n1,nbrnode);
01507     len5 = length(n2,nbrnode);
01508   }
01509   if(len4>1.2*maxlen || len5>1.2*maxlen) {
01510     return true;
01511   }
01512   else return false;
01513 }
01514 
01515 void FEM_Adapt_Algs::tests(bool b=true) {
01516   
01517   if(!b) {
01518     theMod->fmUtil->AreaTest(theMesh);
01519     return;
01520   }
01521   theMod->fmUtil->AreaTest(theMesh);
01522   theMod->fmUtil->StructureTest(theMesh);
01523   theMod->fmUtil->IdxlListTest(theMesh);
01524   theMod->fmUtil->residualLockTest(theMesh);
01525   
01526 
01527 
01528 
01529 
01530   return;
01531 }