• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

src/fem/vpee.c

Go to the documentation of this file.
00001 
00050 #include "apbscfg.h"
00051 
00052 #if defined(HAVE_MC_H)
00053 #if defined(HAVE_MCX_H)
00054 
00055 #include "mc/mc.h"
00056 #include "apbs/vpee.h"
00057 
00058 VPRIVATE int Vpee_userDefined(Vpee *thee, SS *sm);
00059 VPRIVATE int Vpee_ourSimp(Vpee *thee, SS *sm, int rcol);
00060 VEXTERNC double Aprx_estNonlinResid(Aprx *thee, SS *sm,
00061     Bvec *u, Bvec *ud, Bvec *f);
00062 VEXTERNC double Aprx_estLocalProblem(Aprx *thee, SS *sm,
00063     Bvec *u, Bvec *ud, Bvec *f);
00064 VEXTERNC double Aprx_estDualProblem(Aprx *thee, SS *sm,
00065     Bvec *u, Bvec *ud, Bvec *f);
00066 
00067 /* ///////////////////////////////////////////////////////////////////////////
00068 // Class Vpee: Non-inlineable methods
00070 
00071 /* ///////////////////////////////////////////////////////////////////////////
00072 // Routine:  Vpee_ctor
00073 //
00074 // Author:   Nathan Baker
00076 VPUBLIC Vpee* Vpee_ctor(Gem *gm, int localPartID, int killFlag, double
00077   killParam) {
00078 
00079     Vpee *thee = VNULL;
00080 
00081     /* Set up the structure */
00082     thee = Vmem_malloc(VNULL, 1, sizeof(Vpee) );
00083     VASSERT( thee != VNULL);
00084     VASSERT( Vpee_ctor2(thee, gm, localPartID, killFlag, killParam));
00085 
00086     return thee;
00087 }
00088 
00089 /* ///////////////////////////////////////////////////////////////////////////
00090 // Routine:  Vpee_ctor2
00091 //
00092 // Author:   Nathan Baker
00094 VPUBLIC int Vpee_ctor2(Vpee *thee, Gem *gm, int localPartID, int killFlag,
00095   double killParam) {
00096 
00097     int ivert, nLocalVerts;
00098     SS *simp;
00099     VV *vert;
00100     double radius, dx, dy, dz;
00101 
00102     VASSERT(thee != VNULL);
00103 
00104     /* Sanity check on input values */
00105     if (killFlag == 0) {
00106         Vnm_print(0, "Vpee_ctor2: No error attenuation outside partition.\n");
00107     } else if (killFlag == 1) {
00108         Vnm_print(0, "Vpee_ctor2: Error outside local partition ignored.\n");
00109     } else if (killFlag == 2) {
00110         Vnm_print(0, "Vpee_ctor2: Error ignored outside sphere with radius %4.3f times the radius of the circumscribing sphere\n", killParam);
00111         if (killParam < 1.0) {
00112           Vnm_print(2, "Vpee_ctor2: Warning! Parameter killParam = %4.3 < 1.0!\n",
00113             killParam);
00114           Vnm_print(2, "Vpee_ctor2: This may result in non-optimal marking and refinement!\n");
00115         }
00116     } else if (killFlag == 3) {
00117         Vnm_print(0, "Vpee_ctor2: Error outside local partition and immediate neighbors ignored [NOT IMPLEMENTED].\n");
00118     } else {
00119         Vnm_print(2, "Vpee_ctor2: UNRECOGNIZED killFlag PARAMETER! BAILING!.\n");
00120         VASSERT(0);
00121     }
00122 
00123     thee->gm = gm;
00124     thee->localPartID = localPartID;
00125     thee->killFlag = killFlag;
00126     thee->killParam = killParam;
00127     thee->mem = Vmem_ctor("APBS::VPEE");
00128 
00129     /* Now, figure out the center of geometry for the local partition.  The
00130      * general plan is to loop through the vertices, loop through the
00131      * vertices' simplex lists and find the vertices with simplices containing
00132      * chart values we're interested in. */
00133     thee->localPartCenter[0] = 0.0;
00134     thee->localPartCenter[1] = 0.0;
00135     thee->localPartCenter[2] = 0.0;
00136     nLocalVerts = 0;
00137     for (ivert=0; ivert<Gem_numVV(thee->gm); ivert++) {
00138         vert = Gem_VV(thee->gm, ivert);
00139         simp = VV_firstSS(vert);
00140         VASSERT(simp != VNULL);
00141         while (simp != VNULL) {
00142             if (SS_chart(simp) == thee->localPartID) {
00143                 thee->localPartCenter[0] += VV_coord(vert, 0);
00144                 thee->localPartCenter[1] += VV_coord(vert, 1);
00145                 thee->localPartCenter[2] += VV_coord(vert, 2);
00146                 nLocalVerts++;
00147                 break;
00148             }
00149             simp = SS_link(simp, vert);
00150         }
00151     }
00152     VASSERT(nLocalVerts > 0);
00153     thee->localPartCenter[0] =
00154       thee->localPartCenter[0]/((double)(nLocalVerts));
00155     thee->localPartCenter[1] =
00156       thee->localPartCenter[1]/((double)(nLocalVerts));
00157     thee->localPartCenter[2] =
00158       thee->localPartCenter[2]/((double)(nLocalVerts));
00159     Vnm_print(0, "Vpee_ctor2: Part %d centered at (%4.3f, %4.3f, %4.3f)\n",
00160       thee->localPartID, thee->localPartCenter[0], thee->localPartCenter[1],
00161       thee->localPartCenter[2]);
00162 
00163 
00164     /* Now, figure out the radius of the sphere circumscribing the local
00165      * partition.  We need to keep track of vertices so we don't double count
00166      * them. */
00167     thee->localPartRadius = 0.0;
00168     for (ivert=0; ivert<Gem_numVV(thee->gm); ivert++) {
00169         vert = Gem_VV(thee->gm, ivert);
00170         simp = VV_firstSS(vert);
00171         VASSERT(simp != VNULL);
00172         while (simp != VNULL) {
00173             if (SS_chart(simp) == thee->localPartID) {
00174                 dx = thee->localPartCenter[0] - VV_coord(vert, 0);
00175                 dy = thee->localPartCenter[1] - VV_coord(vert, 1);
00176                 dz = thee->localPartCenter[2] - VV_coord(vert, 2);
00177                 radius = dx*dx + dy*dy + dz*dz;
00178                 if (radius > thee->localPartRadius) thee->localPartRadius =
00179                   radius;
00180                 break;
00181             }
00182             simp = SS_link(simp, vert);
00183         }
00184     }
00185     thee->localPartRadius = VSQRT(thee->localPartRadius);
00186     Vnm_print(0, "Vpee_ctor2: Part %d has circumscribing sphere of radius %4.3f\n",
00187       thee->localPartID, thee->localPartRadius);
00188 
00189     return 1;
00190 }
00191 
00192 /* ///////////////////////////////////////////////////////////////////////////
00193 // Routine:  Vpee_dtor
00194 //
00195 // Author:   Nathan Baker
00197 VPUBLIC void Vpee_dtor(Vpee **thee) {
00198 
00199     if ((*thee) != VNULL) {
00200         Vpee_dtor2(*thee);
00201         Vmem_free(VNULL, 1, sizeof(Vpee), (void **)thee);
00202         (*thee) = VNULL;
00203     }
00204 
00205 }
00206 
00207 /* ///////////////////////////////////////////////////////////////////////////
00208 // Routine:  Vpee_dtor2
00209 //
00210 // Author:   Nathan Baker
00212 VPUBLIC void Vpee_dtor2(Vpee *thee) { Vmem_dtor(&(thee->mem)); }
00213 
00214 /* ///////////////////////////////////////////////////////////////////////////
00215 // Routine:  Vpee_markRefine
00216 //
00217 // Author:   Nathan Baker (and Michael Holst: the author of AM_markRefine, on
00218 //           which this is based)
00220 VPUBLIC int Vpee_markRefine(Vpee *thee, AM *am, int level, int akey, int rcol,
00221   double etol, int bkey) {
00222 
00223     Aprx *aprx;
00224     int marked = 0;
00225     int markMe, i, smid, count, currentQ;
00226     double minError = 0.0;
00227     double maxError = 0.0;
00228     double errEst = 0.0;
00229     double mlevel, barrier;
00230     SS *sm;
00231 
00232 
00233     VASSERT(thee != VNULL);
00234 
00235     /* Get the Aprx object from AM */
00236     aprx = am->aprx;
00237 
00238     /* input check and some i/o */
00239     if ( ! ((-1 <= akey) && (akey <= 4)) ) {
00240         Vnm_print(0,"Vpee_markRefine: bad refine key; simplices marked = %d\n",
00241             marked);
00242         return marked;
00243     }
00244 
00245     /* For uniform markings, we have no effect */
00246     if ((-1 <= akey) && (akey <= 0)) {
00247         marked = Gem_markRefine(thee->gm, akey, rcol);
00248         return marked;
00249     }
00250 
00251     /* Informative I/O */
00252     if (akey == 2) {
00253         Vnm_print(0,"Vpee_estRefine: using Aprx_estNonlinResid().\n");
00254     } else if (akey == 3) {
00255         Vnm_print(0,"Vpee_estRefine: using Aprx_estLocalProblem().\n");
00256     } else if (akey == 4) {
00257         Vnm_print(0,"Vpee_estRefine: using Aprx_estDualProblem().\n");
00258     } else {
00259         Vnm_print(0,"Vpee_estRefine: bad key given; simplices marked = %d\n",
00260             marked);
00261         return marked;
00262     }
00263     if (thee->killFlag == 0) {
00264         Vnm_print(0, "Vpee_markRefine: No error attenuation -- simplices in all partitions will be marked.\n");
00265     } else if (thee->killFlag == 1) {
00266         Vnm_print(0, "Vpee_markRefine: Maximum error attenuation -- only simplices in local partition will be marked.\n");
00267     } else if (thee->killFlag == 2) {
00268         Vnm_print(0, "Vpee_markRefine: Spherical error attenutation -- simplices within a sphere of %4.3f times the size of the partition will be marked\n",
00269           thee->killParam);
00270     } else if (thee->killFlag == 2) {
00271         Vnm_print(0, "Vpee_markRefine: Neighbor-based error attenuation -- simplices in the local and neighboring partitions will be marked [NOT IMPLEMENTED]!\n");
00272         VASSERT(0);
00273     } else {
00274         Vnm_print(2,"Vpee_markRefine: bogus killFlag given; simplices marked = %d\n",
00275             marked);
00276         return marked;
00277     }
00278 
00279     /* set the barrier type */
00280     mlevel = (etol*etol) / Gem_numSS(thee->gm);
00281     if (bkey == 0) {
00282         barrier = (etol*etol);
00283         Vnm_print(0,"Vpee_estRefine: forcing [err per S] < [TOL] = %g\n",
00284             barrier);
00285     } else if (bkey == 1) {
00286         barrier = mlevel;
00287         Vnm_print(0,"Vpee_estRefine: forcing [err per S] < [(TOL^2/numS)^{1/2}] = %g\n",
00288             VSQRT(barrier));
00289     } else {
00290         Vnm_print(0,"Vpee_estRefine: bad bkey given; simplices marked = %d\n",
00291             marked);
00292         return marked;
00293     }
00294 
00295     /* timer */
00296     Vnm_tstart(30, "error estimation");
00297 
00298     /* count = num generations to produce from marked simplices (minimally) */
00299     count = 1; /* must be >= 1 */
00300 
00301     /* check the refinement Q for emptyness */
00302     currentQ = 0;
00303     if (Gem_numSQ(thee->gm,currentQ) > 0) {
00304         Vnm_print(0,"Vpee_markRefine: non-empty refinement Q%d....clearing..",
00305             currentQ);
00306         Gem_resetSQ(thee->gm,currentQ);
00307         Vnm_print(0,"..done.\n");
00308     }
00309     if (Gem_numSQ(thee->gm,!currentQ) > 0) {
00310         Vnm_print(0,"Vpee_markRefine: non-empty refinement Q%d....clearing..",
00311             !currentQ);
00312         Gem_resetSQ(thee->gm,!currentQ);
00313         Vnm_print(0,"..done.\n");
00314     }
00315     VASSERT( Gem_numSQ(thee->gm,currentQ)  == 0 );
00316     VASSERT( Gem_numSQ(thee->gm,!currentQ) == 0 );
00317 
00318     /* clear everyone's refinement flags */
00319     Vnm_print(0,"Vpee_markRefine: clearing all simplex refinement flags..");
00320     for (i=0; i<Gem_numSS(thee->gm); i++) {
00321         if ( (i>0) && (i % VPRTKEY) == 0 ) Vnm_print(0,"[MS:%d]",i);
00322         sm = Gem_SS(thee->gm,i);
00323         SS_setRefineKey(sm,currentQ,0);
00324         SS_setRefineKey(sm,!currentQ,0);
00325         SS_setRefinementCount(sm,0);
00326     }
00327     Vnm_print(0,"..done.\n");
00328 
00329     /* NON-ERROR-BASED METHODS */
00330     /* Simplex flag clearing */
00331     if (akey == -1) return marked;
00332     /* Uniform & user-defined refinement*/
00333     if ((akey == 0) || (akey == 1)) {
00334         smid = 0;
00335         while ( smid < Gem_numSS(thee->gm)) {
00336             /* Get the simplex and find out if it's markable */
00337             sm = Gem_SS(thee->gm,smid);
00338             markMe = Vpee_ourSimp(thee, sm, rcol);
00339             if (markMe) {
00340                 if (akey == 0) {
00341                     marked++;
00342                     Gem_appendSQ(thee->gm,currentQ, sm);
00343                     SS_setRefineKey(sm,currentQ,1);
00344                     SS_setRefinementCount(sm,count);
00345                 } else if (Vpee_userDefined(thee, sm)) {
00346                     marked++;
00347                     Gem_appendSQ(thee->gm,currentQ, sm);
00348                     SS_setRefineKey(sm,currentQ,1);
00349                     SS_setRefinementCount(sm,count);
00350                 }
00351             }
00352             smid++;
00353         }
00354     }
00355 
00356     /* ERROR-BASED METHODS */
00357     /* gerror = global error accumulation */
00358     aprx->gerror = 0.;
00359 
00360     /* traverse the simplices and process the error estimates */
00361     Vnm_print(0,"Vpee_markRefine: estimating error..");
00362     smid = 0;
00363     while ( smid < Gem_numSS(thee->gm)) {
00364 
00365         /* Get the simplex and find out if it's markable */
00366         sm = Gem_SS(thee->gm,smid);
00367         markMe = Vpee_ourSimp(thee, sm, rcol);
00368 
00369         if ( (smid>0) && (smid % VPRTKEY) == 0 ) Vnm_print(0,"[MS:%d]",smid);
00370 
00371         /* Produce an error estimate for this element if it is in the set */
00372         if (markMe) {
00373             if (akey == 2) {
00374                 errEst = Aprx_estNonlinResid(aprx, sm, am->u,am->ud,am->f);
00375             } else if (akey == 3) {
00376                 errEst = Aprx_estLocalProblem(aprx, sm, am->u,am->ud,am->f);
00377             } else if (akey == 4) {
00378                 errEst = Aprx_estDualProblem(aprx, sm, am->u,am->ud,am->f);
00379             }
00380             VASSERT( errEst >= 0. );
00381 
00382             /* if error estimate above tol, mark element for refinement */
00383             if ( errEst > barrier ) {
00384                 marked++;
00385                 Gem_appendSQ(thee->gm,currentQ, sm); /*add to refinement Q*/
00386                 SS_setRefineKey(sm,currentQ,1);      /* note now on refine Q */
00387                 SS_setRefinementCount(sm,count);     /* refine X many times? */
00388             }
00389 
00390             /* keep track of min/max errors over the mesh */
00391             minError = VMIN2( VSQRT(VABS(errEst)), minError );
00392             maxError = VMAX2( VSQRT(VABS(errEst)), maxError );
00393 
00394             /* store the estimate */
00395             Bvec_set( aprx->wev, smid, errEst );
00396 
00397             /* accumlate into global error (errEst is SQUAREd already) */
00398             aprx->gerror += errEst;
00399 
00400         /* otherwise store a zero for the estimate */
00401         } else {
00402             Bvec_set( aprx->wev, smid, 0. );
00403         }
00404 
00405         smid++;
00406     }
00407 
00408     /* do some i/o */
00409     Vnm_print(0,"..done.  [marked=<%d/%d>]\n",marked,Gem_numSS(thee->gm));
00410     Vnm_print(0,"Vpee_estRefine: TOL=<%g>  Global_Error=<%g>\n",
00411         etol, aprx->gerror);
00412     Vnm_print(0,"Vpee_estRefine: (TOL^2/numS)^{1/2}=<%g>  Max_Ele_Error=<%g>\n",
00413         VSQRT(mlevel),maxError);
00414     Vnm_tstop(30, "error estimation");
00415 
00416     /* check for making the error tolerance */
00417     if ((bkey == 1) && (aprx->gerror <= etol)) {
00418         Vnm_print(0,
00419             "Vpee_estRefine: *********************************************\n");
00420         Vnm_print(0,
00421             "Vpee_estRefine: Global Error criterion met; setting marked=0.\n");
00422         Vnm_print(0,
00423             "Vpee_estRefine: *********************************************\n");
00424         marked = 0;
00425     }
00426 
00427 
00428     /* return */
00429     return marked;
00430 
00431 }
00432 
00433 /* ///////////////////////////////////////////////////////////////////////////
00434 // Routine:  Vpee_numSS
00435 //
00436 // Author:   Nathan Baker
00438 VPUBLIC int Vpee_numSS(Vpee *thee) {
00439     int num = 0;
00440     int isimp;
00441 
00442     for (isimp=0; isimp<Gem_numSS(thee->gm); isimp++) {
00443         if (SS_chart(Gem_SS(thee->gm, isimp)) == thee->localPartID) num++;
00444     }
00445 
00446     return num;
00447 }
00448 
00449 /* ///////////////////////////////////////////////////////////////////////////
00450 // Routine:  Vpee_userDefined
00451 //
00452 // Purpose:  Reduce code bloat by wrapping up the common steps for getting the
00453 //           user-defined error estimate
00454 //
00455 // Author:   Nathan Baker
00457 VPRIVATE int Vpee_userDefined(Vpee *thee, SS *sm) {
00458 
00459     int ivert, icoord, chart[4], fType[4], vType[4];
00460     double vx[4][3];
00461 
00462     for (ivert=0; ivert<Gem_dimVV(thee->gm); ivert++) {
00463         fType[ivert] = SS_faceType(sm,ivert);
00464         vType[ivert] = VV_type(SS_vertex(sm,ivert) );
00465         chart[ivert] = VV_chart(SS_vertex(sm,ivert) );
00466         for (icoord=0; icoord<Gem_dimII(thee->gm); icoord++) {
00467             vx[ivert][icoord] = VV_coord(SS_vertex(sm,ivert), icoord );
00468         }
00469     }
00470     return thee->gm->pde->markSimplex(Gem_dim(thee->gm), Gem_dimII(thee->gm),
00471              SS_type(sm), fType, vType, chart, vx, sm);
00472 }
00473 
00474 /* ///////////////////////////////////////////////////////////////////////////
00475 // Routine:  Vpee_ourSimp
00476 //
00477 // Purpose:  Reduce code bloat by wrapping up the common steps for determining
00478 //           whether the given simplex can be marked (i.e., belongs to our
00479 //           partition or overlap region)
00480 //
00481 // Returns:  1 if could be marked, 0 otherwise
00482 //
00483 // Author:   Nathan Baker
00485 VPRIVATE int Vpee_ourSimp(Vpee *thee, SS *sm, int rcol) {
00486 
00487     int ivert;
00488     double dist, dx, dy, dz;
00489 
00490     if (thee->killFlag == 0) return 1;
00491     else if (thee->killFlag == 1) {
00492         if ((SS_chart(sm) == rcol) || (rcol < 0)) return 1;
00493     } else if (thee->killFlag == 2) {
00494         if (rcol < 0) return 1;
00495         else {
00496             /* We can only do distance-based searches on the local partition */
00497             VASSERT(rcol == thee->localPartID);
00498             /* Find the closest distance between this simplex and the
00499              * center of the local partition and check it against
00500              * (thee->localPartRadius*thee->killParam) */
00501             dist = 0;
00502             for (ivert=0; ivert<SS_dimVV(sm); ivert++) {
00503                 dx = VV_coord(SS_vertex(sm, ivert), 0) -
00504                   thee->localPartCenter[0];
00505                 dy = VV_coord(SS_vertex(sm, ivert), 1) -
00506                   thee->localPartCenter[1];
00507                 dz = VV_coord(SS_vertex(sm, ivert), 2) -
00508                   thee->localPartCenter[2];
00509                 dist = VSQRT((dx*dx + dy*dy + dz*dz));
00510             }
00511             if (dist < thee->localPartRadius*thee->killParam) return 1;
00512         }
00513     } else if (thee->killFlag == 3) VASSERT(0);
00514     else VASSERT(0);
00515 
00516     return 0;
00517 
00518 }
00519 
00520 #endif 
00521 #endif

Generated on Wed Oct 20 2010 12:01:33 for APBS by  doxygen 1.7.2