moab
CslamUtils.cpp
Go to the documentation of this file.
00001 /*
00002  * CslamUtils.cpp
00003  *
00004  *  Created on: Oct 3, 2012
00005  *      Author: iulian
00006  */
00007 
00008 #include "CslamUtils.hpp"
00009 #include <math.h>
00010 // this is from mbcoupler; maybe it should be moved somewhere in moab src
00011 // right now, add a dependency to mbcoupler
00012 // #include "ElemUtil.hpp"
00013 #include "moab/MergeMesh.hpp"
00014 #include "moab/ReadUtilIface.hpp"
00015 #include <iostream>
00016 // this is for sstream
00017 #include <sstream>
00018 
00019 #include <queue>
00020 
00021 namespace moab {
00022 // vec utilities that could be common between quads on a plane or sphere
00023 double dist2(double * a, double * b)
00024 {
00025   double abx = b[0] - a[0], aby = b[1] - a[1];
00026   return sqrt(abx * abx + aby * aby);
00027 }
00028 double area2D(double *a, double *b, double *c)
00029 {
00030   // (b-a)x(c-a) / 2
00031   return ((b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0])) / 2;
00032 }
00033 int borderPointsOfXinY2(double * X, int nX, double * Y, int nY, double * P, int side[MAXEDGES], double epsilon_area)
00034 {
00035   // 2 triangles, 3 corners, is the corner of X in Y?
00036   // Y must have a positive area
00037   /*
00038    */
00039   int extraPoint = 0;
00040   for (int i = 0; i < nX; i++)
00041   {
00042     // compute twice the area of all nY triangles formed by a side of Y and a corner of X; if one is negative, stop
00043     // (negative means it is outside; X and Y are all oriented such that they are positive oriented;
00044     //  if one area is negative, it means it is outside the convex region, for sure)
00045     double * A = X + 2 * i;
00046 
00047     int inside = 1;
00048     for (int j = 0; j < nY; j++)
00049     {
00050       double * B = Y + 2 * j;
00051 
00052       int j1 = (j + 1) % nY;
00053       double * C = Y + 2 * j1; // no copy of data
00054 
00055       double area2 = (B[0] - A[0]) * (C[1] - A[1])
00056           - (C[0] - A[0]) * (B[1] - A[1]);
00057       if (area2 < -epsilon_area)
00058       {
00059         inside = 0;
00060         break;
00061       }
00062     }
00063     if (inside)
00064     {
00065       side[i] = 1;// so vertex i of X is inside the convex region formed by Y
00066       // so side has nX dimension (first array)
00067       P[extraPoint * 2] = A[0];
00068       P[extraPoint * 2 + 1] = A[1];
00069       extraPoint++;
00070     }
00071   }
00072   return extraPoint;
00073 }
00074 
00075 int swap2(double * p, double * q)
00076 {
00077   double tmp = *p;
00078   *p = *q;
00079   *q = tmp;
00080   return 0;
00081 }
00082 int SortAndRemoveDoubles2(double * P, int & nP, double epsilon_1)
00083 {
00084   if (nP < 2)
00085     return 0; // nothing to do
00086   // center of gravity for the points
00087   double c[2] = { 0., 0. };
00088   int k = 0;
00089   for (k = 0; k < nP; k++)
00090   {
00091     c[0] += P[2 * k];
00092     c[1] += P[2 * k + 1];
00093   }
00094   c[0] /= nP;
00095   c[1] /= nP;
00096   // how many
00097   std::vector<double> angle(nP); // could be at most nP points
00098   for (k = 0; k < nP; k++)
00099   {
00100     double x = P[2 * k] - c[0], y = P[2 * k + 1] - c[1];
00101     if (x != 0. || y != 0.)
00102       angle[k] = atan2(y, x);
00103     else
00104     {
00105       angle[k] = 0;
00106       // this means that the points are on a line, or all coincident // degenerate case
00107     }
00108   }
00109   // sort according to angle; also eliminate close points
00110   // this is a bubble sort, for np = 24 it could be pretty big
00111   // maybe a better sort is needed here (qsort?)
00112   int sorted = 1;
00113   do
00114   {
00115     sorted = 1;
00116     for (k = 0; k < nP - 1; k++)
00117     {
00118       if (angle[k] > angle[k + 1])
00119       {
00120         sorted = 0;
00121         swap2(&angle[k], &angle[k+1]);
00122         swap2(P + (2 * k), P + (2 * k + 2));
00123         swap2(P + (2 * k + 1), P + (2 * k + 3));
00124       }
00125     }
00126   } while (!sorted);
00127   // eliminate doubles
00128 
00129   int i = 0, j = 1; // the next one; j may advance faster than i
00130   // check the unit
00131   // double epsilon_1 = 1.e-5; // these are cm; 2 points are the same if the distance is less than 1.e-5 cm
00132   while (j < nP)
00133   {
00134     double d2 = dist2(&P[2 * i], &P[2 * j]);
00135     if (d2 > epsilon_1)
00136     {
00137       i++;
00138       P[2 * i] = P[2 * j];
00139       P[2 * i + 1] = P[2 * j + 1];
00140     }
00141     j++;
00142   }
00143   // test also the last point with the first one (index 0)
00144 
00145   double d2 = dist2(P, &P[2 * i]); // check the first and last points (ordered from -pi to +pi)
00146   if (d2 > epsilon_1)
00147   {
00148     nP = i + 1;
00149   }
00150   else
00151     nP = i; // effectively delete the last point (that would have been the same with first)
00152   if (nP == 0)
00153     nP = 1; // we should be left with at least one point we already tested if nP is 0 originally
00154   return 0;
00155 }
00156 
00157 // the marks will show what edges of blue intersect the red
00158 
00159 int EdgeIntersections2(double * blue, int nsBlue, double * red, int nsRed,
00160     int markb[MAXEDGES], int markr[MAXEDGES], double * points, int & nPoints)
00161 {
00162   /* EDGEINTERSECTIONS computes edge intersections of two elements
00163    [P,n]=EdgeIntersections(X,Y) computes for the two given elements  * red
00164    and blue ( stored column wise )
00165    (point coordinates are stored column-wise, in counter clock
00166    order) the points P where their edges intersect. In addition,
00167    in n the indices of which neighbors of red  are also intersecting
00168    with blue are given.
00169    */
00170 
00171   // points is an array with enough slots   (24 * 2 doubles)
00172   nPoints = 0;
00173   for (int i=0; i<MAXEDGES; i++){
00174     markb[i]=markr[i] = 0;
00175   }
00176 
00177   for (int i = 0; i < nsBlue; i++)
00178   {
00179     for (int j = 0; j < nsRed; j++)
00180     {
00181       double b[2];
00182       double a[2][2]; // 2*2
00183       int iPlus1 = (i + 1) % nsBlue;
00184       int jPlus1 = (j + 1) % nsRed;
00185       for (int k = 0; k < 2; k++)
00186       {
00187         b[k] = red[2 * j + k] - blue[2 * i + k];
00188         // row k of a: a(k, 0), a(k, 1)
00189         a[k][0] = blue[2 * iPlus1 + k] - blue[2 * i + k];
00190         a[k][1] = red[2 * j + k] - red[2 * jPlus1 + k];
00191 
00192       }
00193       double delta = a[0][0] * a[1][1] - a[0][1] * a[1][0];
00194       if (delta != 0.)
00195       {
00196         // not parallel
00197         double alfa = (b[0] * a[1][1] - a[0][1] * b[1]) / delta;
00198         double beta = (-b[0] * a[1][0] + b[1] * a[0][0]) / delta;
00199         if (0 <= alfa && alfa <= 1. && 0 <= beta && beta <= 1.)
00200         {
00201           // the intersection is good
00202           for (int k = 0; k < 2; k++)
00203           {
00204             points[2 * nPoints + k] = blue[2 * i + k]
00205                 + alfa * (blue[2 * iPlus1 + k] - blue[2 * i + k]);
00206           }
00207           markb[i] = 1; // so neighbor number i of blue will be considered too.
00208           markr[j] = 1; // this will be used in advancing red around blue quad
00209           nPoints++;
00210         }
00211       }
00212       // the case delta == 0. will be considered by the interior points logic
00213 
00214     }
00215   }
00216   return 0;
00217 }
00218 
00219 
00220 // vec utils related to gnomonic projection on a sphere
00221 
00222 // vec utils
00223 
00224 /*
00225  *
00226  * position on a sphere of radius R
00227  * if plane specified, use it; if not, return the plane, and the point in the plane
00228  * there are 6 planes, numbered 1 to 6
00229  * plane 1: x=R, plane 2: y=R, 3: x=-R, 4: y=-R, 5: z=-R, 6: z=R
00230  *
00231  * projection on the plane will preserve the orientation, such that a triangle, quad pointing
00232  * outside the sphere will have a positive orientation in the projection plane
00233  */
00234 void decide_gnomonic_plane(const CartVect & pos, int & plane)
00235 {
00236   // decide plane, based on max x, y, z
00237   if (fabs(pos[0]) < fabs(pos[1]))
00238   {
00239     if (fabs(pos[2]) < fabs(pos[1]))
00240     {
00241       // pos[1] is biggest
00242       if (pos[1] > 0)
00243         plane = 2;
00244       else
00245         plane = 4;
00246     }
00247     else
00248     {
00249       // pos[2] is biggest
00250       if (pos[2] < 0)
00251         plane = 5;
00252       else
00253         plane = 6;
00254     }
00255   }
00256   else
00257   {
00258     if (fabs(pos[2]) < fabs(pos[0]))
00259     {
00260       // pos[0] is the greatest
00261       if (pos[0] > 0)
00262         plane = 1;
00263       else
00264         plane = 3;
00265     }
00266     else
00267     {
00268       // pos[2] is biggest
00269       if (pos[2] < 0)
00270         plane = 5;
00271       else
00272         plane = 6;
00273     }
00274   }
00275   return;
00276 }
00277 // point on a sphere is projected on one of six planes, decided earlier
00278 int gnomonic_projection(const CartVect & pos, double R, int plane, double & c1, double & c2)
00279 {
00280   double alfa = 1.; // the new point will be on line alfa*pos
00281 
00282   switch (plane)
00283   {
00284   case 1:
00285   {
00286     // the plane with x = R; x>y, x>z
00287     // c1->y, c2->z
00288     alfa = R / pos[0];
00289     c1 = alfa * pos[1];
00290     c2 = alfa * pos[2];
00291     break;
00292   }
00293   case 2:
00294   {
00295     // y = R -> zx
00296     alfa = R / pos[1];
00297     c1 = alfa * pos[2];
00298     c2 = alfa * pos[0];
00299     break;
00300   }
00301   case 3:
00302   {
00303     // x=-R, -> yz
00304     alfa = -R / pos[0];
00305     c1 = -alfa * pos[1]; // the sign is to preserve orientation
00306     c2 = alfa * pos[2];
00307     break;
00308   }
00309   case 4:
00310   {
00311     // y = -R
00312     alfa = -R / pos[1];
00313     c1 = -alfa * pos[2]; // the sign is to preserve orientation
00314     c2 = alfa * pos[0];
00315     break;
00316   }
00317   case 5:
00318   {
00319     // z = -R
00320     alfa = -R / pos[2];
00321     c1 = -alfa * pos[0]; // the sign is to preserve orientation
00322     c2 = alfa * pos[1];
00323     break;
00324   }
00325   case 6:
00326   {
00327     alfa = R / pos[2];
00328     c1 = alfa * pos[0];
00329     c2 = alfa * pos[1];
00330     break;
00331   }
00332   default:
00333     return 1; // error
00334   }
00335 
00336   return 0; // no error
00337 }
00338 // given the position on plane (one out of 6), find out the position on sphere
00339 int reverse_gnomonic_projection(const double & c1, const double & c2, double R, int plane,
00340     CartVect & pos)
00341 {
00342 
00343   // the new point will be on line beta*pos
00344   double len = sqrt(c1 * c1 + c2 * c2 + R * R);
00345   double beta = R / len; // it is less than 1, in general
00346 
00347   switch (plane)
00348   {
00349   case 1:
00350   {
00351     // the plane with x = R; x>y, x>z
00352     // c1->y, c2->z
00353     pos[0] = beta * R;
00354     pos[1] = c1 * beta;
00355     pos[2] = c2 * beta;
00356     break;
00357   }
00358   case 2:
00359   {
00360     // y = R -> zx
00361     pos[1] = R * beta;
00362     pos[2] = c1 * beta;
00363     pos[0] = c2 * beta;
00364     break;
00365   }
00366   case 3:
00367   {
00368     // x=-R, -> yz
00369     pos[0] = -R * beta;
00370     pos[1] = -c1 * beta; // the sign is to preserve orientation
00371     pos[2] = c2 * beta;
00372     break;
00373   }
00374   case 4:
00375   {
00376     // y = -R
00377     pos[1] = -R * beta;
00378     pos[2] = -c1 * beta; // the sign is to preserve orientation
00379     pos[0] = c2 * beta;
00380     break;
00381   }
00382   case 5:
00383   {
00384     // z = -R
00385     pos[2] = -R * beta;
00386     pos[0] = -c1 * beta; // the sign is to preserve orientation
00387     pos[1] = c2 * beta;
00388     break;
00389   }
00390   case 6:
00391   {
00392     pos[2] = R * beta;
00393     pos[0] = c1 * beta;
00394     pos[1] = c2 * beta;
00395     break;
00396   }
00397   default:
00398     return 1; // error
00399   }
00400 
00401   return 0; // no error
00402 }
00403 
00404 /*
00405  *
00406     use physical_constants, only : dd_pi
00407     type(cartesian3D_t), intent(in) :: cart
00408     type(spherical_polar_t)         :: sphere
00409 
00410     sphere%r=distance(cart)
00411     sphere%lat=ASIN(cart%z/sphere%r)
00412     sphere%lon=0
00413 
00414     ! ==========================================================
00415     ! enforce three facts:
00416     !
00417     ! 1) lon at poles is defined to be zero
00418     !
00419     ! 2) Grid points must be separated by about .01 Meter (on earth)
00420     !    from pole to be considered "not the pole".
00421     !
00422     ! 3) range of lon is { 0<= lon < 2*pi }
00423     !
00424     ! ==========================================================
00425 
00426     if (distance(cart) >= DIST_THRESHOLD) then
00427        sphere%lon=ATAN2(cart%y,cart%x)
00428        if (sphere%lon<0) then
00429           sphere%lon=sphere%lon+2*DD_PI
00430        end if
00431     end if
00432 
00433   end function cart_to_spherical
00434  */
00435 SphereCoords cart_to_spherical(CartVect & cart3d)
00436 {
00437   SphereCoords res;
00438   res.R = cart3d.length();
00439   if (res.R < 0)
00440   {
00441     res.lon=res.lat = 0.;
00442     return res;
00443   }
00444   res.lat = asin(cart3d[2]/res.R);
00445   res.lon=atan2(cart3d[1], cart3d[0]);
00446   if (res.lon<0)
00447     res.lon+=2*M_PI;// M_PI is defined in math.h? it seems to be true, although
00448   // there are some defines it depends on :(
00449   // #if defined __USE_BSD || defined __USE_XOPEN ???
00450 
00451   return res;
00452 }
00453 /*
00454  * ! ===================================================================
00455   ! spherical_to_cart:
00456   ! converts spherical polar {lon,lat}  to 3D cartesian {x,y,z}
00457   ! on unit sphere
00458   ! ===================================================================
00459 
00460   function spherical_to_cart(sphere) result (cart)
00461 
00462     type(spherical_polar_t), intent(in) :: sphere
00463     type(cartesian3D_t)                 :: cart
00464 
00465     cart%x=sphere%r*COS(sphere%lat)*COS(sphere%lon)
00466     cart%y=sphere%r*COS(sphere%lat)*SIN(sphere%lon)
00467     cart%z=sphere%r*SIN(sphere%lat)
00468 
00469   end function spherical_to_cart
00470  */
00471 CartVect spherical_to_cart (SphereCoords & sc)
00472 {
00473   CartVect res;
00474   res[0] = sc.R * cos(sc.lat)*cos(sc.lon) ; // x coordinate
00475   res[1] = sc.R * cos(sc.lat)*sin(sc.lon); // y
00476   res[2] = sc.R * sin(sc.lat);             // z
00477   return res;
00478 }
00479 // remove dependency to coupler now
00480 #if 0
00481 ErrorCode SpectralVisuMesh(Interface * mb, Range & input, int NP, EntityHandle & outputSet, double tolerance)
00482 {
00483   ErrorCode rval = MB_SUCCESS;
00484 
00485   // this will compute the gl points on parametric element
00486   moab::Element::SpectralQuad specQuad(NP);
00487   Range fineElem;
00488 
00489   std::vector<int> gids(input.size()*(NP-1)*(NP-1));// total number of "linear" elements
00490   // get all edges? or not? Form all gl points + quads, then merge, then output
00491   int startGid=0;
00492   for (Range::iterator it=input.begin(); it!=input.end(); it++)
00493   {
00494     const moab::EntityHandle * conn4 = NULL;
00495     int num_nodes = 0;
00496     rval = mb->get_connectivity(*it, conn4, num_nodes);
00497     if (moab::MB_SUCCESS != rval)
00498     {
00499       std::cout << "can't get connectivity for quad \n";
00500       return rval;
00501     }
00502     assert(num_nodes==4);
00503 
00504     std::vector<CartVect> verts(4);
00505     rval = mb->get_coords(conn4, num_nodes, &(verts[0][0]));
00506     if (moab::MB_SUCCESS != rval)
00507     {
00508       std::cout << "can't get coords for quad \n";
00509       return rval;
00510     }
00511 
00512     specQuad.set_vertices(verts);
00513     specQuad.compute_gl_positions();
00514     double * xyz[3];
00515     int size;
00516     specQuad.get_gl_points(xyz[0], xyz[1], xyz[2], size);
00517     assert(NP*NP==size);
00518     // these points are in lexicographic order;
00519     std::vector<EntityHandle> nodes(size);
00520     for (int i=0; i<size; i++)
00521     {
00522       double coords[3]={ xyz[0][i], xyz[1][i], xyz[2][i] };
00523       rval = mb->create_vertex(coords, nodes[i] );
00524       if (rval!=moab::MB_SUCCESS)
00525         return rval;
00526     }
00527     // create (NP-1)^2 quads, one by one (sic)
00528     for (int i=0; i<NP-1; i++)
00529     {
00530       for (int j=0; j<NP-1; j++)
00531       {
00532         EntityHandle connec[4]={ nodes[ i*NP+j],      nodes[i*NP+j+1],
00533                                   nodes[(i+1)*NP+j+1], nodes[(i+1)*NP+j] };
00534         EntityHandle element_handle;
00535         rval = mb->create_element(MBQUAD, connec, 4, element_handle);
00536         if (rval!=moab::MB_SUCCESS)
00537           return rval;
00538         fineElem.insert(element_handle);
00539         gids[startGid]=startGid+1;
00540         startGid++;
00541       }
00542     }
00543 
00544   }
00545 
00546   mb->add_entities(outputSet, fineElem);
00547   // merge all nodes
00548   MergeMesh mgtool(mb);
00549   rval = mgtool.merge_entities(fineElem, tolerance);
00550   if (MB_SUCCESS!=rval)
00551     return rval;
00552   Tag gidTag;
00553   rval = mb->tag_get_handle("GLOBAL_ID", 1, MB_TYPE_INTEGER,
00554       gidTag, MB_TAG_DENSE|MB_TAG_CREAT);
00555   if (MB_SUCCESS!=rval)
00556       return rval;
00557   rval = mb->tag_set_data(gidTag, fineElem, &gids[0]);
00558 
00559   return rval;
00560 }
00561 // remove for the time being dependency on coupler
00562 #endif
00563 ErrorCode ProjectOnSphere(Interface * mb, EntityHandle set, double R)
00564 {
00565   Range ents;
00566   ErrorCode rval = mb->get_entities_by_handle(set, ents);
00567   if (rval!=moab::MB_SUCCESS)
00568     return rval;
00569 
00570   Range nodes;
00571   rval = mb->get_connectivity( ents, nodes);
00572   if (rval!=moab::MB_SUCCESS)
00573     return rval;
00574 
00575   // one by one, get the node and project it on the sphere, with a radius given
00576   // the center of the sphere is at 0,0,0
00577   for (Range::iterator nit=nodes.begin(); nit!=nodes.end(); nit++)
00578   {
00579     EntityHandle nd=*nit;
00580     CartVect pos;
00581     rval = mb->get_coords(&nd, 1, (double*)&(pos[0]));
00582     if (rval!=moab::MB_SUCCESS)
00583       return rval;
00584     double len=pos.length();
00585     if (len==0.)
00586       return MB_FAILURE;
00587     pos = R/len*pos;
00588     rval = mb->set_coords(&nd, 1, (double*)&(pos[0]));
00589     if (rval!=moab::MB_SUCCESS)
00590        return rval;
00591   }
00592   return MB_SUCCESS;
00593 }
00594 //
00595 bool point_in_interior_of_convex_polygon (double * points, int np, double pt[2])
00596 {
00597   bool inside = true;
00598   // assume points are counterclockwise
00599   for (int i = 0; i < np; i++)
00600   {
00601     // compute the area of triangles formed by a side of polygon and the pt; if one is negative, stop
00602     double * A = points + 2 * i;
00603 
00604     int i1=(i+1)%np;
00605     double * B = points + 2 * i1; // no copy of data
00606 
00607     double area2 = (B[0] - A[0]) * (pt[1] - A[1])
00608         - (pt[0] - A[0]) * (B[1] - A[1]);
00609     if (area2 < 0.)
00610     {
00611       inside = false;
00612       break;
00613     }
00614   }
00615   return inside;
00616 }
00617 // assume they are one the same sphere
00618 double spherical_angle(double * A, double * B, double * C, double Radius)
00619 {
00620   // the angle by definition is between the planes OAB and OBC
00621   CartVect a(A);
00622   CartVect b(B);
00623   CartVect c(C);
00624   double err1=a.length_squared()-Radius*Radius;
00625   if (fabs(err1)>0.0001)
00626   {
00627     std::cout << " error in input " << a << " radius: " << Radius << " error:" << err1<< "\n";
00628   }
00629   CartVect normalOAB = a * b;
00630   CartVect normalOCB = c * b;
00631   return angle(normalOAB, normalOCB);
00632 }
00633 // could be bigger than M_PI;
00634 // angle at B could be bigger than M_PI, if the orientation is such that ABC points toward the interior
00635 double oriented_spherical_angle(double * A, double * B, double * C)
00636 {
00637   // assume the same radius, sphere at origin
00638   CartVect a(A), b(B), c(C);
00639   CartVect normalOAB = a * b;
00640   CartVect normalOCB = c * b;
00641   CartVect orient = (c-b)*(a-b);
00642   double ang = angle(normalOAB, normalOCB); // this is between 0 and M_PI
00643   if (ang!=ang)
00644   {
00645     // signal of a nan
00646     std::cout << a << " " << b << " " << c <<"\n";
00647     std::cout << ang << "\n";
00648   }
00649   if (orient%b < 0)
00650     return (2*M_PI-ang);// the other angle, supplement
00651 
00652   return ang;
00653 
00654 }
00655 double area_spherical_triangle(double *A, double *B, double *C, double Radius)
00656 {
00657   double correction = spherical_angle(A, B, C, Radius)+spherical_angle(B, C, A, Radius)+
00658       spherical_angle(C, A, B, Radius)-M_PI;
00659   double area = Radius*Radius*correction;
00660   // now, is it negative or positive? is it pointing toward the center or outward?
00661   CartVect a(A), b(B), c(C);
00662   CartVect abc = (b-a)*(c-a);
00663   if (abc%a > 0) // dot product positive, means ABC points out
00664     return area;
00665   else
00666     return -area;
00667 
00668 }
00669 
00670 double area_spherical_polygon (double * A, int N, double Radius)
00671 {
00672   // this should work for non-convex polygons too
00673   // assume that the A, A+3, ..., A+3*(N-1) are the coordinates
00674   //
00675   if (N<=2)
00676     return 0.;
00677   double sum_angles = 0.;
00678   for (int i=0; i<N; i++)
00679   {
00680     int i1 = (i+1)%N;
00681     int i2 = (i+2)%N;
00682     sum_angles += oriented_spherical_angle( A+3*i, A+3*i1, A+3*i2);
00683   }
00684   double correction = sum_angles-(N-2)*M_PI;
00685   return Radius*Radius *correction;
00686 
00687 }
00688 /*
00689  *  l'Huiller's formula for spherical triangle
00690  *  http://williams.best.vwh.net/avform.htm
00691  *  a, b, c are arc measures in radians, too
00692  *  A, B, C are angles on the sphere, for which we already have formula
00693  *               c
00694  *         A -------B
00695  *          \       |
00696  *           \      |
00697  *            \b    |a
00698  *             \    |
00699  *              \   |
00700  *               \  |
00701  *                \C|
00702  *                 \|
00703  *
00704  *  (The angle at B is not necessarily a right angle)
00705  *
00706  *    sin(a)  sin(b)   sin(c)
00707  *    ----- = ------ = ------
00708  *    sin(A)  sin(B)   sin(C)
00709  *
00710  * In terms of the sides (this is excess, as before, but numerically stable)
00711  *
00712  *  E = 4*atan(sqrt(tan(s/2)*tan((s-a)/2)*tan((s-b)/2)*tan((s-c)/2)))
00713  */
00714 
00715 double area_spherical_triangle_lHuiller(double * ptA, double * ptB, double * ptC, double Radius)
00716 {
00717   // now, a is angle BOC, O is origin
00718   CartVect vA(ptA), vB(ptB), vC(ptC);
00719   double a = angle(vB, vC);
00720   double b = angle(vC, vA);
00721   double c = angle(vA, vB);
00722   int sign =1;
00723   if ((vA*vB)%vC < 0)
00724     sign = -1;
00725   double s = (a+b+c)/2;
00726   double tmp = tan(s/2)*tan((s-a)/2)*tan((s-b)/2)*tan((s-c)/2);
00727   if (tmp<0.)
00728     tmp = 0.;
00729   double E = 4*atan(sqrt(tmp));
00730   if (E!=E)
00731     std::cout << " NaN at spherical triangle area \n";
00732   return sign * E * Radius*Radius;
00733 }
00734 
00735 
00736 double area_spherical_polygon_lHuiller (double * A, int N, double Radius)
00737 {
00738   // this should work for non-convex polygons too
00739   // assume that the A, A+3, ..., A+3*(N-1) are the coordinates
00740   //
00741   // assume that the orientation is positive;
00742   // if negative orientation, the area will be negative
00743   if (N<=2)
00744     return 0.;
00745   double area = 0.;
00746   for (int i=1; i<N-1; i++)
00747   {
00748     int i1 = i+1;
00749     area += area_spherical_triangle_lHuiller( A, A+3*i, A+3*i1, Radius);
00750   }
00751   return area;
00752 }
00753 
00754 double area_on_sphere(Interface * mb, EntityHandle set, double R)
00755 {
00756   // get all entities of dimension 2
00757   // then get the connectivity, etc
00758   Range inputRange;
00759   ErrorCode rval = mb->get_entities_by_dimension(set, 2, inputRange);
00760   if (MB_SUCCESS != rval)
00761     return -1;
00762 
00763   // compare total area with 4*M_PI * R^2
00764   double total_area = 0.;
00765   for (Range::iterator eit=inputRange.begin(); eit!= inputRange.end(); eit++ )
00766   {
00767     EntityHandle eh=*eit;
00768     // get the nodes, then the coordinates
00769     const EntityHandle * verts;
00770     int num_nodes;
00771     rval = mb->get_connectivity(eh, verts, num_nodes);
00772     if (MB_SUCCESS != rval)
00773       return -1;
00774     std::vector<double> coords(3*num_nodes);
00775     // get coordinates
00776     rval = mb->get_coords(verts, num_nodes, &coords[0]);
00777     if (MB_SUCCESS != rval)
00778       return -1;
00779     total_area+=area_spherical_polygon (&coords[0], num_nodes, R);
00780   }
00781   return total_area;
00782 }
00783 double area_on_sphere_lHuiller(Interface * mb, EntityHandle set, double R)
00784 {
00785   // get all entities of dimension 2
00786   // then get the connectivity, etc
00787   Range inputRange;
00788   ErrorCode rval = mb->get_entities_by_dimension(set, 2, inputRange);
00789   if (MB_SUCCESS != rval)
00790     return -1;
00791 
00792   double total_area = 0.;
00793   for (Range::iterator eit = inputRange.begin(); eit != inputRange.end(); eit++)
00794   {
00795     EntityHandle eh = *eit;
00796     // get the nodes, then the coordinates
00797     const EntityHandle * verts;
00798     int num_nodes;
00799     rval = mb->get_connectivity(eh, verts, num_nodes);
00800     if (MB_SUCCESS != rval)
00801       return -1;
00802     std::vector<double> coords(3 * num_nodes);
00803     // get coordinates
00804     rval = mb->get_coords(verts, num_nodes, &coords[0]);
00805     if (MB_SUCCESS != rval)
00806       return -1;
00807     total_area += area_spherical_polygon_lHuiller(&coords[0], num_nodes, R);
00808   }
00809   return total_area;
00810 }
00811 
00812 double area_spherical_element(Interface * mb, EntityHandle elem, double R)
00813 {
00814   const EntityHandle * verts;
00815   int num_nodes;
00816   ErrorCode rval = mb->get_connectivity(elem, verts, num_nodes);
00817   if (MB_SUCCESS != rval)
00818     return -1;
00819   std::vector<double> coords(3 * num_nodes);
00820   // get coordinates
00821   rval = mb->get_coords(verts, num_nodes, &coords[0]);
00822   if (MB_SUCCESS != rval)
00823     return -1;
00824   return area_spherical_polygon_lHuiller(&coords[0], num_nodes, R);
00825 
00826 }
00827 /*
00828  *
00829  */
00830 double distance_on_great_circle(CartVect & p1, CartVect & p2)
00831 {
00832   SphereCoords sph1 = cart_to_spherical(p1);
00833   SphereCoords sph2 = cart_to_spherical(p2);
00834   // radius should be the same
00835   return sph1.R * acos(sin (sph1.lon)* sin(sph2.lon) + cos(sph1.lat)*cos(sph2.lat)*cos(sph2.lon-sph2.lon) );
00836 }
00837 /*
00838  * based on paper A class of deformational flow test cases for linear transport problems on the sphere
00839  *  longitude lambda [0.. 2*pi) and latitude theta (-pi/2, pi/2)
00840  *  lambda: -> lon (0, 2*pi)
00841  *  theta : -> lat (-pi/2, po/2)
00842  *  Radius of the sphere is 1 (if not, everything gets multiplied by 1)
00843  *
00844  *  cosine bell: center lambda0, theta0:
00845  */
00846 void departure_point_case1(CartVect & arrival_point, double t, double delta_t, CartVect & departure_point)
00847 {
00848   // always assume radius is 1 here?
00849   SphereCoords sph = cart_to_spherical(arrival_point);
00850   double T=5; // duration of integration (5 units)
00851   double k = 2.4; //flow parameter
00852   /*     radius needs to be within some range   */
00853   double  sl2 = sin(sph.lon/2);
00854   double pit = M_PI * t / T;
00855   double omega = M_PI/T;
00856   double costetha = cos(sph.lat);
00857   //double u = k * sl2*sl2 * sin(2*sph.lat) * cos(pit);
00858   double v = k * sin(sph.lon) * costetha * cos(pit);
00859   //double psi = k * sl2 * sl2 *costetha * costetha * cos(pit);
00860   double u_tilda = 2*k*sl2*sl2*sin(sph.lat)*cos(pit);
00861 
00862   // formula 35, page 8
00863   // this will approximate dep point using a Taylor series with up to second derivative
00864   // this will be O(delta_t^3) exact.
00865   double lon_dep = sph.lon - delta_t * u_tilda -delta_t*delta_t * k * sl2 *
00866       ( sl2 * sin (sph.lat) * sin(pit) * omega
00867           - u_tilda * sin(sph.lat) * cos(pit) * cos (sph.lon/2)
00868           - v * sl2 * costetha * cos(pit)   );
00869   // formula 36, page 8 again
00870   double lat_dep = sph.lat - delta_t*v - delta_t * delta_t/4* k *
00871       ( sin(sph.lon)* cos(sph.lat) * sin(pit) * omega
00872           - u_tilda * cos(sph.lon) * cos(sph.lat) * cos(pit)
00873           + v * sin(sph.lon) * sin(sph.lat) * cos(pit)  );
00874   SphereCoords sph_dep;
00875   sph_dep.R = 1.; // radius
00876   sph_dep.lat = lat_dep;
00877   sph_dep.lon = lon_dep;
00878 
00879   departure_point = spherical_to_cart(sph_dep);
00880   return;
00881 }
00882 
00883 void velocity_case1(CartVect & arrival_point, double t, CartVect & velo)
00884 {
00885   // always assume radius is 1 here?
00886   SphereCoords sph = cart_to_spherical(arrival_point);
00887   double T=5; // duration of integration (5 units)
00888   double k = 2.4; //flow parameter
00889   /*     radius needs to be within some range   */
00890   double  sl2 = sin(sph.lon/2);
00891   double pit = M_PI * t / T;
00892   //double omega = M_PI/T;
00893   double coslat = cos(sph.lat);
00894   double sinlat = sin(sph.lat);
00895   double sinlon = sin(sph.lon);
00896   double coslon = cos(sph.lon);
00897   double u = k * sl2*sl2 * sin(2*sph.lat) * cos(pit);
00898   double v = k/2 * sinlon * coslat * cos(pit);
00899   velo[0] = - u * sinlon - v * sinlat * coslon;
00900   velo[1] = u * coslon - v * sinlat * sinlon;
00901   velo[2] = v * coslat;
00902 
00903 }
00904 // break the nonconvex quads into triangles; remove the quad from the set? yes.
00905 // maybe radius is not needed;
00906 //
00907 ErrorCode enforce_convexity(Interface * mb, EntityHandle lset, int my_rank)
00908 {
00909   // look at each polygon; compute all angles; if one is reflex, break that angle with
00910   // the next triangle; put the 2 new polys in the set;
00911   // still look at the next poly
00912   // replace it with 2 triangles, and remove from set;
00913   // it should work for all polygons / tested first for case 1, with dt 0.5 (too much deformation)
00914   // get all entities of dimension 2
00915   // then get the connectivity, etc
00916 
00917   Range inputRange;
00918   ErrorCode rval = mb->get_entities_by_dimension(lset, 2, inputRange);
00919   if (MB_SUCCESS != rval)
00920     return rval;
00921 
00922   Tag corrTag=0;
00923   EntityHandle dumH=0;
00924   rval = mb->tag_get_handle(CORRTAGNAME,
00925            1, MB_TYPE_HANDLE, corrTag,
00926            MB_TAG_DENSE, &dumH);
00927   if(rval==MB_TAG_NOT_FOUND)
00928     corrTag = 0;
00929 
00930   Tag gidTag;
00931   rval = mb->tag_get_handle("GLOBAL_ID", 1, MB_TYPE_INTEGER,
00932         gidTag, MB_TAG_DENSE);
00933 
00934   if(rval!=MB_SUCCESS)
00935     return rval;
00936 
00937   std::vector<double> coords;
00938   coords.resize(3*MAXEDGES); // at most 10 vertices per polygon
00939   // we should create a queue with new polygons that need processing for reflex angles
00940   //  (obtuse)
00941   std::queue<EntityHandle> newPolys;
00942   int brokenPolys=0;
00943   Range::iterator eit = inputRange.begin();
00944   while (eit != inputRange.end() || !newPolys.empty())
00945   {
00946     EntityHandle eh;
00947     if (eit != inputRange.end())
00948     {
00949       eh = *eit;
00950       eit++;
00951     }
00952     else
00953     {
00954       eh = newPolys.front();
00955       newPolys.pop();
00956     }
00957     // get the nodes, then the coordinates
00958     const EntityHandle * verts;
00959     int num_nodes;
00960     rval = mb->get_connectivity(eh, verts, num_nodes);
00961     if (MB_SUCCESS != rval)
00962       return rval;
00963     int nsides = num_nodes;
00964     // account for possible padded polygons
00965     while (verts[nsides-2]==verts[nsides-1] && nsides>3)
00966       nsides--;
00967     EntityHandle corrHandle=0;
00968     if (corrTag)
00969     {
00970       rval = mb->tag_get_data(corrTag, &eh, 1, &corrHandle);
00971       if (MB_SUCCESS != rval)
00972         return rval;
00973     }
00974     int gid=0;
00975     rval = mb->tag_get_data(gidTag, &eh, 1, &gid);
00976     if (MB_SUCCESS != rval)
00977       return rval;
00978     coords.resize(3 * nsides);
00979     if (nsides < 4)
00980       continue; // if already triangles, don't bother
00981        // get coordinates
00982     rval = mb->get_coords(verts, nsides, &coords[0]);
00983     if (MB_SUCCESS != rval)
00984      return rval;
00985     // compute each angle
00986     bool alreadyBroken = false;
00987 
00988     for (int i=0; i<nsides; i++)
00989     {
00990       double * A = &coords[3*i];
00991       double * B = &coords[3*((i+1)%nsides)];
00992       double * C = &coords[3*((i+2)%nsides)];
00993       double angle = oriented_spherical_angle(A, B, C);
00994       if (angle-M_PI > 0.) // even almost reflex is bad; break it!
00995       {
00996         if (alreadyBroken)
00997         {
00998           mb->list_entities(&eh, 1);
00999           mb->list_entities(verts, nsides);
01000           double * D = &coords[3*((i+3)%nsides)];
01001           std::cout<< "ABC: " << angle << " \n";
01002           std::cout<< "BCD: " << oriented_spherical_angle( B, C, D) << " \n";
01003           std::cout<< "CDA: " << oriented_spherical_angle( C, D, A) << " \n";
01004           std::cout<< "DAB: " << oriented_spherical_angle( D, A, B)<< " \n";
01005           std::cout << " this cell has at least 2 angles > 180, it has serious issues\n";
01006 
01007           return MB_FAILURE;
01008         }
01009         // the bad angle is at i+1;
01010         // create 1 triangle and one polygon; add the polygon to the input range, so
01011         // it will be processed too
01012         // also, add both to the set :) and remove the original polygon from the set
01013         // break the next triangle, even though not optimal
01014         // so create the triangle i+1, i+2, i+3; remove i+2 from original list
01015         // even though not optimal in general, it is good enough.
01016         EntityHandle conn3[3]={ verts[ (i+1)%nsides],
01017             verts[ (i+2)%nsides],
01018             verts[ (i+3)%nsides] };
01019         // create a polygon with num_nodes-1 vertices, and connectivity
01020         // verts[i+1], verts[i+3], (all except i+2)
01021         std::vector<EntityHandle> conn(nsides-1);
01022         for (int j=1; j<nsides; j++)
01023         {
01024           conn[j-1]=verts[(i+j+2)%nsides];
01025         }
01026         EntityHandle newElement;
01027         rval = mb->create_element(MBTRI, conn3, 3, newElement);
01028         if (MB_SUCCESS != rval)
01029           return rval;
01030 
01031         rval = mb->add_entities(lset, &newElement, 1);
01032         if (MB_SUCCESS != rval)
01033           return rval;
01034         if (corrTag)
01035         {
01036           rval = mb->tag_set_data(corrTag, &newElement, 1, &corrHandle);
01037           if (MB_SUCCESS != rval)
01038             return rval;
01039         }
01040         rval = mb->tag_set_data(gidTag, &newElement, 1, &gid);
01041         if (MB_SUCCESS != rval)
01042           return rval;
01043         if (nsides == 4)
01044         {
01045           // create another triangle
01046           rval = mb->create_element(MBTRI, &conn[0], 3, newElement);
01047           if (MB_SUCCESS != rval)
01048             return rval;
01049         }
01050         else
01051         {
01052           // create another polygon, and add it to the inputRange
01053           rval = mb->create_element(MBPOLYGON, &conn[0], nsides-1, newElement);
01054           if (MB_SUCCESS != rval)
01055             return rval;
01056           newPolys.push(newElement); // because it has less number of edges, the
01057           // reverse should work to find it.
01058         }
01059         rval = mb->add_entities(lset, &newElement, 1);
01060         if (MB_SUCCESS != rval)
01061           return rval;
01062         if (corrTag)
01063         {
01064           rval = mb->tag_set_data(corrTag, &newElement, 1, &corrHandle);
01065           if (MB_SUCCESS != rval)
01066             return rval;
01067         }
01068         rval = mb->tag_set_data(gidTag, &newElement, 1, &gid);
01069          if (MB_SUCCESS != rval)
01070            return rval;
01071         mb->remove_entities(lset, &eh, 1);
01072         brokenPolys++;
01073         /*std::cout<<"remove: " ;
01074         mb->list_entities(&eh, 1);
01075 
01076         std::stringstream fff;
01077         fff << "file0" <<  brokenQuads<< ".vtk";
01078         mb->write_file(fff.str().c_str(), 0, 0, &lset, 1);*/
01079         alreadyBroken=true; // get out of the loop, element is broken
01080       }
01081     }
01082   }
01083   std::cout << "on local process " << my_rank << " " <<  brokenPolys << " concave polygons were decomposed in convex ones \n";
01084   return MB_SUCCESS;
01085 }
01086 ErrorCode create_span_quads(Interface * mb, EntityHandle euler_set, int rank)
01087 {
01088   // first get all edges adjacent to polygons
01089   Tag dpTag = 0;
01090   std::string tag_name("DP");
01091   ErrorCode rval = mb->tag_get_handle(tag_name.c_str(), 3, MB_TYPE_DOUBLE, dpTag, MB_TAG_DENSE);
01092   // if the tag does not exist, get out early
01093   if (rval!=MB_SUCCESS)
01094     return rval;
01095   Range polygons;
01096   rval = mb->get_entities_by_dimension(euler_set, 2, polygons);
01097   if (MB_SUCCESS != rval)
01098     return rval;
01099   Range iniEdges;
01100   rval = mb->get_adjacencies(polygons,
01101       1,
01102       false,
01103       iniEdges,
01104       Interface::UNION);
01105   if (MB_SUCCESS != rval)
01106       return rval;
01107   // now create some if missing
01108   Range allEdges;
01109   rval = mb->get_adjacencies(polygons,
01110         1,
01111         true,
01112         allEdges,
01113         Interface::UNION);
01114   // create the vertices at the DP points, and the quads after that
01115   Range verts;
01116   rval = mb->get_connectivity(polygons, verts);
01117   if (MB_SUCCESS != rval)
01118     return rval;
01119   int num_verts = (int) verts.size();
01120   // now see the departure points; to what boxes should we send them?
01121   std::vector<double> dep_points(3*num_verts);
01122   rval = mb->tag_get_data(dpTag, verts, (void*)&dep_points[0]);
01123   if (MB_SUCCESS != rval)
01124     return rval;
01125 
01126   // create vertices corresponding to dp locations
01127   ReadUtilIface *read_iface;
01128   rval = mb->query_interface(read_iface);
01129   if (MB_SUCCESS != rval)
01130     return rval;
01131   std::vector<double *> coords;
01132   EntityHandle start_vert, start_elem, *connect;
01133     // create verts, num is 2(nquads+1) because they're in a 1d row; will initialize coords in loop over quads later
01134   rval = read_iface->get_node_coords (3, num_verts, 0, start_vert, coords);
01135   if (MB_SUCCESS != rval)
01136     return rval;
01137   // fill it up
01138   for (int i=0; i<num_verts; i++)
01139   {
01140     // block from interleaved
01141     coords[0][i]=dep_points[3*i];
01142     coords[1][i]=dep_points[3*i+1];
01143     coords[2][i]=dep_points[3*i+2];
01144   }
01145   // create quads; one quad for each edge
01146   rval = read_iface->get_element_connect(allEdges.size(), 4, MBQUAD, 0, start_elem, connect);
01147   if (MB_SUCCESS != rval)
01148     return rval;
01149 
01150   const EntityHandle * edge_conn = NULL;
01151   int quad_index=0;
01152   EntityHandle firstVertHandle = verts[0];// assume vertices are contiguous...
01153   for (Range::iterator eit=allEdges.begin(); eit!=allEdges.end(); eit++, quad_index++)
01154   {
01155     EntityHandle edge=*eit;
01156     int num_nodes;
01157     rval = mb->get_connectivity(edge, edge_conn, num_nodes);
01158     if (MB_SUCCESS != rval)
01159         return rval;
01160     connect[quad_index*4] = edge_conn[0];
01161     connect[quad_index*4+1] = edge_conn[1];
01162 
01163     // maybe some indexing in range?
01164     connect[quad_index*4+2] = start_vert + edge_conn[1]- firstVertHandle;
01165     connect[quad_index*4+3] = start_vert + edge_conn[0]- firstVertHandle;
01166   }
01167 
01168 
01169   Range quads(start_elem, start_elem+allEdges.size()-1);
01170   EntityHandle outSet;
01171   rval = mb->create_meshset(MESHSET_SET, outSet);
01172   if (MB_SUCCESS != rval)
01173     return rval;
01174   mb->add_entities(outSet, quads);
01175 
01176   Tag colTag;
01177   rval = mb->tag_get_handle("COLOR_ID", 1, MB_TYPE_INTEGER,
01178       colTag, MB_TAG_DENSE|MB_TAG_CREAT);
01179   if (MB_SUCCESS != rval)
01180       return rval;
01181   int j=1;
01182   for (Range::iterator itq=quads.begin(); itq!=quads.end(); itq++, j++)
01183   {
01184     EntityHandle q=*itq;
01185     rval = mb->tag_set_data(colTag, &q, 1, &j);
01186     if (MB_SUCCESS != rval)
01187       return rval;
01188   }
01189   std::stringstream outf;
01190   outf << "SpanQuads" << rank << ".h5m";
01191   rval = mb->write_file(outf.str().c_str(), 0, 0, &outSet, 1);
01192   if (MB_SUCCESS != rval)
01193     return rval;
01194   EntityHandle outSet2;
01195   rval = mb->create_meshset(MESHSET_SET, outSet2);
01196   if (MB_SUCCESS != rval)
01197     return rval;
01198 
01199   Range quadEdges;
01200   rval = mb->get_adjacencies(quads,
01201           1,
01202           true,
01203           quadEdges,
01204           Interface::UNION);
01205   mb->add_entities(outSet2, quadEdges);
01206 
01207   std::stringstream outf2;
01208   outf2 << "SpanEdges" << rank << ".h5m";
01209   rval = mb->write_file(outf2.str().c_str(), 0, 0, &outSet2, 1);
01210   if (MB_SUCCESS != rval)
01211     return rval;
01212 
01213 // maybe some clean up
01214   mb->delete_entities(&outSet, 1);
01215   mb->delete_entities(&outSet2, 1);
01216   mb->delete_entities(quads);
01217   Range new_edges=subtract(allEdges, iniEdges);
01218   mb->delete_entities(new_edges);
01219   new_edges=subtract(quadEdges, iniEdges);
01220   mb->delete_entities(new_edges);
01221   Range new_verts(start_vert, start_vert+num_verts);
01222   mb->delete_entities(new_verts);
01223 
01224   return MB_SUCCESS;
01225 
01226 }
01227 
01228 // distance along a great circle on a sphere of radius 1
01229 // page 4
01230 double distance_on_sphere(double la1, double te1, double la2, double te2)
01231 {
01232   return acos(sin(te1)*sin(te2)+cos(te1)*cos(te2)*cos(la1-la2));
01233 }
01234 // page 4 Nair Lauritzen paper
01235 // param will be: (la1, te1), (la2, te2), b, c; hmax=1, r=1/2
01236 double quasi_smooth_field(double lam, double tet, double * params)
01237 {
01238   double la1 = params[0];
01239   double te1 = params[1];
01240   double la2 = params[2];
01241   double te2 = params[3];
01242   double b = params[4];
01243   double c = params[5];
01244   double hmax = params[6]; // 1;
01245   double r = params[7] ; // 0.5;
01246   double r1 = distance_on_sphere(lam, tet, la1, te1);
01247   double r2 = distance_on_sphere(lam, tet, la2, te2);
01248   double value = b;
01249   if (r1<r)
01250   {
01251     value += c*hmax/2*(1+cos(M_PI*r1/r));
01252   }
01253   if (r2<r)
01254   {
01255     value += c*hmax/2*(1+cos(M_PI*r2/r));
01256   }
01257   return value;
01258 }
01259 // page 4
01260 // params are now x1, y1, ..., y2, z2 (6 params)
01261 // plus h max and b0 (total of 8 params); radius is 1
01262 double smooth_field(double lam, double tet, double * params)
01263 {
01264   SphereCoords sc;
01265   sc.R = 1.;
01266   sc.lat= tet;
01267   sc.lon = lam;
01268   double hmax = params[6];
01269   double b0 = params[7];
01270   CartVect xyz = spherical_to_cart(sc);
01271   CartVect c1(params);
01272   CartVect c2(params+3);
01273   double expo1 = -b0 * (xyz-c1).length_squared();
01274   double expo2 = -b0 * (xyz-c2).length_squared();
01275   return hmax*( exp(expo1) + exp(expo2));
01276 }
01277 // page 5
01278 double slotted_cylinder_field(double lam, double tet, double * params)
01279 {
01280   double la1 = params[0];
01281   double te1 = params[1];
01282   double la2 = params[2];
01283   double te2 = params[3];
01284   double b = params[4];
01285   double c = params[5];
01286   //double hmax = params[6]; // 1;
01287   double r = params[6] ; // 0.5;
01288   double r1 = distance_on_sphere(lam, tet, la1, te1);
01289   double r2 = distance_on_sphere(lam, tet, la2, te2);
01290   double value = b;
01291   double d1=fabs(lam-la1);
01292   double d2 = fabs(lam-la2);
01293   double rp6 = r/6;
01294   double rt5p12 = r*5/12;
01295 
01296   if (r1<=r &&  d1>=rp6)
01297       value=c;
01298   if (r2<=r &&  d2>=rp6)
01299       value =c;
01300   if (r1<=r && d1<rp6 && tet-te1<-rt5p12)
01301     value = c;
01302   if (r2<=r && d2<rp6 && tet-te2 > rt5p12)
01303     value =c;
01304 
01305   return value;
01306 }
01307 
01308 } //namespace moab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines