00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "fem_adapt_algs.h"
00011 #include "fem_mesh_modify.h"
00012 #include "fem_adapt_if.h"
00013
00014 #define MINAREA 1.0e-18
00015 #define MAXAREA 1.0e12
00016
00017 #define GRADATION 1.3
00018
00019 CtvDeclare(FEM_Adapt_Algs *, _adaptAlgs);
00020
00021 FEM_Adapt_Algs::FEM_Adapt_Algs(FEM_Mesh *m, femMeshModify *fm, int dimension)
00022 {
00023 theMesh = m;
00024 theMod = fm;
00025 dim = dimension;
00026
00027 theAdaptor = theMod->fmAdaptL;
00028 }
00029
00030 void FEM_Adapt_Algs::FEM_AdaptMesh(int qm, int method, double factor,
00031 double *sizes)
00032 {
00033 SetMeshSize(method, factor, sizes);
00034 GradateMesh(GRADATION);
00035 (void)Refine(qm, method, factor, sizes);
00036 GradateMesh(GRADATION);
00037 (void)Coarsen(qm, method, factor, sizes);
00038 }
00039
00040
00041
00042
00043
00044
00045 void FEM_Adapt_Algs::FEM_Refine(int qm, int method, double factor,
00046 double *sizes)
00047 {
00048 SetMeshSize(method, factor, sizes);
00049 GradateMesh(GRADATION);
00050 (void)Refine(qm, method, factor, sizes);
00051 }
00052
00053
00054 int FEM_Adapt_Algs::Refine(int qm, int method, double factor, double *sizes)
00055 {
00056
00057 int elId, mods=0, iter_mods=1;
00058 int elemWidth = theMesh->elem[0].getConn().width();
00059 refineElements = refineStack = NULL;
00060 refineTop = refineHeapSize = 0;
00061 while (iter_mods != 0) {
00062 iter_mods=0;
00063 numNodes = theMesh->node.size();
00064 numElements = theMesh->elem[0].size();
00065
00066 if (refineStack) delete [] refineStack;
00067 refineStack = new elemHeap[numElements];
00068 if (refineElements) delete [] refineElements;
00069 refineElements = new elemHeap[numElements+1];
00070 for (int i=0; i<numElements; i++) {
00071 if (theMesh->elem[0].is_valid(i)) {
00072
00073 int *eConn = (int*)malloc(elemWidth*sizeof(int));
00074 double tmpLen, avgEdgeLength=0.0, maxEdgeLength = 0.0;
00075 theMesh->e2n_getAll(i, eConn);
00076 for (int j=0; j<elemWidth-1; j++) {
00077 for (int k=j+1; k<elemWidth; k++) {
00078 tmpLen = length(eConn[j], eConn[k]);
00079 avgEdgeLength += tmpLen;
00080 if (tmpLen > maxEdgeLength) maxEdgeLength = tmpLen;
00081 }
00082 }
00083 avgEdgeLength /= 3.0;
00084 double qFactor=getAreaQuality(i);
00085 if (theMesh->elem[0].getMeshSizing(i) <= 0.0)
00086 CkPrintf("WARNING: mesh element %d has no sizing!\n", i);
00087 if ((theMesh->elem[0].getMeshSizing(i) > 0.0) &&
00088 (avgEdgeLength > (theMesh->elem[0].getMeshSizing(i)*REFINE_TOL))){
00089 Insert(i, qFactor*(1.0/maxEdgeLength), 0);
00090 }
00091 }
00092 }
00093 while (refineHeapSize>0 || refineTop > 0) {
00094 int n1, n2;
00095 if (refineTop>0) {
00096 refineTop--;
00097 elId=refineStack[refineTop].elID;
00098 }
00099 else elId=Delete_Min(0);
00100 if ((elId != -1) && (theMesh->elem[0].is_valid(elId))) {
00101 int *eConn = (int*)malloc(elemWidth*sizeof(int));
00102 int n1, n2;
00103 double tmpLen, avgEdgeLength=0.0, maxEdgeLength = 0.0;
00104 theMesh->e2n_getAll(elId, eConn);
00105 for (int j=0; j<elemWidth-1; j++) {
00106 for (int k=j+1; k<elemWidth; k++) {
00107 tmpLen = length(eConn[j], eConn[k]);
00108 avgEdgeLength += tmpLen;
00109 if (tmpLen > maxEdgeLength) {
00110 maxEdgeLength = tmpLen;
00111 n1 = eConn[j]; n2 = eConn[k];
00112 }
00113 }
00114 }
00115 avgEdgeLength /= 3.0;
00116 if ((theMesh->elem[0].getMeshSizing(elId) > 0.0) &&
00117 (avgEdgeLength>(theMesh->elem[0].getMeshSizing(elId)*REFINE_TOL))){
00118 if (theAdaptor->edge_bisect(n1, n2) > 0) iter_mods++;
00119 }
00120 }
00121 CthYield();
00122 }
00123 mods += iter_mods;
00124 CkPrintf("ParFUM_Refine: %d modifications in last pass.\n", iter_mods);
00125 }
00126 CkPrintf("ParFUM_Refine: %d total modifications.\n", mods);
00127 delete[] refineStack;
00128 delete[] refineElements;
00129 return mods;
00130 }
00131
00132
00133
00134
00135
00136
00137 void FEM_Adapt_Algs::FEM_Coarsen(int qm, int method, double factor,
00138 double *sizes)
00139 {
00140 CkPrintf("WARNING: ParFUM_Coarsen: Under construction.\n");
00141 SetMeshSize(method, factor, sizes);
00142 GradateMesh(GRADATION);
00143 (void)Coarsen(qm, method, factor, sizes);
00144 }
00145
00146
00147 int FEM_Adapt_Algs::Coarsen(int qm, int method, double factor, double *sizes)
00148 {
00149
00150 int elId, mods=0, iter_mods=1, pass=0;
00151 int elemWidth = theMesh->elem[0].getConn().width();
00152 double qFactor;
00153 coarsenElements = NULL;
00154 coarsenHeapSize = 0;
00155 while (iter_mods != 0) {
00156 iter_mods=0;
00157 pass++;
00158 numNodes = theMesh->node.size();
00159 numElements = theMesh->elem[0].size();
00160
00161 if (coarsenElements) delete [] coarsenElements;
00162 coarsenElements = new elemHeap[numElements+1];
00163 coarsenElements[0].len=-2.0;
00164 coarsenElements[0].elID=-1;
00165 for (int i=0; i<numElements; i++) {
00166 if (theMesh->elem[0].is_valid(i)) {
00167
00168 int *eConn = (int*)malloc(elemWidth*sizeof(int));
00169 theMesh->e2n_getAll(i, eConn);
00170 double tmpLen, avgEdgeLength=0.0,
00171 minEdgeLength = length(eConn[0], eConn[1]);
00172 for (int j=0; j<elemWidth-1; j++) {
00173 for (int k=j+1; k<elemWidth; k++) {
00174 tmpLen = length(eConn[j], eConn[k]);
00175 avgEdgeLength += tmpLen;
00176 if (tmpLen < minEdgeLength) minEdgeLength = tmpLen;
00177 }
00178 }
00179 avgEdgeLength /= 3.0;
00180 qFactor=getAreaQuality(i);
00181 if (((theMesh->elem[0].getMeshSizing(i) > 0.0) &&
00182 (avgEdgeLength < (theMesh->elem[0].getMeshSizing(i)*COARSEN_TOL)))
00183 || (qFactor < QUALITY_MIN)) {
00184
00185
00186 Insert(i, qFactor*minEdgeLength, 1);
00187 }
00188 }
00189 }
00190 while (coarsenHeapSize>0) {
00191 elId=Delete_Min(1);
00192 if ((elId != -1) && (theMesh->elem[0].is_valid(elId))) {
00193 int *eConn = (int*)malloc(elemWidth*sizeof(int));
00194 theMesh->e2n_getAll(elId, eConn);
00195 int n1=eConn[0], n2=eConn[1];
00196 double tmpLen, avgEdgeLength=0.0,
00197 minEdgeLength = length(n1, n2);
00198 for (int j=0; j<elemWidth-1; j++) {
00199 for (int k=j+1; k<elemWidth; k++) {
00200 tmpLen = length(eConn[j], eConn[k]);
00201 avgEdgeLength += tmpLen;
00202 if (tmpLen < minEdgeLength) {
00203 minEdgeLength = tmpLen;
00204 n1 = eConn[j]; n2 = eConn[k];
00205 }
00206 }
00207 }
00208 CkAssert(n1!=-1 && n2!=-1);
00209 avgEdgeLength /= 3.0;
00210 qFactor=getAreaQuality(elId);
00211
00212 if (((theMesh->elem[0].getMeshSizing(elId) > 0.0) &&
00213 (avgEdgeLength < (theMesh->elem[0].getMeshSizing(elId)*COARSEN_TOL)))
00214 || (qFactor < QUALITY_MIN)) {
00215
00216
00217 int eNbr = theMesh->e2e_getNbr(elId, theMesh->e2n_getIndex(elId,n1)+
00218 theMesh->e2n_getIndex(elId,n2)-1, 0);
00219
00220 if ((eNbr >= 0) && (theMesh->elem[0].is_valid(eNbr))) {
00221 eConn = (int*)malloc(elemWidth*sizeof(int));
00222 theMesh->e2n_getAll(eNbr, eConn);
00223 avgEdgeLength=0.0;
00224 for (int j=0; j<elemWidth-1; j++) {
00225 for (int k=j+1; k<elemWidth; k++) {
00226 avgEdgeLength += length(eConn[j], eConn[k]);
00227 }
00228 }
00229 avgEdgeLength /= 3.0;
00230 qFactor=getAreaQuality(eNbr);
00231 if (((theMesh->elem[0].getMeshSizing(eNbr) > 0.0) &&
00232 (avgEdgeLength < (theMesh->elem[0].getMeshSizing(eNbr))))
00233 || (qFactor < QUALITY_MIN)) {
00234
00235 if (theAdaptor->edge_contraction(n1, n2) > 0) iter_mods++;
00236 }
00237 }
00238 else {
00239
00240 if (theAdaptor->edge_contraction(n1, n2) > 0) iter_mods++;
00241 }
00242 }
00243 }
00244 CthYield();
00245 }
00246 mods += iter_mods;
00247 CkPrintf("ParFUM_Coarsen: %d modifications in pass %d.\n", iter_mods, pass);
00248 }
00249 CkPrintf("ParFUM_Coarsen: %d total modifications over %d passes.\n", mods, pass);
00250 delete[] coarsenElements;
00251 return mods;
00252 }
00253
00254
00255 void FEM_Adapt_Algs::FEM_Smooth(int qm, int method)
00256 {
00257 CkPrintf("WARNING: ParFUM_Smooth: Not yet implemented.\n");
00258 }
00259
00260
00261 void FEM_Adapt_Algs::FEM_Repair(int qm)
00262 {
00263 CkPrintf("WARNING: ParFUM_Repair: Not yet implemented.\n");
00264 }
00265
00266
00267
00268
00269 void FEM_Adapt_Algs::FEM_Remesh(int qm, int method, double factor,
00270 double *sizes)
00271 {
00272 CkPrintf("WARNING: ParFUM_Remesh: Under construction.\n");
00273 }
00274
00275
00276 void FEM_Adapt_Algs::SetMeshSize(int method, double factor, double *sizes)
00277 {
00278 numNodes = theMesh->node.size();
00279 numElements = theMesh->elem[0].size();
00280
00281 if (method == 0) {
00282
00283 for (int i=0; i<numElements; i++) {
00284 theMesh->elem[0].setMeshSizing(i, factor);
00285 }
00286 CkPrintf("ParFUM_SetMeshSize: UNIFORM %4.6e\n", factor);
00287 }
00288 else if (method == 1) {
00289 for (int i=0; i<numElements; i++) {
00290 if (sizes[i] > 0.0) {
00291 theMesh->elem[0].setMeshSizing(i, sizes[i]);
00292 }
00293 }
00294 CkPrintf("ParFUM_SetMeshSize: SIZES input\n");
00295 }
00296 else if (method == 2) {
00297 double avgEdgeLength = 0.0;
00298 int width = theMesh->elem[0].getConn().width();
00299 int* eConn = (int*)malloc(width*sizeof(int));
00300 int numEdges=3;
00301 if (dim==3) numEdges=6;
00302 for (int i=0; i<numElements; i++) {
00303 theMesh->e2n_getAll(i, eConn);
00304 for (int j=0; j<width-1; j++) {
00305 for (int k=j+1; k<width; k++) {
00306 avgEdgeLength += length(eConn[j], eConn[k]);
00307 }
00308 }
00309 avgEdgeLength += length(eConn[0], eConn[width-1]);
00310 avgEdgeLength /= (double)numEdges;
00311 theMesh->elem[0].setMeshSizing(i, factor*avgEdgeLength);
00312 }
00313 CkPrintf("ParFUM_SetMeshSize: CALCULATED & SCALED \n");
00314 }
00315 else if (method == 3) {
00316 for (int i=0; i<numElements; i++) {
00317 if (sizes[i] > 0.0) {
00318 theMesh->elem[0].setMeshSizing(i, sizes[i]*theMesh->elem[0].getMeshSizing(i));
00319 }
00320 }
00321 }
00322 else if (method == 4) {
00323 for (int i=0; i<numElements; i++) {
00324 theMesh->elem[0].setMeshSizing(i, factor*theMesh->elem[0].getMeshSizing(i));
00325 }
00326 }
00327 else if (method == 5) {
00328 CkPrintf("ParFUM_SetMeshSize: USE EXISTING SIZES \n");
00329 }
00330
00331
00332
00333
00334 }
00335
00336
00337 void FEM_Adapt_Algs::SetReferenceMesh()
00338 {
00339
00340
00341 double avgLength = 0.0;
00342 int width = theMesh->elem[0].getConn().width();
00343 int* eConn = (int*)malloc(width*sizeof(int));
00344 int numElements = theMesh->elem[0].size();
00345
00346 for (int i=0; i<numElements; ++i, avgLength=0) {
00347 theMesh->e2n_getAll(i, eConn);
00348 for (int j=0; j<width-1; ++j) {
00349 avgLength += length(eConn[j], eConn[j+1]);
00350 }
00351 avgLength += length(eConn[0], eConn[width-1]);
00352 avgLength /= width;
00353 theMesh->elem[0].setMeshSizing(i, avgLength);
00354 }
00355 free(eConn);
00356 }
00357
00358
00359 void FEM_Adapt_Algs::GradateMesh(double smoothness)
00360 {
00361
00362
00363
00364
00365
00366 const double beta = smoothness;
00367
00368 double maxShock, minShock;
00369 int iteration = 0, updates = 0;
00370
00371 int* adjNodes, *boundNodes;
00372 int nadjNodes, nnodes;
00373 int meshNum = FEM_Mesh_default_read();
00374
00375 if (smoothness < 1.0) {
00376 printf("");
00377 }
00378
00379 nnodes = theMesh->node.size();
00380 boundNodes = new int[nnodes];
00381 FEM_Mesh_data(meshNum, FEM_NODE, FEM_BOUNDARY,
00382 boundNodes, 0, nnodes, FEM_INT, 1);
00383
00384
00385 printf("Running h-shock mesh gradation with beta=%.3f\n", beta);
00386 fflush(NULL);
00387
00388 #ifndef GRADATION_ITER_LIMIT
00389 #define GRADATION_ITER_LIMIT 10
00390 #endif
00391
00392 do {
00393 maxShock = 0;
00394 minShock = 1e10;
00395
00396 for (int node=0; node<nnodes; ++node) {
00397 if (boundNodes[node]!= 0 || !FEM_is_valid(meshNum, FEM_NODE, node))
00398 continue;
00399
00400
00401
00402 theMesh->n2n_getAll(node, &adjNodes, &nadjNodes);
00403 for (int adjNode=0; adjNode<nadjNodes; ++adjNode) {
00404 double edgelen = length(node, adjNodes[adjNode]);
00405
00406
00407
00408 int e1, e2;
00409 theMesh->get2ElementsOnEdge(node, adjNodes[adjNode], &e1, &e2);
00410
00411 double s1, s2;
00412 s1 = theMesh->elem[0].getMeshSizing(e1);
00413 s2 = theMesh->elem[0].getMeshSizing(e2);
00414
00415 if (s1 <= 0 || s2 <= 0) continue;
00416
00417
00418 CkAssert(s1 >= 0 && s2 >= 0 && "Bad size");
00419 CkAssert(edgelen > 1e-6 && "Length 0 edge");
00420 CkAssert(edgelen == edgelen && "Length inf edge");
00421
00422 double ratio = (s1 > s2) ? s1/s2 : s2/s1;
00423 CkAssert (ratio >= 1.0 && ratio == ratio && "Bad ratio");
00424
00425
00426
00427 if (ratio > beta) {
00428 if (s1 > s2) {
00429 theMesh->elem[0].setMeshSizing(e1, s1 - (s1-s2)/3);
00430 theMesh->elem[0].setMeshSizing(e2, s2 + (s1-s2)/3);
00431 } else {
00432 theMesh->elem[0].setMeshSizing(e2, s2 - (s2-s1)/3);
00433 theMesh->elem[0].setMeshSizing(e1, s1 + (s2-s1)/3);
00434 }
00435 updates++;
00436 }
00437 if (ratio > maxShock) maxShock = ratio;
00438 if (ratio < minShock) minShock = ratio;
00439
00440
00442
00443
00444
00445
00446
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469 }
00470 delete[] adjNodes;
00471 }
00472
00473 printf("Finished iteration %d\n", iteration);
00474 printf("Max shock:%8.3f\n", maxShock);
00475 printf("Min shock:%8.3f\n", minShock);
00476 printf("Target:%8.3f\n", beta);
00477
00478 } while (maxShock > beta && ++iteration < GRADATION_ITER_LIMIT);
00479 tests();
00480
00481 printf("%d total updates in %d iterations in GradateMesh\n",
00482 updates, iteration);
00483 fflush(NULL);
00484
00485 delete[] boundNodes;
00486 }
00487
00488
00489 int FEM_Adapt_Algs::simple_refine(double targetA, double xmin, double ymin, double xmax, double ymax) {
00490 int *con = (int*)malloc(3*sizeof(int));
00491 double *n1_coord = (double*)malloc(2*sizeof(double));
00492 double *n2_coord = (double*)malloc(2*sizeof(double));
00493 double *n3_coord = (double*)malloc(2*sizeof(double));
00494 bool adapted = true;
00495
00496 while(adapted) {
00497 adapted = false;
00498 int noEle = theMesh->elem[0].size();
00499 double *areas = (double*)malloc(noEle*sizeof(double));
00500 int *map1 = (int*)malloc(noEle*sizeof(int));
00501 for(int i=0; i<noEle; i++) {
00502 if(theMesh->elem[0].is_valid(i)) {
00503 theMesh->e2n_getAll(i,con,0);
00504 getCoord(con[0], n1_coord);
00505 getCoord(con[1], n2_coord);
00506 getCoord(con[2], n3_coord);
00507
00508 if((n1_coord[0]<xmax && n1_coord[0]>xmin && n1_coord[1]<ymax && n1_coord[1]>ymin) || (n2_coord[0]<xmax && n2_coord[0]>xmin && n2_coord[1]<ymax && n2_coord[1]>ymin) || (n3_coord[0]<xmax && n3_coord[0]>xmin && n3_coord[1]<ymax && n3_coord[1]>ymin)) {
00509 areas[i] = getArea(n1_coord, n2_coord, n3_coord);
00510 }
00511 else {
00512 areas[i] = MINAREA;
00513 }
00514 } else {
00515 areas[i] = MINAREA;
00516 }
00517 map1[i] = i;
00518 }
00519
00520 for(int i=0; i<noEle; i++) {
00521 for(int j=i+1; j<noEle; j++) {
00522 if(areas[j] > areas[i]) {
00523 double tmp = areas[j];
00524 areas[j] = areas[i];
00525 areas[i] = tmp;
00526 int t = map1[j];
00527 map1[j] = map1[i];
00528 map1[i] = t;
00529 }
00530 }
00531 }
00532
00533 for(int i=0; i<noEle; i++) {
00534 if(theMesh->elem[0].is_valid(map1[i])) {
00535 if(areas[i] > targetA) {
00536 refine_element_leb(map1[i]);
00537 adapted = true;
00538 }
00539 }
00540
00541 }
00542 free(areas);
00543 free(map1);
00544
00545 }
00546
00547 free(con);
00548 free(n1_coord);
00549 free(n2_coord);
00550 free(n3_coord);
00551
00552 if(adapted) return -1;
00553 else return 1;
00554 }
00555
00556 int FEM_Adapt_Algs::simple_coarsen(double targetA, double xmin, double ymin, double xmax, double ymax) {
00557 int noEle = theMesh->elem[0].size();
00558 int *con = (int*)malloc(3*sizeof(int));
00559 double *areas = (double*)malloc(noEle*sizeof(double));
00560 int *map1 = (int*)malloc(noEle*sizeof(int));
00561 double *n1_coord = (double*)malloc(2*sizeof(double));
00562 double *n2_coord = (double*)malloc(2*sizeof(double));
00563 double *n3_coord = (double*)malloc(2*sizeof(double));
00564 int *shortestEdge = (int *)malloc(2*sizeof(int));
00565 bool adapted = true;
00566
00567 while(adapted) {
00568 adapted = false;
00569 for(int i=0; i<noEle; i++) {
00570 if(theMesh->elem[0].is_valid(i)) {
00571 theMesh->e2n_getAll(i,con,0);
00572 getCoord(con[0], n1_coord);
00573 getCoord(con[1], n2_coord);
00574 getCoord(con[2], n3_coord);
00575
00576 if((n1_coord[0]<xmax && n1_coord[0]>xmin && n1_coord[1]<ymax && n1_coord[1]>ymin) || (n2_coord[0]<xmax && n2_coord[0]>xmin && n2_coord[1]<ymax && n2_coord[1]>ymin) || (n3_coord[0]<xmax && n3_coord[0]>xmin && n3_coord[1]<ymax && n3_coord[1]>ymin)) {
00577 areas[i] = getArea(n1_coord, n2_coord, n3_coord);
00578 }
00579 else {
00580 areas[i] = MAXAREA;
00581 }
00582 } else {
00583 areas[i] = MAXAREA;
00584 }
00585 map1[i] = i;
00586 }
00587
00588 for(int i=0; i<noEle; i++) {
00589 for(int j=i+1; j<noEle; j++) {
00590 if(areas[j] < areas[i]) {
00591 double tmp = areas[j];
00592 areas[j] = areas[i];
00593 areas[i] = tmp;
00594 int t = map1[j];
00595 map1[j] = map1[i];
00596 map1[i] = t;
00597 }
00598 }
00599 }
00600
00601 for(int i=0; i<noEle; i++) {
00602 if(theMesh->elem[0].is_valid(map1[i])) {
00603 if(areas[i] < targetA) {
00604
00605 theMesh->e2n_getAll(map1[i],con,0);
00606 getShortestEdge(con[0], con[1], con[2], shortestEdge);
00607 int ret = theAdaptor->edge_contraction(shortestEdge[0], shortestEdge[1]);
00608 if(ret != -1) adapted = true;
00609 }
00610 }
00611
00612 }
00613
00614 }
00615
00616 free(con);
00617 free(areas);
00618 free(map1);
00619 free(n1_coord);
00620 free(n2_coord);
00621 free(n3_coord);
00622 free(shortestEdge);
00623
00624 if(adapted) return -1;
00625 else return 1;
00626 }
00627
00628 void FEM_Adapt_Algs::tests() {
00629
00630
00631 theMod->fmUtil->StructureTest(theMesh);
00632 theMod->fmUtil->IdxlListTest(theMesh);
00633 theMod->fmUtil->residualLockTest(theMesh);
00634
00635
00636
00637
00638
00639
00640 return;
00641 }
00642
00643
00644
00645
00646
00647
00648
00649 int FEM_Adapt_Algs::refine_element_leb(int e) {
00650 int *eConn = (int*)malloc(3*sizeof(int));
00651 int fixNode, otherNode, opNode, longEdge, nbr;
00652 double eLens[3], longEdgeLen = 0.0;
00653
00654 if(e==-1) {
00655 free(eConn);
00656 return -1;
00657 }
00658
00659 theMesh->e2n_getAll(e, eConn);
00660 eLens[0] = length(eConn[0], eConn[1]);
00661 eLens[1] = length(eConn[1], eConn[2]);
00662 eLens[2] = length(eConn[2], eConn[0]);
00663 for (int i=0; i<3; i++) {
00664 if (eLens[i] > longEdgeLen) {
00665 longEdgeLen = eLens[i];
00666 longEdge = i;
00667 fixNode = eConn[i];
00668 otherNode = eConn[(i+1)%3];
00669 opNode = eConn[(i+2)%3];
00670 }
00671 }
00672 free(eConn);
00673
00674 nbr = theMesh->e2e_getNbr(e, longEdge);
00675 if (nbr == -1)
00676 return theAdaptor->edge_bisect(fixNode, otherNode);
00677 int nbrOpNode = theAdaptor->e2n_getNot(nbr, fixNode, otherNode);
00678 double fixEdgeLen = length(fixNode, nbrOpNode);
00679 double otherEdgeLen = length(otherNode, nbrOpNode);
00680 if ((fixEdgeLen > longEdgeLen) || (otherEdgeLen > longEdgeLen)) {
00681
00682 int newNode = theAdaptor->edge_bisect(fixNode, otherNode);
00683 if(newNode==-1) return -1;
00684 int propElem, propNode;
00685 if (fixEdgeLen > otherEdgeLen) {
00686 propElem = theAdaptor->findElementWithNodes(newNode, fixNode, nbrOpNode);
00687 propNode = fixNode;
00688 }
00689 else {
00690 propElem = theAdaptor->findElementWithNodes(newNode,otherNode,nbrOpNode);
00691 propNode = otherNode;
00692 }
00693
00694
00695 if(!FEM_Is_ghost_index(propElem)) {
00696 refine_flip_element_leb(propElem,propNode,newNode,nbrOpNode,longEdgeLen);
00697 }
00698 else {
00699 int localChk, nbrChk;
00700 localChk = theMod->getfmUtil()->getIdx();
00701 nbrChk = theMod->getfmUtil()->getRemoteIdx(theMesh,propElem,0);
00702 int propNodeT = theAdaptor->getSharedNodeIdxl(propNode, nbrChk);
00703 int newNodeT = theAdaptor->getSharedNodeIdxl(newNode, nbrChk);
00704 int nbrghost = (nbrOpNode>=0)?0:1;
00705 int nbrOpNodeT = (nbrOpNode>=0)?(theAdaptor->getSharedNodeIdxl(nbrOpNode, nbrChk)):(theAdaptor->getGhostNodeIdxl(nbrOpNode, nbrChk));
00706 int propElemT = theAdaptor->getGhostElementIdxl(propElem, nbrChk);
00707 meshMod[nbrChk].refine_flip_element_leb(localChk, propElemT, propNodeT, newNodeT,nbrOpNodeT,nbrghost,longEdgeLen);
00708 }
00709 return newNode;
00710 }
00711 else return theAdaptor->edge_bisect(fixNode, otherNode);
00712 }
00713 void FEM_Adapt_Algs::refine_flip_element_leb(int e, int p, int n1, int n2,
00714 double le)
00715 {
00716 int newNode = refine_element_leb(e);
00717 if(newNode == -1) return;
00718 (void) theAdaptor->edge_flip(n1, n2);
00719 if (length(p, newNode) > le) {
00720 int localChk = theMod->getfmUtil()->getIdx();
00721 int newElem = theAdaptor->findElementWithNodes(newNode, n1, p);
00722 refine_flip_element_leb(newElem, p, n1, newNode, le);
00723 }
00724 }
00725
00726
00727
00728
00729 double FEM_Adapt_Algs::length(int n1, int n2)
00730 {
00731 double *n1_coord = (double*)malloc(dim*sizeof(double));
00732 double *n2_coord = (double*)malloc(dim*sizeof(double));
00733
00734 getCoord(n1, n1_coord);
00735 getCoord(n2, n2_coord);
00736
00737 double ret = length(n1_coord, n2_coord);
00738
00739 free(n1_coord);
00740 free(n2_coord);
00741 return ret;
00742 }
00743
00744 double FEM_Adapt_Algs::length(double *n1_coord, double *n2_coord) {
00745 double d, ds_sum=0.0;
00746
00747 for (int i=0; i<dim; i++) {
00748 d = n1_coord[i] - n2_coord[i];
00749 ds_sum += d*d;
00750 }
00751 return (sqrt(ds_sum));
00752 }
00753
00754
00755 double FEM_Adapt_Algs::getArea(int n1, int n2, int n3)
00756 {
00757 double *n1_coord = (double*)malloc(dim*sizeof(double));
00758 double *n2_coord = (double*)malloc(dim*sizeof(double));
00759 double *n3_coord = (double*)malloc(dim*sizeof(double));
00760
00761 getCoord(n1, n1_coord);
00762 getCoord(n2, n2_coord);
00763 getCoord(n3, n3_coord);
00764
00765 double ret = getArea(n1_coord, n2_coord, n3_coord);
00766
00767 free(n1_coord);
00768 free(n2_coord);
00769 free(n3_coord);
00770 return ret;
00771 }
00772
00773 double FEM_Adapt_Algs::getArea(double *n1_coord, double *n2_coord, double *n3_coord) {
00774 double area=0.0;
00775 double aLen, bLen, cLen, sLen, d, ds_sum;
00776
00777 ds_sum = 0.0;
00778 for (int i=0; i<2; i++) {
00779 d = n1_coord[i] - n2_coord[i];
00780 ds_sum += d*d;
00781 }
00782 aLen = sqrt(ds_sum);
00783 ds_sum = 0.0;
00784 for (int i=0; i<2; i++) {
00785 d = n2_coord[i] - n3_coord[i];
00786 ds_sum += d*d;
00787 }
00788 bLen = sqrt(ds_sum);
00789 ds_sum = 0.0;
00790 for (int i=0; i<2; i++) {
00791 d = n3_coord[i] - n1_coord[i];
00792 ds_sum += d*d;
00793 }
00794 cLen = sqrt(ds_sum);
00795 sLen = (aLen+bLen+cLen)/2;
00796 if(sLen-aLen < 0) return 0.0;
00797 else if(sLen-bLen < 0) return 0.0;
00798 else if(sLen-cLen < 0) return 0.0;
00799 return (sqrt(sLen*(sLen-aLen)*(sLen-bLen)*(sLen-cLen)));
00800 }
00801
00802 bool FEM_Adapt_Algs::didItFlip(int n1, int n2, int n3, double *n4_coord)
00803 {
00804
00805 double *n1_coord = (double*)malloc(dim*sizeof(double));
00806 double *n2_coord = (double*)malloc(dim*sizeof(double));
00807 double *n3_coord = (double*)malloc(dim*sizeof(double));
00808
00809 getCoord(n1, n1_coord);
00810 getCoord(n2, n2_coord);
00811 getCoord(n3, n3_coord);
00812
00813 double ret_old = getSignedArea(n1_coord, n2_coord, n3_coord);
00814 double ret_new = getSignedArea(n1_coord, n2_coord, n4_coord);
00815
00816 free(n1_coord);
00817 free(n2_coord);
00818 free(n3_coord);
00819
00820 if(ret_old > SLIVERAREA && ret_new < -SLIVERAREA) return true;
00821 else if(ret_old < -SLIVERAREA && ret_new > SLIVERAREA) return true;
00822 else if(fabs(ret_new) < SLIVERAREA) return true;
00823 else return false;
00824 }
00825
00826
00827 bool FEM_Adapt_Algs::didItFlip(double *n1_coord, double *n2_coord, double *n3_coord, double *n4_coord)
00828 {
00829 double ret_old = getSignedArea(n1_coord, n2_coord, n3_coord);
00830 double ret_new = getSignedArea(n1_coord, n2_coord, n4_coord);
00831 if(ret_old > MINAREA && ret_new < -MINAREA) return true;
00832 else if(ret_old < -MINAREA && ret_new > MINAREA) return true;
00833 else return false;
00834 }
00835
00836 double FEM_Adapt_Algs::getSignedArea(double *n1_coord, double *n2_coord, double *n3_coord) {
00837 double area=0.0;
00838 double vec1_x, vec1_y, vec2_x, vec2_y;
00839
00840 vec1_x = n1_coord[0] - n2_coord[0];
00841 vec1_y = n1_coord[1] - n2_coord[1];
00842 vec2_x = n3_coord[0] - n2_coord[0];
00843 vec2_y = n3_coord[1] - n2_coord[1];
00844
00845 area = vec1_x*vec2_y - vec2_x*vec1_y;
00846 return area;
00847 }
00848
00849 int FEM_Adapt_Algs::getCoord(int n1, double *crds) {
00850 if(!FEM_Is_ghost_index(n1)) {
00851 FEM_Mesh_dataP(theMesh, FEM_NODE, coord_attr, (void *)crds, n1, 1, FEM_DOUBLE, dim);
00852 }
00853 else {
00854 int numchunks;
00855 IDXL_Share **chunks1;
00856 theMod->fmUtil->getChunkNos(0,n1,&numchunks,&chunks1);
00857 int index = theMod->idx;
00858 for(int j=0; j<numchunks; j++) {
00859 int chk = chunks1[j]->chk;
00860 if(chk==index) continue;
00861 int ghostidx = theMod->fmUtil->exists_in_IDXL(theMesh,n1,chk,2);
00862 double2Msg *d = meshMod[chk].getRemoteCoord(index,ghostidx);
00863 crds[0] = d->i;
00864 crds[1] = d->j;
00865 for(int j=0; j<numchunks; j++) {
00866 delete chunks1[j];
00867 }
00868 if(numchunks != 0) free(chunks1);
00869 break;
00870 }
00871 }
00872 return 1;
00873 }
00874
00875 int FEM_Adapt_Algs::getShortestEdge(int n1, int n2, int n3, int* shortestEdge) {
00876 double *n1_coord = (double*)malloc(dim*sizeof(double));
00877 double *n2_coord = (double*)malloc(dim*sizeof(double));
00878 double *n3_coord = (double*)malloc(dim*sizeof(double));
00879
00880 getCoord(n1, n1_coord);
00881 getCoord(n2, n2_coord);
00882 getCoord(n3, n3_coord);
00883
00884 double aLen = length(n1_coord, n2_coord);
00885 int shortest = 0;
00886
00887 double bLen = length(n2_coord, n3_coord);
00888 if(bLen < aLen) shortest = 1;
00889
00890 double cLen = length(n3_coord, n1_coord);
00891 if((cLen < aLen) && (cLen < bLen)) shortest = 2;
00892
00893 if(shortest==0) {
00894 shortestEdge[0] = n1;
00895 shortestEdge[1] = n2;
00896 }
00897 else if (shortest==1) {
00898 shortestEdge[0] = n2;
00899 shortestEdge[1] = n3;
00900 }
00901 else {
00902 shortestEdge[0] = n3;
00903 shortestEdge[1] = n1;
00904 }
00905 free(n1_coord);
00906 free(n2_coord);
00907 free(n3_coord);
00908 return 1;
00909 }
00910
00911
00912 void FEM_Adapt_Algs::Insert(int eIdx, double len, int cFlag)
00913 {
00914 int i;
00915 if (cFlag) {
00916 i = ++coarsenHeapSize;
00917 while ((coarsenElements[i/2].len>=len) && (i != 1)) {
00918 coarsenElements[i].len=coarsenElements[i/2].len;
00919 coarsenElements[i].elID=coarsenElements[i/2].elID;
00920 i/=2;
00921 }
00922 coarsenElements[i].elID=eIdx;
00923 coarsenElements[i].len=len;
00924 }
00925 else {
00926 i = ++refineHeapSize;
00927 while ((refineElements[i/2].len>=len) && (i != 1)) {
00928 refineElements[i].len=refineElements[i/2].len;
00929 refineElements[i].elID=refineElements[i/2].elID;
00930 i/=2;
00931 }
00932 refineElements[i].elID=eIdx;
00933 refineElements[i].len=len;
00934 }
00935 }
00936
00937
00938 int FEM_Adapt_Algs::Delete_Min(int cflag)
00939 {
00940 int Child, i, Min_ID;
00941 if (cflag) {
00942 Min_ID=coarsenElements[1].elID;
00943 for (i=1; i*2 <= coarsenHeapSize-1; i=Child) {
00944 Child = i*2;
00945 if (Child != coarsenHeapSize)
00946 if (coarsenElements[Child+1].len < coarsenElements[Child].len)
00947 Child++;
00948
00949 if (coarsenElements[coarsenHeapSize].len >= coarsenElements[Child].len) {
00950 coarsenElements[i].elID = coarsenElements[Child].elID;
00951 coarsenElements[i].len = coarsenElements[Child].len;
00952 }
00953 else break;
00954 }
00955 coarsenElements[i].elID = coarsenElements[coarsenHeapSize].elID;
00956 coarsenElements[i].len = coarsenElements[coarsenHeapSize].len;
00957 coarsenHeapSize--;
00958 return Min_ID;
00959 }
00960 else {
00961 Min_ID=refineElements[1].elID;
00962 for (i=1; i*2 <= refineHeapSize-1; i=Child) {
00963 Child = i*2;
00964 if (Child !=refineHeapSize)
00965 if (refineElements[Child+1].len < refineElements[Child].len)
00966 Child++;
00967
00968 if (refineElements[refineHeapSize].len >= refineElements[Child].len){
00969 refineElements[i].elID = refineElements[Child].elID;
00970 refineElements[i].len = refineElements[Child].len;
00971 }
00972 else break;
00973 }
00974 refineElements[i].elID = refineElements[refineHeapSize].elID;
00975 refineElements[i].len = refineElements[refineHeapSize].len;
00976 refineHeapSize--;
00977 return Min_ID;
00978 }
00979 }
00980
00981 double FEM_Adapt_Algs::getAreaQuality(int elem)
00982 {
00983 double f, q, len[3];
00984 int n[3];
00985 double currentArea;
00986 double *n1_coord = (double*)malloc(dim*sizeof(double));
00987 double *n2_coord = (double*)malloc(dim*sizeof(double));
00988 double *n3_coord = (double*)malloc(dim*sizeof(double));
00989 theMesh->e2n_getAll(elem, n);
00990 getCoord(n[0], n1_coord);
00991 getCoord(n[1], n2_coord);
00992 getCoord(n[2], n3_coord);
00993
00994 currentArea = getArea(n1_coord, n2_coord, n3_coord);
00995
00996 len[0] = length(n1_coord, n2_coord);
00997 len[1] = length(n2_coord, n3_coord);
00998 len[2] = length(n3_coord, n1_coord);
00999 f = 4.0*sqrt(3.0);
01000 q = (f*currentArea)/(len[0]*len[0]+len[1]*len[1]+len[2]*len[2]);
01001 return q;
01002 }
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015 void FEM_Adapt_Algs::FEM_mesh_smooth(FEM_Mesh *meshP, int *nodes, int nNodes, int attrNo) {
01016 vector2d newPos, *coords, *ghostCoords;
01017 int idx, nNod, nGn, gIdxN, *boundVals, nodesInChunk, mesh;
01018 int *adjnodes;
01019
01020 mesh=FEM_Mesh_default_read();
01021 nodesInChunk = FEM_Mesh_get_length(mesh,FEM_NODE);
01022 nGn = FEM_Mesh_get_length(mesh, FEM_GHOST + FEM_NODE);
01023
01024 boundVals = new int[nodesInChunk];
01025 coords = new vector2d[nodesInChunk+nGn];
01026
01027 FEM_Mesh_data(mesh, FEM_NODE, FEM_BOUNDARY, (int*) boundVals, 0, nodesInChunk, FEM_INT, 1);
01028
01029 FEM_Mesh_data(mesh, FEM_NODE, attrNo, (double*)coords, 0, nodesInChunk, FEM_DOUBLE, 2);
01030
01031 IDXL_Layout_t coord_layout = IDXL_Layout_create(IDXL_DOUBLE, 2);
01032 FEM_Update_ghost_field(coord_layout,-1, coords);
01033 ghostCoords = &(coords[nodesInChunk]);
01034 for (int i=0; i<nNodes; i++)
01035 {
01036 if (nodes==NULL) idx=i;
01037 else idx=nodes[i];
01038 newPos.x=0;
01039 newPos.y=0;
01040 CkAssert(idx<nodesInChunk);
01041 if (FEM_is_valid(mesh, FEM_NODE, idx) && boundVals[idx]==0)
01042 {
01043 meshP->n2n_getAll(idx, &adjnodes, &nNod);
01044 for (int j=0; j<nNod; j++) {
01045 if (adjnodes[j]<-1) {
01046 gIdxN = FEM_From_ghost_index(adjnodes[j]);
01047 newPos.x += ghostCoords[gIdxN].x;
01048 newPos.y += ghostCoords[gIdxN].y;
01049 }
01050 else {
01051 newPos.x += coords[adjnodes[j]].x;
01052 newPos.y += coords[adjnodes[j]].y;
01053 }
01054 }
01055 newPos.x/=nNod;
01056 newPos.y/=nNod;
01057 FEM_set_entity_coord2(mesh, FEM_NODE, idx, newPos.x, newPos.y);
01058 delete [] adjnodes;
01059 }
01060 }
01061
01062 delete [] coords;
01063 delete [] boundVals;
01064 }
01065