moab
|
00001 /* 00002 * Intx2MeshOnSphere.cpp 00003 * 00004 * Created on: Oct 3, 2012 00005 */ 00006 00007 #include "Intx2MeshOnSphere.hpp" 00008 #include "moab/GeomUtil.hpp" 00009 #include "MBTagConventions.hpp" 00010 #include <queue> 00011 #ifdef USE_MPI 00012 #include "moab/ParallelComm.hpp" 00013 #endif 00014 00015 namespace moab { 00016 00017 00018 Intx2MeshOnSphere::Intx2MeshOnSphere(Interface * mbimpl):Intx2Mesh(mbimpl) 00019 { 00020 // TODO Auto-generated constructor stub 00021 00022 } 00023 00024 Intx2MeshOnSphere::~Intx2MeshOnSphere() 00025 { 00026 // TODO Auto-generated destructor stub 00027 } 00028 00029 /* the elements are convex for sure, then do a gnomonic projection of both, 00030 * compute intersection in the plane, then go back to the sphere for the points 00031 * */ 00032 int Intx2MeshOnSphere::computeIntersectionBetweenRedAndBlue(EntityHandle red, EntityHandle blue, 00033 double * P, int & nP, double & area, int markb[MAXEDGES], int markr[MAXEDGES], 00034 int & nsBlue, int & nsRed, bool check_boxes_first) 00035 { 00036 // the points will be at most 40; they will describe a convex patch, after the points will be ordered and 00037 // collapsed (eliminate doubles) 00038 // the area is not really required, except to see if it is greater than 0 00039 00040 // gnomonic projection 00041 // int plane = 0; 00042 // get coordinates of the red quad, to decide the gnomonic plane 00043 00044 int num_nodes; 00045 ErrorCode rval = mb->get_connectivity(red, redConn, num_nodes); 00046 00047 if (MB_SUCCESS != rval ) 00048 return 1; 00049 nsRed = num_nodes; 00050 // account for possible padded polygons 00051 while (redConn[nsRed-2]==redConn[nsRed-1] && nsRed>3) 00052 nsRed--; 00053 00054 //CartVect coords[4]; 00055 rval = mb->get_coords(redConn, nsRed, &(redCoords[0][0])); 00056 if (MB_SUCCESS != rval) 00057 return 1; 00058 CartVect middle = redCoords[0]; 00059 for (int i=1; i<nsRed; i++) 00060 middle += redCoords[i]; 00061 middle = 1./nsRed * middle; 00062 00063 decide_gnomonic_plane(middle, plane);// output the plane 00064 //CartVect bluecoords[4]; 00065 rval = mb->get_connectivity(blue, blueConn, num_nodes); 00066 if (MB_SUCCESS != rval ) 00067 return 1; 00068 nsBlue = num_nodes; 00069 // account for possible padded polygons 00070 while (blueConn[nsBlue-2]==blueConn[nsBlue-1] && nsBlue>3) 00071 nsBlue--; 00072 rval = mb->get_coords(blueConn, nsBlue, &(blueCoords[0][0])); 00073 if (MB_SUCCESS != rval) 00074 return 1; 00075 00076 if (dbg_1) 00077 { 00078 std::cout << "red " << mb->id_from_handle(red) << "\n"; 00079 for (int j = 0; j < nsRed; j++) 00080 { 00081 std::cout << redCoords[j] << "\n"; 00082 } 00083 std::cout << "blue " << mb->id_from_handle(blue) << "\n"; 00084 for (int j = 0; j < nsBlue; j++) 00085 { 00086 std::cout << blueCoords[j] << "\n"; 00087 } 00088 mb->list_entities(&red, 1); 00089 mb->list_entities(&blue, 1); 00090 std::cout << "middle " << middle << " plane:" << plane << "\n"; 00091 } 00092 area = 0.; 00093 nP = 0; // number of intersection points we are marking the boundary of blue! 00094 if (check_boxes_first) 00095 { 00096 // look at the boxes formed with vertices; if they are far away, return false early 00097 if (!GeomUtil::bounding_boxes_overlap(redCoords, nsRed, blueCoords, nsBlue, box_error)) 00098 return 0; // no error, but no intersection, decide early to get out 00099 } 00100 for (int j = 0; j < nsRed; j++) 00101 { 00102 // populate coords in the plane for intersection 00103 // they should be oriented correctly, positively 00104 int rc = gnomonic_projection(redCoords[j], R, plane, redCoords2D[2 * j], 00105 redCoords2D[2 * j + 1]); 00106 if (rc != 0) 00107 return 1; 00108 } 00109 for (int j=0; j<nsBlue; j++) 00110 { 00111 int rc = gnomonic_projection(blueCoords[j], R, plane, blueCoords2D[2 * j], 00112 blueCoords2D[2 * j + 1]); 00113 if (rc != 0) 00114 return 1; 00115 } 00116 if (dbg_1) 00117 { 00118 std::cout << "gnomonic plane: " << plane << "\n"; 00119 std::cout << " red blue\n"; 00120 for (int j = 0; j < nsRed; j++) 00121 { 00122 std::cout << redCoords2D[2 * j] << " " << redCoords2D[2 * j + 1] << "\n"; 00123 } 00124 for (int j = 0; j < nsBlue; j++) 00125 { 00126 std::cout << blueCoords2D[2 * j] << " " << blueCoords2D[2 * j + 1] << "\n"; 00127 } 00128 } 00129 00130 int ret = EdgeIntersections2(blueCoords2D, nsBlue, redCoords2D, nsRed, markb, markr, P, nP); 00131 if (ret != 0) 00132 return 1; // some unforeseen error 00133 00134 int side[MAXEDGES] = { 0 };// this refers to what side? blue or red? 00135 int extraPoints = borderPointsOfXinY2(blueCoords2D, nsBlue, redCoords2D, nsRed, &(P[2 * nP]), side, epsilon_area); 00136 if (extraPoints >= 1) 00137 { 00138 for (int k = 0; k < nsBlue; k++) 00139 { 00140 if (side[k]) 00141 { 00142 // this means that vertex k of blue is inside convex red; mark edges k-1 and k in blue, 00143 // as being "intersected" by red; (even though they might not be intersected by other edges, 00144 // the fact that their apex is inside, is good enough) 00145 markb[k] = 1; 00146 markb[(k + nsBlue-1) % nsBlue] = 1; // it is the previous edge, actually, but instead of doing -1, it is 00147 // better to do modulo +3 (modulo 4) 00148 // null side b for next call 00149 side[k]=0; 00150 } 00151 } 00152 } 00153 nP += extraPoints; 00154 00155 extraPoints = borderPointsOfXinY2(redCoords2D, nsRed, blueCoords2D, nsBlue, &(P[2 * nP]), side, epsilon_area); 00156 if (extraPoints >= 1) 00157 { 00158 for (int k = 0; k < nsRed; k++) 00159 { 00160 if (side[k]) 00161 { 00162 // this is to mark that red edges k-1 and k are intersecting blue 00163 markr[k] = 1; 00164 markr[(k + nsRed-1) % nsRed] = 1; // it is the previous edge, actually, but instead of doing -1, it is 00165 // better to do modulo +3 (modulo 4) 00166 // null side b for next call 00167 } 00168 } 00169 } 00170 nP += extraPoints; 00171 00172 // now sort and orient the points in P, such that they are forming a convex polygon 00173 // this will be the foundation of our new mesh 00174 // this works if the polygons are convex 00175 SortAndRemoveDoubles2(P, nP, epsilon_1); // nP should be at most 8 in the end ? 00176 // if there are more than 3 points, some area will be positive 00177 00178 if (nP >= 3) 00179 { 00180 for (int k = 1; k < nP - 1; k++) 00181 area += area2D(P, &P[2 * k], &P[2 * k + 2]); 00182 } 00183 00184 return 0; // no error 00185 } 00186 00187 00188 // this method will also construct the triangles/polygons in the new mesh 00189 // if we accept planar polygons, we just save them 00190 // also, we could just create new vertices every time, and merge only in the end; 00191 // could be too expensive, and the tolerance for merging could be an 00192 // interesting topic 00193 int Intx2MeshOnSphere::findNodes(EntityHandle red, int nsRed, EntityHandle blue, int nsBlue, 00194 double * iP, int nP) 00195 { 00196 // first of all, check against red and blue vertices 00197 // 00198 if (dbg_1) 00199 { 00200 std::cout << "red, blue, nP, P " << mb->id_from_handle(red) << " " 00201 << mb->id_from_handle(blue) << " " << nP << "\n"; 00202 for (int n = 0; n < nP; n++) 00203 std::cout << " \t" << iP[2 * n] << "\t" << iP[2 * n + 1] << "\n"; 00204 00205 } 00206 00207 // get the edges for the red triangle; the extra points will be on those edges, saved as 00208 // lists (unordered) 00209 std::vector<EntityHandle> redEdges(nsRed);// 00210 int i = 0; 00211 for (i = 0; i < nsRed; i++) 00212 { 00213 EntityHandle v[2] = { redConn[i], redConn[(i + 1) % nsRed] };// this is fine even for padded polygons 00214 std::vector<EntityHandle> adj_entities; 00215 ErrorCode rval = mb->get_adjacencies(v, 2, 1, false, adj_entities, 00216 Interface::INTERSECT); 00217 if (rval != MB_SUCCESS || adj_entities.size() < 1) 00218 return 0; // get out , big error 00219 redEdges[i] = adj_entities[0]; // should be only one edge between 2 nodes 00220 } 00221 // these will be in the new mesh, mbOut 00222 // some of them will be handles to the initial vertices from blue or red meshes (lagr or euler) 00223 00224 EntityHandle * foundIds = new EntityHandle[nP]; 00225 for (i = 0; i < nP; i++) 00226 { 00227 double * pp = &iP[2 * i]; // iP+2*i 00228 // project the point back on the sphere 00229 CartVect pos; 00230 reverse_gnomonic_projection(pp[0], pp[1], R, plane, pos); 00231 int found = 0; 00232 // first, are they on vertices from red or blue? 00233 // priority is the red mesh (mb2?) 00234 int j = 0; 00235 EntityHandle outNode = (EntityHandle) 0; 00236 for (j = 0; j < nsRed && !found; j++) 00237 { 00238 //int node = redTri.v[j]; 00239 double d2 = dist2(pp, &redCoords2D[2 * j]); 00240 if (d2 < epsilon_1) 00241 { 00242 00243 foundIds[i] = redConn[j]; // no new node 00244 found = 1; 00245 if (dbg_1) 00246 std::cout << " red node j:" << j << " id:" 00247 << mb->id_from_handle(redConn[j]) << " 2d coords:" << redCoords2D[2 * j] << " " 00248 << redCoords2D[2 * j + 1] << " d2: " << d2 << " \n"; 00249 } 00250 } 00251 00252 for (j = 0; j < nsBlue && !found; j++) 00253 { 00254 //int node = blueTri.v[j]; 00255 double d2 = dist2(pp, &blueCoords2D[2 * j]); 00256 if (d2 < epsilon_1) 00257 { 00258 // suspect is blueConn[j] corresponding in mbOut 00259 00260 foundIds[i] = blueConn[j]; // no new node 00261 found = 1; 00262 if (dbg_1) 00263 std::cout << " blue node " << j << " " 00264 << mb->id_from_handle(blueConn[j]) << " d2:" << d2 << " \n"; 00265 } 00266 00267 } 00268 if (!found) 00269 { 00270 // find the edge it belongs, first, on the red element 00271 // 00272 for (j = 0; j < nsRed; j++) 00273 { 00274 int j1 = (j + 1) % nsRed; 00275 double area = area2D(&redCoords2D[2 * j], &redCoords2D[2 * j1], pp); 00276 if (dbg_1) 00277 std::cout << " edge " << j << ": " 00278 << mb->id_from_handle(redEdges[j]) << " " << redConn[j] << " " 00279 << redConn[j1] << " area : " << area << "\n"; 00280 if (fabs(area) < epsilon_1/2) 00281 { 00282 // found the edge; now find if there is a point in the list here 00283 //std::vector<EntityHandle> * expts = extraNodesMap[redEdges[j]]; 00284 int indx = -1; 00285 indx = RedEdges.index(redEdges[j]); 00286 std::vector<EntityHandle> * expts = extraNodesVec[indx]; 00287 // if the points pp is between extra points, then just give that id 00288 // if not, create a new point, (check the id) 00289 // get the coordinates of the extra points so far 00290 int nbExtraNodesSoFar = expts->size(); 00291 CartVect * coords1 = new CartVect[nbExtraNodesSoFar]; 00292 mb->get_coords(&(*expts)[0], nbExtraNodesSoFar, &(coords1[0][0])); 00293 //std::list<int>::iterator it; 00294 for (int k = 0; k < nbExtraNodesSoFar && !found; k++) 00295 { 00296 //int pnt = *it; 00297 double d2 = (pos - coords1[k]).length_squared(); 00298 if (d2 < epsilon_1) 00299 { 00300 found = 1; 00301 foundIds[i] = (*expts)[k]; 00302 if (dbg_1) 00303 std::cout << " found node:" << foundIds[i] << std::endl; 00304 } 00305 } 00306 if (!found) 00307 { 00308 // create a new point in 2d (at the intersection) 00309 //foundIds[i] = m_num2dPoints; 00310 //expts.push_back(m_num2dPoints); 00311 // need to create a new node in mbOut 00312 // this will be on the edge, and it will be added to the local list 00313 mb->create_vertex(pos.array(), outNode); 00314 (*expts).push_back(outNode); 00315 foundIds[i] = outNode; 00316 found = 1; 00317 if (dbg_1) 00318 std::cout << " new node: " << outNode << std::endl; 00319 } 00320 delete[] coords1; 00321 } 00322 } 00323 } 00324 if (!found) 00325 { 00326 std::cout << " red quad: "; 00327 for (int j1 = 0; j1 < nsRed; j1++) 00328 { 00329 std::cout << redCoords2D[2 * j1] << " " << redCoords2D[2 * j1 + 1] << "\n"; 00330 } 00331 std::cout << " a point pp is not on a red quad " << *pp << " " << pp[1] 00332 << " red quad " << mb->id_from_handle(red) << " \n"; 00333 delete[] foundIds; 00334 return 1; 00335 } 00336 } 00337 if (dbg_1) 00338 { 00339 std::cout << " candidate polygon: nP" << nP << " plane: " << plane << "\n"; 00340 for (int i1 = 0; i1 < nP; i1++) 00341 std::cout << iP[2 * i1] << " " << iP[2 * i1 + 1] << " " << foundIds[i1] << "\n"; 00342 } 00343 // first, find out if we have nodes collapsed; shrink them 00344 // we may have to reduce nP 00345 // it is possible that some nodes are collapsed after intersection only 00346 // nodes will always be in order (convex intersection) 00347 correct_polygon(foundIds, nP); 00348 // now we can build the triangles, from P array, with foundIds 00349 // we will put them in the out set 00350 if (nP >= 3) 00351 { 00352 EntityHandle polyNew; 00353 mb->create_element(MBPOLYGON, foundIds, nP, polyNew); 00354 mb->add_entities(outSet, &polyNew, 1); 00355 00356 // tag it with the index ids from red and blue sets 00357 int id = rs1.index(blue); // index starts from 0 00358 mb->tag_set_data(blueParentTag, &polyNew, 1, &id); 00359 id = rs2.index(red); 00360 mb->tag_set_data(redParentTag, &polyNew, 1, &id); 00361 00362 static int count=0; 00363 count++; 00364 mb->tag_set_data(countTag, &polyNew, 1, &count); 00365 00366 if (dbg_1) 00367 { 00368 00369 std::cout << "Count: " << count << "\n"; 00370 std::cout << " polygon " << mb->id_from_handle(polyNew) << " nodes: " << nP << " :"; 00371 for (int i1 = 0; i1 < nP; i1++) 00372 std::cout << " " << mb->id_from_handle(foundIds[i1]); 00373 std::cout << " plane: " << plane << "\n"; 00374 std::vector<CartVect> posi(nP); 00375 mb->get_coords(foundIds, nP, &(posi[0][0])); 00376 for (int i1 = 0; i1 < nP; i1++) 00377 std::cout << foundIds[i1]<< " " << posi[i1] << "\n"; 00378 00379 std::stringstream fff; 00380 fff << "file0" << count<< ".vtk"; 00381 mb->write_mesh(fff.str().c_str(), &outSet, 1); 00382 } 00383 00384 } 00385 disable_debug(); 00386 delete[] foundIds; 00387 foundIds = NULL; 00388 return 0; 00389 } 00390 bool Intx2MeshOnSphere::is_inside_element(double xyz[3], EntityHandle eh) 00391 { 00392 int num_nodes; 00393 ErrorCode rval = mb->get_connectivity(eh, redConn, num_nodes); 00394 00395 if (MB_SUCCESS != rval) 00396 return false; 00397 int nsRed = num_nodes; 00398 00399 //CartVect coords[4]; 00400 rval = mb->get_coords(redConn, num_nodes, &(redCoords[0][0])); 00401 if (MB_SUCCESS != rval) 00402 return 1; 00403 CartVect center(0.,0.,0.); 00404 for (int k=0; k<num_nodes; k++) 00405 center += redCoords[k]; 00406 center = 1./num_nodes*center; 00407 decide_gnomonic_plane(center, plane);// output the plane 00408 for (int j = 0; j < nsRed; j++) 00409 { 00410 // populate coords in the plane for decision making 00411 // they should be oriented correctly, positively 00412 int rc = gnomonic_projection(redCoords[j], R, plane, redCoords2D[2 * j], 00413 redCoords2D[2 * j + 1]); 00414 if (rc != 0) 00415 return false; 00416 } 00417 double pt[2]; 00418 CartVect pos(xyz); 00419 int rc=gnomonic_projection(pos, R, plane, pt[0], pt[1]); 00420 if (rc != 0) 00421 return false; 00422 00423 // now, is the projected point inside the red quad? 00424 // cslam utils 00425 if (point_in_interior_of_convex_polygon (redCoords2D, nsRed, pt)) 00426 return true; 00427 return false; 00428 } 00429 00430 ErrorCode Intx2MeshOnSphere::update_tracer_data(EntityHandle out_set, Tag & tagElem, Tag & tagArea) 00431 { 00432 EntityHandle dum = 0; 00433 00434 Tag corrTag; 00435 ErrorCode rval = mb->tag_get_handle(CORRTAGNAME, 00436 1, MB_TYPE_HANDLE, corrTag, 00437 MB_TAG_DENSE, &dum); // it should have been created 00438 ERRORR(rval, "can't get correlation tag"); 00439 00440 Tag gid; 00441 rval = mb->tag_get_handle(GLOBAL_ID_TAG_NAME, 1, MB_TYPE_INTEGER, gid, MB_TAG_DENSE); 00442 ERRORR(rval,"can't get global ID tag" ); 00443 00444 // get all polygons out of out_set; then see where are they coming from 00445 Range polys; 00446 rval = mb->get_entities_by_dimension(out_set, 2, polys); 00447 ERRORR(rval, "can't get polygons out"); 00448 00449 // rs2 is the red range, arrival; rs1 is blue, departure; 00450 // there is a connection between rs1 and rs2, through the corrTag 00451 // corrTag is __correlation 00452 // basically, mb->tag_get_data(corrTag, &(redPoly), 1, &bluePoly); 00453 // also, mb->tag_get_data(corrTag, &(bluePoly), 1, &redPoly); 00454 // we start from rs2 existing, then we have to update something 00455 std::vector<double> currentVals(rs2.size()); 00456 rval = mb->tag_get_data(tagElem, rs2, ¤tVals[0]); 00457 ERRORR(rval, "can't get existing tag values"); 00458 00459 // for each polygon, we have 2 indices: red and blue parents 00460 // we need index blue to update index red? 00461 std::vector<double> newValues(rs2.size(), 0.);// initialize with 0 all of them 00462 // area of the polygon * conc on red (old) current quantity 00463 // finaly, divide by the area of the red 00464 double check_intx_area=0.; 00465 for (Range::iterator it= polys.begin(); it!=polys.end(); it++) 00466 { 00467 EntityHandle poly=*it; 00468 int blueIndex, redIndex; 00469 rval = mb->tag_get_data(blueParentTag, &poly, 1, &blueIndex); 00470 ERRORR(rval, "can't get blue tag"); 00471 EntityHandle blue = rs1[blueIndex]; 00472 rval = mb->tag_get_data(redParentTag, &poly, 1, &redIndex); 00473 ERRORR(rval, "can't get red tag"); 00474 //EntityHandle red = rs2[redIndex]; 00475 // big assumption here, red and blue are "parallel" ;we should have an index from 00476 // blue to red (so a deformed blue corresponds to an arrival red) 00477 double areap = area_spherical_element(mb, poly, R); 00478 check_intx_area+=areap; 00479 // so the departure cell at time t (blueIndex) covers a portion of a redCell 00480 // that quantity will be transported to the redCell at time t+dt 00481 // the blue corresponds to a red arrival 00482 EntityHandle redArr; 00483 rval = mb->tag_get_data(corrTag, &blue, 1, &redArr); 00484 if (0==redArr || MB_TAG_NOT_FOUND==rval) 00485 { 00486 #ifdef USE_MPI 00487 if (!remote_cells) 00488 ERRORR( MB_FAILURE, "no remote cells, failure\n"); 00489 // maybe the element is remote, from another processor 00490 int global_id_blue; 00491 rval = mb->tag_get_data(gid, &blue, 1, &global_id_blue); 00492 ERRORR(rval, "can't get arrival red for corresponding blue gid"); 00493 // find the 00494 int index_in_remote = remote_cells->find(1, global_id_blue); 00495 if (index_in_remote==-1) 00496 ERRORR( MB_FAILURE, "can't find the global id element in remote cells\n"); 00497 remote_cells->vr_wr[index_in_remote] += currentVals[redIndex]*areap; 00498 #endif 00499 } 00500 else if (MB_SUCCESS==rval) 00501 { 00502 int arrRedIndex = rs2.index(redArr); 00503 if (-1 == arrRedIndex) 00504 ERRORR(MB_FAILURE, "can't find the red arrival index"); 00505 newValues[arrRedIndex] += currentVals[redIndex]*areap; 00506 } 00507 00508 else 00509 ERRORR(rval, "can't get arrival red for corresponding "); 00510 } 00511 // now, send back the remote_cells to the processors they came from, with the updated values for 00512 // the tracer mass in a cell 00513 #ifdef USE_MPI 00514 if (remote_cells) 00515 { 00516 // so this means that some cells will be sent back with tracer info to the procs they were sent from 00517 (parcomm->proc_config().crystal_router())->gs_transfer(1, *remote_cells, 0); 00518 // now, look at the global id, find the proper "red" cell with that index and update its mass 00519 //remote_cells->print("remote cells after routing"); 00520 int n = remote_cells->get_n(); 00521 for (int j=0; j<n; j++) 00522 { 00523 EntityHandle redCell = remote_cells->vul_rd[j];// entity handle sent back 00524 int arrRedIndex = rs2.index(redCell); 00525 if (-1 == arrRedIndex) 00526 ERRORR(MB_FAILURE, "can't find the red arrival index"); 00527 newValues[arrRedIndex] += remote_cells->vr_rd[j]; 00528 } 00529 } 00530 #endif /* USE_MPI */ 00531 // now divide by red area (current) 00532 int j=0; 00533 Range::iterator iter = rs2.begin(); 00534 void * data=NULL; //used for stored area 00535 int count =0; 00536 double total_mass_local=0.; 00537 while (iter != rs2.end()) 00538 { 00539 rval = mb->tag_iterate(tagArea, iter, rs2.end(), count, data); 00540 ERRORR(rval, "can't tag iterate"); 00541 double * ptrArea=(double*)data; 00542 for (int i=0; i<count; i++, iter++, j++, ptrArea++) 00543 { 00544 total_mass_local+=newValues[j]; 00545 newValues[j]/= (*ptrArea); 00546 } 00547 } 00548 rval = mb->tag_set_data(tagElem, rs2, &newValues[0]); 00549 ERRORR(rval, "can't set new values tag"); 00550 00551 00552 #ifdef USE_MPI 00553 double total_mass=0.; 00554 double total_intx_area =0; 00555 int mpi_err = MPI_Reduce(&total_mass_local, &total_mass, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); 00556 if (MPI_SUCCESS != mpi_err) return MB_FAILURE; 00557 // now reduce total area 00558 mpi_err = MPI_Reduce(&check_intx_area, &total_intx_area, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); 00559 if (MPI_SUCCESS != mpi_err) return MB_FAILURE; 00560 if (my_rank==0) 00561 { 00562 std::cout <<"total mass now:" << total_mass << "\n"; 00563 std::cout <<"check: total intersection area: (4 * M_PI * R^2): " << 4 * M_PI * R*R << " " << total_intx_area << "\n"; 00564 } 00565 00566 if (remote_cells) 00567 { 00568 delete remote_cells; 00569 remote_cells=NULL; 00570 } 00571 #else 00572 std::cout <<"total mass now:" << total_mass_local << "\n"; 00573 std::cout <<"check: total intersection area: (4 * M_PI * R^2): " << 4 * M_PI * R*R << " " << check_intx_area << "\n"; 00574 #endif 00575 return MB_SUCCESS; 00576 } 00577 } /* namespace moab */