![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 /** \file iMOAB.cpp
00002 */
00003
00004 #include "moab/MOABConfig.h"
00005 #include "moab/Core.hpp"
00006 #include "AEntityFactory.hpp"
00007
00008 #ifdef MOAB_HAVE_MPI
00009 #include "moab_mpi.h"
00010 #include "moab/ParallelComm.hpp"
00011 #include "moab/ParCommGraph.hpp"
00012 #include "moab/ParallelMergeMesh.hpp"
00013 #include "moab/IntxMesh/IntxUtils.hpp"
00014 #endif
00015 #include "DebugOutput.hpp"
00016 #include "moab/iMOAB.h"
00017
00018 /* this is needed because of direct access to hdf5/mhdf */
00019 #ifdef MOAB_HAVE_HDF5
00020 #include "mhdf.h"
00021 #include
00022 #endif
00023
00024 #include "moab/CartVect.hpp"
00025 #include "MBTagConventions.hpp"
00026 #include "moab/MeshTopoUtil.hpp"
00027 #include "moab/ReadUtilIface.hpp"
00028 #include "moab/MergeMesh.hpp"
00029
00030 #ifdef MOAB_HAVE_TEMPESTREMAP
00031 #include "STLStringHelper.h"
00032 #include "moab/IntxMesh/IntxUtils.hpp"
00033
00034 #include "moab/Remapping/TempestRemapper.hpp"
00035 #include "moab/Remapping/TempestOnlineMap.hpp"
00036 #endif
00037
00038 // C++ includes
00039 #include
00040 #include
00041 #include
00042
00043 using namespace moab;
00044
00045 // #define VERBOSE
00046
00047 // global variables ; should they be organized in a structure, for easier references?
00048 // or how do we keep them global?
00049
00050 #ifdef __cplusplus
00051 extern "C" {
00052 #endif
00053
00054 #ifdef MOAB_HAVE_TEMPESTREMAP
00055 struct TempestMapAppData
00056 {
00057 moab::TempestRemapper* remapper;
00058 std::map< std::string, moab::TempestOnlineMap* > weightMaps;
00059 iMOAB_AppID pid_src;
00060 iMOAB_AppID pid_dest;
00061 };
00062 #endif
00063
00064 struct appData
00065 {
00066 EntityHandle file_set;
00067 int global_id; // external component id, unique for application
00068 std::string name;
00069 Range all_verts;
00070 Range local_verts; // it could include shared, but not owned at the interface
00071 // these vertices would be all_verts if no ghosting was required
00072 Range ghost_vertices; // locally ghosted from other processors
00073 Range primary_elems;
00074 Range owned_elems;
00075 Range ghost_elems;
00076 int dimension; // 2 or 3, dimension of primary elements (redundant?)
00077 long num_global_elements; // reunion of all elements in primary_elements; either from hdf5
00078 // reading or from reduce
00079 long num_global_vertices; // reunion of all nodes, after sharing is resolved; it could be
00080 // determined from hdf5 reading
00081 Range mat_sets;
00082 std::map< int, int > matIndex; // map from global block id to index in mat_sets
00083 Range neu_sets;
00084 Range diri_sets;
00085 std::map< std::string, Tag > tagMap;
00086 std::vector< Tag > tagList;
00087 bool point_cloud;
00088 bool is_fortran;
00089
00090 #ifdef MOAB_HAVE_MPI
00091 // constructor for this ParCommGraph takes the joint comm and the MPI groups for each
00092 // application
00093 std::map< int, ParCommGraph* > pgraph; // map from context () to the parcommgraph*
00094 #endif
00095
00096 #ifdef MOAB_HAVE_TEMPESTREMAP
00097 TempestMapAppData tempestData;
00098 #endif
00099 };
00100
00101 struct GlobalContext
00102 {
00103 // are there reasons to have multiple moab inits? Is ref count needed?
00104 Interface* MBI;
00105 // we should also have the default tags stored, initialized
00106 Tag material_tag, neumann_tag, dirichlet_tag,
00107 globalID_tag; // material, neumann, dirichlet, globalID
00108 int refCountMB;
00109 int iArgc;
00110 iMOAB_String* iArgv;
00111 int unused_pid;
00112
00113 std::map< std::string, int > appIdMap; // from app string (uppercase) to app id
00114 std::map< int, int > appIdCompMap; // from component id to app id
00115
00116 #ifdef MOAB_HAVE_MPI
00117 std::vector< ParallelComm* > pcomms; // created in order of applications, one moab::ParallelComm for each
00118
00119 #ifdef MOAB_HAVE_ZOLTAN
00120 // this data structure exists only on the root PE of the coupler
00121 // it will store the buffer with the RCB cuts from which the Zoltan zz structure can be de-serialized,
00122 // to be used in the partitioning
00123 //
00124 std::vector< char > uniqueZoltanBuffer;
00125 #endif
00126
00127 #endif
00128
00129 std::vector< appData > appDatas; // the same order as pcomms
00130 int globalrank, worldprocs;
00131 bool MPI_initialized;
00132
00133 GlobalContext()
00134 {
00135 MBI = 0;
00136 refCountMB = 0;
00137 unused_pid = 0;
00138 }
00139 };
00140
00141 static struct GlobalContext context;
00142
00143 ErrCode iMOAB_Initialize( int argc, iMOAB_String* argv )
00144 {
00145 if( argc ) IMOAB_CHECKPOINTER( argv, 1 );
00146
00147 context.iArgc = argc;
00148 context.iArgv = argv; // shallow copy
00149
00150 if( 0 == context.refCountMB )
00151 {
00152 context.MBI = new( std::nothrow ) moab::Core;
00153 // retrieve the default tags
00154 const char* const shared_set_tag_names[] = {MATERIAL_SET_TAG_NAME, NEUMANN_SET_TAG_NAME, DIRICHLET_SET_TAG_NAME,
00155 GLOBAL_ID_TAG_NAME};
00156 // blocks, visible surfaceBC(neumann), vertexBC (Dirichlet), global id, parallel partition
00157 Tag gtags[4];
00158
00159 for( int i = 0; i < 4; i++ )
00160 {
00161
00162 ErrorCode rval =
00163 context.MBI->tag_get_handle( shared_set_tag_names[i], 1, MB_TYPE_INTEGER, gtags[i], MB_TAG_ANY );MB_CHK_ERR( rval );
00164 }
00165
00166 context.material_tag = gtags[0];
00167 context.neumann_tag = gtags[1];
00168 context.dirichlet_tag = gtags[2];
00169 context.globalID_tag = gtags[3];
00170 }
00171
00172 context.MPI_initialized = false;
00173 #ifdef MOAB_HAVE_MPI
00174 int flagInit;
00175 MPI_Initialized( &flagInit );
00176
00177 if( flagInit && !context.MPI_initialized )
00178 {
00179 MPI_Comm_size( MPI_COMM_WORLD, &context.worldprocs );
00180 MPI_Comm_rank( MPI_COMM_WORLD, &context.globalrank );
00181 context.MPI_initialized = true;
00182 }
00183 #endif
00184
00185 context.refCountMB++;
00186 return moab::MB_SUCCESS;
00187 }
00188
00189 ErrCode iMOAB_InitializeFortran()
00190 {
00191 return iMOAB_Initialize( 0, 0 );
00192 }
00193
00194 ErrCode iMOAB_Finalize()
00195 {
00196 context.refCountMB--;
00197
00198 if( 0 == context.refCountMB )
00199 {
00200 delete context.MBI;
00201 }
00202
00203 return MB_SUCCESS;
00204 }
00205
00206 ErrCode iMOAB_RegisterApplication( const iMOAB_String app_name,
00207 #ifdef MOAB_HAVE_MPI
00208 MPI_Comm* comm,
00209 #endif
00210 int* compid,
00211 iMOAB_AppID pid )
00212 {
00213 IMOAB_CHECKPOINTER( app_name, 1 );
00214 #ifdef MOAB_HAVE_MPI
00215 IMOAB_CHECKPOINTER( comm, 2 );
00216 IMOAB_CHECKPOINTER( compid, 3 );
00217 #else
00218 IMOAB_CHECKPOINTER( compid, 2 );
00219 #endif
00220
00221 // will create a parallel comm for this application too, so there will be a
00222 // mapping from *pid to file set and to parallel comm instances
00223 std::string name( app_name );
00224
00225 if( context.appIdMap.find( name ) != context.appIdMap.end() )
00226 {
00227 std::cout << " application " << name << " already registered \n";
00228 return moab::MB_FAILURE;
00229 }
00230
00231 *pid = context.unused_pid++;
00232 context.appIdMap[name] = *pid;
00233 int rankHere = 0;
00234 #ifdef MOAB_HAVE_MPI
00235 MPI_Comm_rank( *comm, &rankHere );
00236 #endif
00237 if( !rankHere ) std::cout << " application " << name << " with ID = " << *pid << " is registered now \n";
00238 if( *compid <= 0 )
00239 {
00240 std::cout << " convention for external application is to have its id positive \n";
00241 return moab::MB_FAILURE;
00242 }
00243
00244 if( context.appIdCompMap.find( *compid ) != context.appIdCompMap.end() )
00245 {
00246 std::cout << " external application with comp id " << *compid << " is already registered\n";
00247 return moab::MB_FAILURE;
00248 }
00249
00250 context.appIdCompMap[*compid] = *pid;
00251
00252 // now create ParallelComm and a file set for this application
00253 #ifdef MOAB_HAVE_MPI
00254 if( *comm )
00255 {
00256 ParallelComm* pco = new ParallelComm( context.MBI, *comm );
00257
00258 #ifndef NDEBUG
00259 int index = pco->get_id(); // it could be useful to get app id from pcomm instance ...
00260 assert( index == *pid );
00261 // here, we assert the the pid is the same as the id of the ParallelComm instance
00262 // useful for writing in parallel
00263 #endif
00264 context.pcomms.push_back( pco );
00265 }
00266 else
00267 {
00268 context.pcomms.push_back( 0 );
00269 }
00270 #endif
00271
00272 // create now the file set that will be used for loading the model in
00273 EntityHandle file_set;
00274 ErrorCode rval = context.MBI->create_meshset( MESHSET_SET, file_set );MB_CHK_ERR( rval );
00275
00276 appData app_data;
00277 app_data.file_set = file_set;
00278 app_data.global_id = *compid; // will be used mostly for par comm graph
00279 app_data.name = name; // save the name of application
00280
00281 #ifdef MOAB_HAVE_TEMPESTREMAP
00282 app_data.tempestData.remapper = NULL; // Only allocate as needed
00283 #endif
00284
00285 app_data.point_cloud = false;
00286 app_data.is_fortran = false;
00287
00288 context.appDatas.push_back(
00289 app_data ); // it will correspond to app_FileSets[*pid] will be the file set of interest
00290 return moab::MB_SUCCESS;
00291 }
00292
00293 ErrCode iMOAB_RegisterApplicationFortran( const iMOAB_String app_name,
00294 #ifdef MOAB_HAVE_MPI
00295 int* comm,
00296 #endif
00297 int* compid,
00298 iMOAB_AppID pid )
00299 {
00300 IMOAB_CHECKPOINTER( app_name, 1 );
00301 #ifdef MOAB_HAVE_MPI
00302 IMOAB_CHECKPOINTER( comm, 2 );
00303 IMOAB_CHECKPOINTER( compid, 3 );
00304 #else
00305 IMOAB_CHECKPOINTER( compid, 2 );
00306 #endif
00307
00308 ErrCode err;
00309 assert( app_name != nullptr );
00310 std::string name( app_name );
00311
00312 #ifdef MOAB_HAVE_MPI
00313 MPI_Comm ccomm;
00314 if( comm )
00315 {
00316 // convert from Fortran communicator to a C communicator
00317 // see transfer of handles
00318 // http://www.mpi-forum.org/docs/mpi-2.2/mpi22-report/node361.htm
00319 ccomm = MPI_Comm_f2c( (MPI_Fint)*comm );
00320 }
00321 #endif
00322
00323 // now call C style registration function:
00324 err = iMOAB_RegisterApplication( app_name,
00325 #ifdef MOAB_HAVE_MPI
00326 &ccomm,
00327 #endif
00328 compid, pid );
00329
00330 // Now that we have created the application context, store that
00331 // the application being registered is from a Fortran context
00332 context.appDatas[*pid].is_fortran = true;
00333
00334 return err;
00335 }
00336
00337 ErrCode iMOAB_DeregisterApplication( iMOAB_AppID pid )
00338 {
00339 // the file set , parallel comm are all in vectors indexed by *pid
00340 // assume we did not delete anything yet
00341 // *pid will not be reused if we register another application
00342 appData& data = context.appDatas[*pid];
00343 int rankHere = 0;
00344 #ifdef MOAB_HAVE_MPI
00345 ParallelComm* pco = context.pcomms[*pid];
00346 rankHere = pco->rank();
00347 #endif
00348 if( !rankHere )
00349 std::cout << " application with ID: " << *pid << " global id: " << data.global_id << " name: " << data.name
00350 << " is de-registered now \n";
00351
00352 EntityHandle fileSet = data.file_set;
00353 // get all entities part of the file set
00354 Range fileents;
00355 ErrorCode rval = context.MBI->get_entities_by_handle( fileSet, fileents, /*recursive */ true );MB_CHK_ERR( rval );
00356
00357 fileents.insert( fileSet );
00358
00359 rval = context.MBI->get_entities_by_type( fileSet, MBENTITYSET, fileents );MB_CHK_ERR( rval ); // append all mesh sets
00360
00361 #ifdef MOAB_HAVE_TEMPESTREMAP
00362 if( data.tempestData.remapper ) delete data.tempestData.remapper;
00363 if( data.tempestData.weightMaps.size() ) data.tempestData.weightMaps.clear();
00364 #endif
00365
00366 #ifdef MOAB_HAVE_MPI
00367
00368 // we could get the pco also with
00369 // ParallelComm * pcomm = ParallelComm::get_pcomm(context.MBI, *pid);
00370
00371 std::map< int, ParCommGraph* >& pargs = data.pgraph;
00372
00373 // free the parallel comm graphs associated with this app
00374 for( std::map< int, ParCommGraph* >::iterator mt = pargs.begin(); mt != pargs.end(); mt++ )
00375 {
00376 ParCommGraph* pgr = mt->second;
00377 delete pgr;
00378 pgr = NULL;
00379 }
00380 if( pco ) delete pco;
00381 #endif
00382
00383 // delete first all except vertices
00384 Range vertices = fileents.subset_by_type( MBVERTEX );
00385 Range noverts = subtract( fileents, vertices );
00386
00387 rval = context.MBI->delete_entities( noverts );MB_CHK_ERR( rval );
00388 // now retrieve connected elements that still exist (maybe in other sets, pids?)
00389 Range adj_ents_left;
00390 rval = context.MBI->get_adjacencies( vertices, 1, false, adj_ents_left, Interface::UNION );MB_CHK_ERR( rval );
00391 rval = context.MBI->get_adjacencies( vertices, 2, false, adj_ents_left, Interface::UNION );MB_CHK_ERR( rval );
00392 rval = context.MBI->get_adjacencies( vertices, 3, false, adj_ents_left, Interface::UNION );MB_CHK_ERR( rval );
00393
00394 if( !adj_ents_left.empty() )
00395 {
00396 Range conn_verts;
00397 rval = context.MBI->get_connectivity( adj_ents_left, conn_verts );MB_CHK_ERR( rval );
00398 vertices = subtract( vertices, conn_verts );
00399 }
00400
00401 rval = context.MBI->delete_entities( vertices );MB_CHK_ERR( rval );
00402
00403 std::map< std::string, int >::iterator mit;
00404
00405 for( mit = context.appIdMap.begin(); mit != context.appIdMap.end(); mit++ )
00406 {
00407 int pidx = mit->second;
00408
00409 if( *pid == pidx )
00410 {
00411 break;
00412 }
00413 }
00414
00415 context.appIdMap.erase( mit );
00416 std::map< int, int >::iterator mit1;
00417
00418 for( mit1 = context.appIdCompMap.begin(); mit1 != context.appIdCompMap.end(); mit1++ )
00419 {
00420 int pidx = mit1->second;
00421
00422 if( *pid == pidx )
00423 {
00424 break;
00425 }
00426 }
00427
00428 context.appIdCompMap.erase( mit1 );
00429
00430 context.unused_pid--; // we have to go backwards always TODO
00431 context.appDatas.pop_back();
00432 #ifdef MOAB_HAVE_MPI
00433 context.pcomms.pop_back();
00434 #endif
00435 return moab::MB_SUCCESS;
00436 }
00437
00438 ErrCode iMOAB_DeregisterApplicationFortran( iMOAB_AppID pid )
00439 {
00440 // release any Fortran specific allocations here before we pass it on
00441 context.appDatas[*pid].is_fortran = false;
00442
00443 // release all datastructure allocations
00444 return iMOAB_DeregisterApplication( pid );
00445 }
00446
00447 // Utility function
00448 static void split_tag_names( std::string input_names,
00449 std::string& separator,
00450 std::vector< std::string >& list_tag_names )
00451 {
00452 size_t pos = 0;
00453 std::string token;
00454 while( ( pos = input_names.find( separator ) ) != std::string::npos )
00455 {
00456 token = input_names.substr( 0, pos );
00457 if( !token.empty() ) list_tag_names.push_back( token );
00458 // std::cout << token << std::endl;
00459 input_names.erase( 0, pos + separator.length() );
00460 }
00461 if( !input_names.empty() )
00462 {
00463 // if leftover something, or if not ended with delimiter
00464 list_tag_names.push_back( input_names );
00465 }
00466 return;
00467 }
00468
00469 ErrCode iMOAB_ReadHeaderInfo( const iMOAB_String filename,
00470 int* num_global_vertices,
00471 int* num_global_elements,
00472 int* num_dimension,
00473 int* num_parts )
00474 {
00475 IMOAB_CHECKPOINTER( filename, 1 );
00476 IMOAB_ASSERT( strlen( filename ), "Invalid filename length." );
00477
00478 #ifdef MOAB_HAVE_HDF5
00479 std::string filen( filename );
00480
00481 int edges = 0;
00482 int faces = 0;
00483 int regions = 0;
00484 if( num_global_vertices ) *num_global_vertices = 0;
00485 if( num_global_elements ) *num_global_elements = 0;
00486 if( num_dimension ) *num_dimension = 0;
00487 if( num_parts ) *num_parts = 0;
00488
00489 mhdf_FileHandle file;
00490 mhdf_Status status;
00491 unsigned long max_id;
00492 struct mhdf_FileDesc* data;
00493
00494 file = mhdf_openFile( filen.c_str(), 0, &max_id, -1, &status );
00495
00496 if( mhdf_isError( &status ) )
00497 {
00498 fprintf( stderr, "%s: %s\n", filename, mhdf_message( &status ) );
00499 return moab::MB_FAILURE;
00500 }
00501
00502 data = mhdf_getFileSummary( file, H5T_NATIVE_ULONG, &status,
00503 1 ); // will use extra set info; will get parallel partition tag info too!
00504
00505 if( mhdf_isError( &status ) )
00506 {
00507 fprintf( stderr, "%s: %s\n", filename, mhdf_message( &status ) );
00508 return moab::MB_FAILURE;
00509 }
00510
00511 if( num_dimension ) *num_dimension = data->nodes.vals_per_ent;
00512 if( num_global_vertices ) *num_global_vertices = (int)data->nodes.count;
00513
00514 for( int i = 0; i < data->num_elem_desc; i++ )
00515 {
00516 struct mhdf_ElemDesc* el_desc = &( data->elems[i] );
00517 struct mhdf_EntDesc* ent_d = &( el_desc->desc );
00518
00519 if( 0 == strcmp( el_desc->type, mhdf_EDGE_TYPE_NAME ) )
00520 {
00521 edges += ent_d->count;
00522 }
00523
00524 if( 0 == strcmp( el_desc->type, mhdf_TRI_TYPE_NAME ) )
00525 {
00526 faces += ent_d->count;
00527 }
00528
00529 if( 0 == strcmp( el_desc->type, mhdf_QUAD_TYPE_NAME ) )
00530 {
00531 faces += ent_d->count;
00532 }
00533
00534 if( 0 == strcmp( el_desc->type, mhdf_POLYGON_TYPE_NAME ) )
00535 {
00536 faces += ent_d->count;
00537 }
00538
00539 if( 0 == strcmp( el_desc->type, mhdf_TET_TYPE_NAME ) )
00540 {
00541 regions += ent_d->count;
00542 }
00543
00544 if( 0 == strcmp( el_desc->type, mhdf_PYRAMID_TYPE_NAME ) )
00545 {
00546 regions += ent_d->count;
00547 }
00548
00549 if( 0 == strcmp( el_desc->type, mhdf_PRISM_TYPE_NAME ) )
00550 {
00551 regions += ent_d->count;
00552 }
00553
00554 if( 0 == strcmp( el_desc->type, mdhf_KNIFE_TYPE_NAME ) )
00555 {
00556 regions += ent_d->count;
00557 }
00558
00559 if( 0 == strcmp( el_desc->type, mdhf_HEX_TYPE_NAME ) )
00560 {
00561 regions += ent_d->count;
00562 }
00563
00564 if( 0 == strcmp( el_desc->type, mhdf_POLYHEDRON_TYPE_NAME ) )
00565 {
00566 regions += ent_d->count;
00567 }
00568
00569 if( 0 == strcmp( el_desc->type, mhdf_SEPTAHEDRON_TYPE_NAME ) )
00570 {
00571 regions += ent_d->count;
00572 }
00573 }
00574
00575 if( num_parts ) *num_parts = data->numEntSets[0];
00576
00577 // is this required?
00578 if( edges > 0 )
00579 {
00580 if( num_dimension ) *num_dimension = 1; // I don't think it will ever return 1
00581 if( num_global_elements ) *num_global_elements = edges;
00582 }
00583
00584 if( faces > 0 )
00585 {
00586 if( num_dimension ) *num_dimension = 2;
00587 if( num_global_elements ) *num_global_elements = faces;
00588 }
00589
00590 if( regions > 0 )
00591 {
00592 if( num_dimension ) *num_dimension = 3;
00593 if( num_global_elements ) *num_global_elements = regions;
00594 }
00595
00596 mhdf_closeFile( file, &status );
00597
00598 free( data );
00599
00600 #else
00601 std::cout << filename
00602 << ": Please reconfigure with HDF5. Cannot retrieve header information for file "
00603 "formats other than a h5m file.\n";
00604 if( num_global_vertices ) *num_global_vertices = 0;
00605 if( num_global_elements ) *num_global_elements = 0;
00606 if( num_dimension ) *num_dimension = 0;
00607 if( num_parts ) *num_parts = 0;
00608 #endif
00609
00610 return moab::MB_SUCCESS;
00611 }
00612
00613 ErrCode iMOAB_LoadMesh( iMOAB_AppID pid,
00614 const iMOAB_String filename,
00615 const iMOAB_String read_options,
00616 int* num_ghost_layers )
00617 {
00618 IMOAB_CHECKPOINTER( filename, 2 );
00619 IMOAB_ASSERT( strlen( filename ), "Invalid filename length." );
00620
00621 // make sure we use the file set and pcomm associated with the *pid
00622 std::ostringstream newopts;
00623 if( read_options ) newopts << read_options;
00624
00625 #ifdef MOAB_HAVE_MPI
00626
00627 if( context.MPI_initialized )
00628 {
00629 if( context.worldprocs > 1 )
00630 {
00631 std::string opts( ( read_options ? read_options : "" ) );
00632 std::string pcid( "PARALLEL_COMM=" );
00633 std::size_t found = opts.find( pcid );
00634
00635 if( found != std::string::npos )
00636 {
00637 std::cerr << " cannot specify PARALLEL_COMM option, it is implicit \n";
00638 return moab::MB_FAILURE;
00639 }
00640
00641 // in serial, apply PARALLEL_COMM option only for h5m files; it does not work for .g
00642 // files (used in test_remapping)
00643 std::string filen( filename );
00644 std::string::size_type idx = filen.rfind( '.' );
00645
00646 if( idx != std::string::npos )
00647 {
00648 std::string extension = filen.substr( idx + 1 );
00649 if( ( extension == std::string( "h5m" ) ) || ( extension == std::string( "nc" ) ) )
00650 newopts << ";;PARALLEL_COMM=" << *pid;
00651 }
00652
00653 if( *num_ghost_layers >= 1 )
00654 {
00655 // if we want ghosts, we will want additional entities, the last .1
00656 // because the addl ents can be edges, faces that are part of the neumann sets
00657 std::string pcid2( "PARALLEL_GHOSTS=" );
00658 std::size_t found2 = opts.find( pcid2 );
00659
00660 if( found2 != std::string::npos )
00661 {
00662 std::cout << " PARALLEL_GHOSTS option is already specified, ignore passed "
00663 "number of layers \n";
00664 }
00665 else
00666 {
00667 // dimension of primary entities is 3 here, but it could be 2 for climate
00668 // meshes; we would need to pass PARALLEL_GHOSTS explicitly for 2d meshes, for
00669 // example: ";PARALLEL_GHOSTS=2.0.1"
00670 newopts << ";PARALLEL_GHOSTS=3.0." << *num_ghost_layers << ".3";
00671 }
00672 }
00673 }
00674 }
00675 #else
00676 IMOAB_ASSERT( *num_ghost_layers == 0, "Cannot provide ghost layers in serial." );
00677 #endif
00678
00679 // Now let us actually load the MOAB file with the appropriate read options
00680 ErrorCode rval = context.MBI->load_file( filename, &context.appDatas[*pid].file_set, newopts.str().c_str() );MB_CHK_ERR( rval );
00681
00682 #ifdef VERBOSE
00683 // some debugging stuff
00684 std::ostringstream outfile;
00685 #ifdef MOAB_HAVE_MPI
00686 int rank = context.pcomms[*pid]->rank();
00687 int nprocs = context.pcomms[*pid]->size();
00688 outfile << "TaskMesh_n" << nprocs << "." << rank << ".h5m";
00689 #else
00690 outfile << "TaskMesh_n1.0.h5m";
00691 #endif
00692 // the mesh contains ghosts too, but they are not part of mat/neumann set
00693 // write in serial the file, to see what tags are missing
00694 rval = context.MBI->write_file( outfile.str().c_str() );MB_CHK_ERR( rval ); // everything on current task, written in serial
00695 #endif
00696
00697 // Update mesh information
00698 return iMOAB_UpdateMeshInfo( pid );
00699 }
00700
00701 ErrCode iMOAB_WriteMesh( iMOAB_AppID pid, const iMOAB_String filename, const iMOAB_String write_options )
00702 {
00703 IMOAB_CHECKPOINTER( filename, 2 );
00704 IMOAB_ASSERT( strlen( filename ), "Invalid filename length." );
00705
00706 appData& data = context.appDatas[*pid];
00707 EntityHandle fileSet = data.file_set;
00708
00709 std::ostringstream newopts;
00710 #ifdef MOAB_HAVE_MPI
00711 std::string write_opts( ( write_options ? write_options : "" ) );
00712 std::string pcid( "PARALLEL_COMM=" );
00713 std::size_t found = write_opts.find( pcid );
00714
00715 if( found != std::string::npos )
00716 {
00717 std::cerr << " cannot specify PARALLEL_COMM option, it is implicit \n";
00718 return moab::MB_FAILURE;
00719 }
00720
00721 // if write in parallel, add pc option, to be sure about which ParallelComm instance is used
00722 std::string pw( "PARALLEL=WRITE_PART" );
00723 found = write_opts.find( pw );
00724
00725 if( found != std::string::npos )
00726 {
00727 newopts << "PARALLEL_COMM=" << *pid << ";";
00728 }
00729
00730 #endif
00731
00732 if( write_options ) newopts << write_options;
00733
00734 std::vector< Tag > copyTagList = data.tagList;
00735 // append Global ID and Parallel Partition
00736 std::string gid_name_tag( "GLOBAL_ID" );
00737
00738 // export global id tag, we need it always
00739 if( data.tagMap.find( gid_name_tag ) == data.tagMap.end() )
00740 {
00741 Tag gid = context.MBI->globalId_tag();
00742 copyTagList.push_back( gid );
00743 }
00744 // also Parallel_Partition PARALLEL_PARTITION
00745 std::string pp_name_tag( "PARALLEL_PARTITION" );
00746
00747 // write parallel part tag too, if it exists
00748 if( data.tagMap.find( pp_name_tag ) == data.tagMap.end() )
00749 {
00750 Tag ptag;
00751 context.MBI->tag_get_handle( pp_name_tag.c_str(), ptag );
00752 if( ptag ) copyTagList.push_back( ptag );
00753 }
00754
00755 // Now let us actually write the file to disk with appropriate options
00756 ErrorCode rval = context.MBI->write_file( filename, 0, newopts.str().c_str(), &fileSet, 1, ©TagList[0],
00757 (int)copyTagList.size() );MB_CHK_ERR( rval );
00758
00759 return moab::MB_SUCCESS;
00760 }
00761
00762 ErrCode iMOAB_WriteLocalMesh( iMOAB_AppID pid, iMOAB_String prefix )
00763 {
00764 IMOAB_CHECKPOINTER( prefix, 2 );
00765 IMOAB_ASSERT( strlen( prefix ), "Invalid prefix string length." );
00766
00767 std::ostringstream file_name;
00768 int rank = 0, size = 1;
00769 #ifdef MOAB_HAVE_MPI
00770 rank = context.pcomms[*pid]->rank();
00771 size = context.pcomms[*pid]->size();
00772 #endif
00773 file_name << prefix << "_" << size << "_" << rank << ".h5m";
00774 // Now let us actually write the file to disk with appropriate options
00775 ErrorCode rval = context.MBI->write_file( file_name.str().c_str(), 0, 0, &context.appDatas[*pid].file_set, 1 );MB_CHK_ERR( rval );
00776
00777 return moab::MB_SUCCESS;
00778 }
00779
00780 ErrCode iMOAB_UpdateMeshInfo( iMOAB_AppID pid )
00781 {
00782 // this will include ghost elements info
00783 appData& data = context.appDatas[*pid];
00784 EntityHandle fileSet = data.file_set;
00785
00786 // first clear all data ranges; this can be called after ghosting
00787 data.all_verts.clear();
00788 data.primary_elems.clear();
00789 data.local_verts.clear();
00790 data.ghost_vertices.clear();
00791 data.owned_elems.clear();
00792 data.ghost_elems.clear();
00793 data.mat_sets.clear();
00794 data.neu_sets.clear();
00795 data.diri_sets.clear();
00796
00797 // Let us get all the vertex entities
00798 ErrorCode rval = context.MBI->get_entities_by_type( fileSet, MBVERTEX, data.all_verts, true );MB_CHK_ERR( rval ); // recursive
00799
00800 // Let us check first entities of dimension = 3
00801 data.dimension = 3;
00802 rval = context.MBI->get_entities_by_dimension( fileSet, data.dimension, data.primary_elems, true );MB_CHK_ERR( rval ); // recursive
00803
00804 if( data.primary_elems.empty() )
00805 {
00806 // Now 3-D elements. Let us check entities of dimension = 2
00807 data.dimension = 2;
00808 rval = context.MBI->get_entities_by_dimension( fileSet, data.dimension, data.primary_elems, true );MB_CHK_ERR( rval ); // recursive
00809
00810 if( data.primary_elems.empty() )
00811 {
00812 // Now 3-D/2-D elements. Let us check entities of dimension = 1
00813 data.dimension = 1;
00814 rval = context.MBI->get_entities_by_dimension( fileSet, data.dimension, data.primary_elems, true );MB_CHK_ERR( rval ); // recursive
00815
00816 if( data.primary_elems.empty() )
00817 {
00818 // no elements of dimension 1 or 2 or 3; it could happen for point clouds
00819 data.dimension = 0;
00820 if( data.all_verts.size() == 0 ) data.dimension = -1; // nothing on this
00821 }
00822 }
00823 }
00824
00825 // check if the current mesh is just a point cloud
00826 data.point_cloud = ( ( data.primary_elems.size() == 0 && data.all_verts.size() > 0 ) || data.dimension == 0 );
00827
00828 #ifdef MOAB_HAVE_MPI
00829
00830 if( context.MPI_initialized )
00831 {
00832 ParallelComm* pco = context.pcomms[*pid];
00833
00834 // filter ghost vertices, from local
00835 rval = pco->filter_pstatus( data.all_verts, PSTATUS_GHOST, PSTATUS_NOT, -1, &data.local_verts );MB_CHK_ERR( rval );
00836
00837 // Store handles for all ghosted entities
00838 data.ghost_vertices = subtract( data.all_verts, data.local_verts );
00839
00840 // filter ghost elements, from local
00841 rval = pco->filter_pstatus( data.primary_elems, PSTATUS_GHOST, PSTATUS_NOT, -1, &data.owned_elems );MB_CHK_ERR( rval );
00842
00843 data.ghost_elems = subtract( data.primary_elems, data.owned_elems );
00844 }
00845 else
00846 {
00847 data.local_verts = data.all_verts;
00848 data.owned_elems = data.primary_elems;
00849 }
00850
00851 #else
00852
00853 data.local_verts = data.all_verts;
00854 data.owned_elems = data.primary_elems;
00855
00856 #endif
00857
00858 // Get the references for some standard internal tags such as material blocks, BCs, etc
00859 rval = context.MBI->get_entities_by_type_and_tag( fileSet, MBENTITYSET, &( context.material_tag ), 0, 1,
00860 data.mat_sets, Interface::UNION );MB_CHK_ERR( rval );
00861
00862 rval = context.MBI->get_entities_by_type_and_tag( fileSet, MBENTITYSET, &( context.neumann_tag ), 0, 1,
00863 data.neu_sets, Interface::UNION );MB_CHK_ERR( rval );
00864
00865 rval = context.MBI->get_entities_by_type_and_tag( fileSet, MBENTITYSET, &( context.dirichlet_tag ), 0, 1,
00866 data.diri_sets, Interface::UNION );MB_CHK_ERR( rval );
00867
00868 return moab::MB_SUCCESS;
00869 }
00870
00871 ErrCode iMOAB_GetMeshInfo( iMOAB_AppID pid,
00872 int* num_visible_vertices,
00873 int* num_visible_elements,
00874 int* num_visible_blocks,
00875 int* num_visible_surfaceBC,
00876 int* num_visible_vertexBC )
00877 {
00878 ErrorCode rval;
00879 appData& data = context.appDatas[*pid];
00880 EntityHandle fileSet = data.file_set;
00881
00882 // this will include ghost elements
00883 // first clear all data ranges; this can be called after ghosting
00884 if( num_visible_elements )
00885 {
00886 num_visible_elements[2] = static_cast< int >( data.primary_elems.size() );
00887 // separate ghost and local/owned primary elements
00888 num_visible_elements[0] = static_cast< int >( data.owned_elems.size() );
00889 num_visible_elements[1] = static_cast< int >( data.ghost_elems.size() );
00890 }
00891 if( num_visible_vertices )
00892 {
00893 num_visible_vertices[2] = static_cast< int >( data.all_verts.size() );
00894 num_visible_vertices[1] = static_cast< int >( data.ghost_vertices.size() );
00895 // local are those that are not ghosts
00896 num_visible_vertices[0] = num_visible_vertices[2] - num_visible_vertices[1];
00897 }
00898
00899 if( num_visible_blocks )
00900 {
00901 rval = context.MBI->get_entities_by_type_and_tag( fileSet, MBENTITYSET, &( context.material_tag ), 0, 1,
00902 data.mat_sets, Interface::UNION );MB_CHK_ERR( rval );
00903
00904 num_visible_blocks[2] = data.mat_sets.size();
00905 num_visible_blocks[0] = num_visible_blocks[2];
00906 num_visible_blocks[1] = 0;
00907 }
00908
00909 if( num_visible_surfaceBC )
00910 {
00911 rval = context.MBI->get_entities_by_type_and_tag( fileSet, MBENTITYSET, &( context.neumann_tag ), 0, 1,
00912 data.neu_sets, Interface::UNION );MB_CHK_ERR( rval );
00913
00914 num_visible_surfaceBC[2] = 0;
00915 // count how many faces are in each neu set, and how many regions are
00916 // adjacent to them;
00917 int numNeuSets = (int)data.neu_sets.size();
00918
00919 for( int i = 0; i < numNeuSets; i++ )
00920 {
00921 Range subents;
00922 EntityHandle nset = data.neu_sets[i];
00923 rval = context.MBI->get_entities_by_dimension( nset, data.dimension - 1, subents );MB_CHK_ERR( rval );
00924
00925 for( Range::iterator it = subents.begin(); it != subents.end(); ++it )
00926 {
00927 EntityHandle subent = *it;
00928 Range adjPrimaryEnts;
00929 rval = context.MBI->get_adjacencies( &subent, 1, data.dimension, false, adjPrimaryEnts );MB_CHK_ERR( rval );
00930
00931 num_visible_surfaceBC[2] += (int)adjPrimaryEnts.size();
00932 }
00933 }
00934
00935 num_visible_surfaceBC[0] = num_visible_surfaceBC[2];
00936 num_visible_surfaceBC[1] = 0;
00937 }
00938
00939 if( num_visible_vertexBC )
00940 {
00941 rval = context.MBI->get_entities_by_type_and_tag( fileSet, MBENTITYSET, &( context.dirichlet_tag ), 0, 1,
00942 data.diri_sets, Interface::UNION );MB_CHK_ERR( rval );
00943
00944 num_visible_vertexBC[2] = 0;
00945 int numDiriSets = (int)data.diri_sets.size();
00946
00947 for( int i = 0; i < numDiriSets; i++ )
00948 {
00949 Range verts;
00950 EntityHandle diset = data.diri_sets[i];
00951 rval = context.MBI->get_entities_by_dimension( diset, 0, verts );MB_CHK_ERR( rval );
00952
00953 num_visible_vertexBC[2] += (int)verts.size();
00954 }
00955
00956 num_visible_vertexBC[0] = num_visible_vertexBC[2];
00957 num_visible_vertexBC[1] = 0;
00958 }
00959
00960 return moab::MB_SUCCESS;
00961 }
00962
00963 ErrCode iMOAB_GetVertexID( iMOAB_AppID pid, int* vertices_length, iMOAB_GlobalID* global_vertex_ID )
00964 {
00965 IMOAB_CHECKPOINTER( vertices_length, 2 );
00966 IMOAB_CHECKPOINTER( global_vertex_ID, 3 );
00967
00968 const Range& verts = context.appDatas[*pid].all_verts;
00969 // check for problems with array length
00970 IMOAB_ASSERT( *vertices_length == static_cast< int >( verts.size() ), "Invalid vertices length provided" );
00971
00972 // global id tag is context.globalID_tag
00973 return context.MBI->tag_get_data( context.globalID_tag, verts, global_vertex_ID );
00974 }
00975
00976 ErrCode iMOAB_GetVertexOwnership( iMOAB_AppID pid, int* vertices_length, int* visible_global_rank_ID )
00977 {
00978 assert( vertices_length && *vertices_length );
00979 assert( visible_global_rank_ID );
00980
00981 Range& verts = context.appDatas[*pid].all_verts;
00982 int i = 0;
00983 #ifdef MOAB_HAVE_MPI
00984 ParallelComm* pco = context.pcomms[*pid];
00985
00986 for( Range::iterator vit = verts.begin(); vit != verts.end(); vit++, i++ )
00987 {
00988 ErrorCode rval = pco->get_owner( *vit, visible_global_rank_ID[i] );MB_CHK_ERR( rval );
00989 }
00990
00991 if( i != *vertices_length )
00992 {
00993 return moab::MB_FAILURE;
00994 } // warning array allocation problem
00995
00996 #else
00997
00998 /* everything owned by proc 0 */
00999 if( (int)verts.size() != *vertices_length )
01000 {
01001 return moab::MB_FAILURE;
01002 } // warning array allocation problem
01003
01004 for( Range::iterator vit = verts.begin(); vit != verts.end(); vit++, i++ )
01005 {
01006 visible_global_rank_ID[i] = 0;
01007 } // all vertices are owned by processor 0, as this is serial run
01008
01009 #endif
01010
01011 return moab::MB_SUCCESS;
01012 }
01013
01014 ErrCode iMOAB_GetVisibleVerticesCoordinates( iMOAB_AppID pid, int* coords_length, double* coordinates )
01015 {
01016 Range& verts = context.appDatas[*pid].all_verts;
01017
01018 // interleaved coordinates, so that means deep copy anyway
01019 if( *coords_length != 3 * (int)verts.size() )
01020 {
01021 return moab::MB_FAILURE;
01022 }
01023
01024 ErrorCode rval = context.MBI->get_coords( verts, coordinates );MB_CHK_ERR( rval );
01025
01026 return moab::MB_SUCCESS;
01027 }
01028
01029 ErrCode iMOAB_GetBlockID( iMOAB_AppID pid, int* block_length, iMOAB_GlobalID* global_block_IDs )
01030 {
01031 // local id blocks? they are counted from 0 to number of visible blocks ...
01032 // will actually return material set tag value for global
01033 Range& matSets = context.appDatas[*pid].mat_sets;
01034
01035 if( *block_length != (int)matSets.size() )
01036 {
01037 return moab::MB_FAILURE;
01038 }
01039
01040 // return material set tag gtags[0 is material set tag
01041 ErrorCode rval = context.MBI->tag_get_data( context.material_tag, matSets, global_block_IDs );MB_CHK_ERR( rval );
01042
01043 // populate map with index
01044 std::map< int, int >& matIdx = context.appDatas[*pid].matIndex;
01045 for( unsigned i = 0; i < matSets.size(); i++ )
01046 {
01047 matIdx[global_block_IDs[i]] = i;
01048 }
01049
01050 return moab::MB_SUCCESS;
01051 }
01052
01053 ErrCode iMOAB_GetBlockInfo( iMOAB_AppID pid,
01054 iMOAB_GlobalID* global_block_ID,
01055 int* vertices_per_element,
01056 int* num_elements_in_block )
01057 {
01058 assert( global_block_ID );
01059
01060 std::map< int, int >& matMap = context.appDatas[*pid].matIndex;
01061 std::map< int, int >::iterator it = matMap.find( *global_block_ID );
01062
01063 if( it == matMap.end() )
01064 {
01065 return moab::MB_FAILURE;
01066 } // error in finding block with id
01067
01068 int blockIndex = matMap[*global_block_ID];
01069 EntityHandle matMeshSet = context.appDatas[*pid].mat_sets[blockIndex];
01070 Range blo_elems;
01071 ErrorCode rval = context.MBI->get_entities_by_handle( matMeshSet, blo_elems );
01072
01073 if( MB_SUCCESS != rval || blo_elems.empty() )
01074 {
01075 return moab::MB_FAILURE;
01076 }
01077
01078 EntityType type = context.MBI->type_from_handle( blo_elems[0] );
01079
01080 if( !blo_elems.all_of_type( type ) )
01081 {
01082 return moab::MB_FAILURE;
01083 } // not all of same type
01084
01085 const EntityHandle* conn = NULL;
01086 int num_verts = 0;
01087 rval = context.MBI->get_connectivity( blo_elems[0], conn, num_verts );MB_CHK_ERR( rval );
01088
01089 *vertices_per_element = num_verts;
01090 *num_elements_in_block = (int)blo_elems.size();
01091
01092 return moab::MB_SUCCESS;
01093 }
01094
01095 ErrCode iMOAB_GetVisibleElementsInfo( iMOAB_AppID pid,
01096 int* num_visible_elements,
01097 iMOAB_GlobalID* element_global_IDs,
01098 int* ranks,
01099 iMOAB_GlobalID* block_IDs )
01100 {
01101 appData& data = context.appDatas[*pid];
01102 #ifdef MOAB_HAVE_MPI
01103 ParallelComm* pco = context.pcomms[*pid];
01104 #endif
01105
01106 ErrorCode rval = context.MBI->tag_get_data( context.globalID_tag, data.primary_elems, element_global_IDs );MB_CHK_ERR( rval );
01107
01108 int i = 0;
01109
01110 for( Range::iterator eit = data.primary_elems.begin(); eit != data.primary_elems.end(); ++eit, ++i )
01111 {
01112 #ifdef MOAB_HAVE_MPI
01113 rval = pco->get_owner( *eit, ranks[i] );MB_CHK_ERR( rval );
01114
01115 #else
01116 /* everything owned by task 0 */
01117 ranks[i] = 0;
01118 #endif
01119 }
01120
01121 for( Range::iterator mit = data.mat_sets.begin(); mit != data.mat_sets.end(); ++mit )
01122 {
01123 EntityHandle matMeshSet = *mit;
01124 Range elems;
01125 rval = context.MBI->get_entities_by_handle( matMeshSet, elems );MB_CHK_ERR( rval );
01126
01127 int valMatTag;
01128 rval = context.MBI->tag_get_data( context.material_tag, &matMeshSet, 1, &valMatTag );MB_CHK_ERR( rval );
01129
01130 for( Range::iterator eit = elems.begin(); eit != elems.end(); ++eit )
01131 {
01132 EntityHandle eh = *eit;
01133 int index = data.primary_elems.index( eh );
01134
01135 if( -1 == index )
01136 {
01137 return moab::MB_FAILURE;
01138 }
01139
01140 if( -1 >= *num_visible_elements )
01141 {
01142 return moab::MB_FAILURE;
01143 }
01144
01145 block_IDs[index] = valMatTag;
01146 }
01147 }
01148
01149 return moab::MB_SUCCESS;
01150 }
01151
01152 ErrCode iMOAB_GetBlockElementConnectivities( iMOAB_AppID pid,
01153 iMOAB_GlobalID* global_block_ID,
01154 int* connectivity_length,
01155 int* element_connectivity )
01156 {
01157 assert( global_block_ID ); // ensure global block ID argument is not null
01158 assert( connectivity_length ); // ensure connectivity length argument is not null
01159
01160 appData& data = context.appDatas[*pid];
01161 std::map< int, int >& matMap = data.matIndex;
01162 std::map< int, int >::iterator it = matMap.find( *global_block_ID );
01163
01164 if( it == matMap.end() )
01165 {
01166 return moab::MB_FAILURE;
01167 } // error in finding block with id
01168
01169 int blockIndex = matMap[*global_block_ID];
01170 EntityHandle matMeshSet = data.mat_sets[blockIndex];
01171 std::vector< EntityHandle > elems;
01172
01173 ErrorCode rval = context.MBI->get_entities_by_handle( matMeshSet, elems );MB_CHK_ERR( rval );
01174
01175 if( elems.empty() )
01176 {
01177 return moab::MB_FAILURE;
01178 }
01179
01180 std::vector< EntityHandle > vconnect;
01181 rval = context.MBI->get_connectivity( &elems[0], elems.size(), vconnect );MB_CHK_ERR( rval );
01182
01183 if( *connectivity_length != (int)vconnect.size() )
01184 {
01185 return moab::MB_FAILURE;
01186 } // mismatched sizes
01187
01188 for( int i = 0; i < *connectivity_length; i++ )
01189 {
01190 int inx = data.all_verts.index( vconnect[i] );
01191
01192 if( -1 == inx )
01193 {
01194 return moab::MB_FAILURE;
01195 } // error, vertex not in local range
01196
01197 element_connectivity[i] = inx;
01198 }
01199
01200 return moab::MB_SUCCESS;
01201 }
01202
01203 ErrCode iMOAB_GetElementConnectivity( iMOAB_AppID pid,
01204 iMOAB_LocalID* elem_index,
01205 int* connectivity_length,
01206 int* element_connectivity )
01207 {
01208 assert( elem_index ); // ensure element index argument is not null
01209 assert( connectivity_length ); // ensure connectivity length argument is not null
01210
01211 appData& data = context.appDatas[*pid];
01212 assert( ( *elem_index >= 0 ) && ( *elem_index < (int)data.primary_elems.size() ) );
01213
01214 int num_nodes;
01215 const EntityHandle* conn;
01216
01217 EntityHandle eh = data.primary_elems[*elem_index];
01218
01219 ErrorCode rval = context.MBI->get_connectivity( eh, conn, num_nodes );MB_CHK_ERR( rval );
01220
01221 if( *connectivity_length < num_nodes )
01222 {
01223 return moab::MB_FAILURE;
01224 } // wrong number of vertices
01225
01226 for( int i = 0; i < num_nodes; i++ )
01227 {
01228 int index = data.all_verts.index( conn[i] );
01229
01230 if( -1 == index )
01231 {
01232 return moab::MB_FAILURE;
01233 }
01234
01235 element_connectivity[i] = index;
01236 }
01237
01238 *connectivity_length = num_nodes;
01239
01240 return moab::MB_SUCCESS;
01241 }
01242
01243 ErrCode iMOAB_GetElementOwnership( iMOAB_AppID pid,
01244 iMOAB_GlobalID* global_block_ID,
01245 int* num_elements_in_block,
01246 int* element_ownership )
01247 {
01248 assert( global_block_ID ); // ensure global block ID argument is not null
01249 assert( num_elements_in_block ); // ensure number of elements in block argument is not null
01250
01251 std::map< int, int >& matMap = context.appDatas[*pid].matIndex;
01252
01253 std::map< int, int >::iterator it = matMap.find( *global_block_ID );
01254
01255 if( it == matMap.end() )
01256 {
01257 return moab::MB_FAILURE;
01258 } // error in finding block with id
01259
01260 int blockIndex = matMap[*global_block_ID];
01261 EntityHandle matMeshSet = context.appDatas[*pid].mat_sets[blockIndex];
01262 Range elems;
01263
01264 ErrorCode rval = context.MBI->get_entities_by_handle( matMeshSet, elems );MB_CHK_ERR( rval );
01265
01266 if( elems.empty() )
01267 {
01268 return moab::MB_FAILURE;
01269 }
01270
01271 if( *num_elements_in_block != (int)elems.size() )
01272 {
01273 return moab::MB_FAILURE;
01274 } // bad memory allocation
01275
01276 int i = 0;
01277 #ifdef MOAB_HAVE_MPI
01278 ParallelComm* pco = context.pcomms[*pid];
01279 #endif
01280
01281 for( Range::iterator vit = elems.begin(); vit != elems.end(); vit++, i++ )
01282 {
01283 #ifdef MOAB_HAVE_MPI
01284 rval = pco->get_owner( *vit, element_ownership[i] );MB_CHK_ERR( rval );
01285 #else
01286 element_ownership[i] = 0; /* owned by 0 */
01287 #endif
01288 }
01289
01290 return moab::MB_SUCCESS;
01291 }
01292
01293 ErrCode iMOAB_GetElementID( iMOAB_AppID pid,
01294 iMOAB_GlobalID* global_block_ID,
01295 int* num_elements_in_block,
01296 iMOAB_GlobalID* global_element_ID,
01297 iMOAB_LocalID* local_element_ID )
01298 {
01299 assert( global_block_ID ); // ensure global block ID argument is not null
01300 assert( num_elements_in_block ); // ensure number of elements in block argument is not null
01301
01302 appData& data = context.appDatas[*pid];
01303 std::map< int, int >& matMap = data.matIndex;
01304
01305 std::map< int, int >::iterator it = matMap.find( *global_block_ID );
01306
01307 if( it == matMap.end() )
01308 {
01309 return moab::MB_FAILURE;
01310 } // error in finding block with id
01311
01312 int blockIndex = matMap[*global_block_ID];
01313 EntityHandle matMeshSet = data.mat_sets[blockIndex];
01314 Range elems;
01315 ErrorCode rval = context.MBI->get_entities_by_handle( matMeshSet, elems );MB_CHK_ERR( rval );
01316
01317 if( elems.empty() )
01318 {
01319 return moab::MB_FAILURE;
01320 }
01321
01322 if( *num_elements_in_block != (int)elems.size() )
01323 {
01324 return moab::MB_FAILURE;
01325 } // bad memory allocation
01326
01327 rval = context.MBI->tag_get_data( context.globalID_tag, elems, global_element_ID );MB_CHK_ERR( rval );
01328
01329 // check that elems are among primary_elems in data
01330 for( int i = 0; i < *num_elements_in_block; i++ )
01331 {
01332 local_element_ID[i] = data.primary_elems.index( elems[i] );
01333
01334 if( -1 == local_element_ID[i] )
01335 {
01336 return moab::MB_FAILURE;
01337 } // error, not in local primary elements
01338 }
01339
01340 return moab::MB_SUCCESS;
01341 }
01342
01343 ErrCode iMOAB_GetPointerToSurfaceBC( iMOAB_AppID pid,
01344 int* surface_BC_length,
01345 iMOAB_LocalID* local_element_ID,
01346 int* reference_surface_ID,
01347 int* boundary_condition_value )
01348 {
01349 // we have to fill bc data for neumann sets;/
01350 ErrorCode rval;
01351
01352 // it was counted above, in GetMeshInfo
01353 appData& data = context.appDatas[*pid];
01354 int numNeuSets = (int)data.neu_sets.size();
01355
01356 int index = 0; // index [0, surface_BC_length) for the arrays returned
01357
01358 for( int i = 0; i < numNeuSets; i++ )
01359 {
01360 Range subents;
01361 EntityHandle nset = data.neu_sets[i];
01362 rval = context.MBI->get_entities_by_dimension( nset, data.dimension - 1, subents );MB_CHK_ERR( rval );
01363
01364 int neuVal;
01365 rval = context.MBI->tag_get_data( context.neumann_tag, &nset, 1, &neuVal );MB_CHK_ERR( rval );
01366
01367 for( Range::iterator it = subents.begin(); it != subents.end(); ++it )
01368 {
01369 EntityHandle subent = *it;
01370 Range adjPrimaryEnts;
01371 rval = context.MBI->get_adjacencies( &subent, 1, data.dimension, false, adjPrimaryEnts );MB_CHK_ERR( rval );
01372
01373 // get global id of the primary ents, and side number of the quad/subentity
01374 // this is moab ordering
01375 for( Range::iterator pit = adjPrimaryEnts.begin(); pit != adjPrimaryEnts.end(); pit++ )
01376 {
01377 EntityHandle primaryEnt = *pit;
01378 // get global id
01379 /*int globalID;
01380 rval = context.MBI->tag_get_data(gtags[3], &primaryEnt, 1, &globalID);
01381 if (MB_SUCCESS!=rval)
01382 return moab::MB_FAILURE;
01383 global_element_ID[index] = globalID;*/
01384
01385 // get local element id
01386 local_element_ID[index] = data.primary_elems.index( primaryEnt );
01387
01388 if( -1 == local_element_ID[index] )
01389 {
01390 return moab::MB_FAILURE;
01391 } // did not find the element locally
01392
01393 int side_number, sense, offset;
01394 rval = context.MBI->side_number( primaryEnt, subent, side_number, sense, offset );MB_CHK_ERR( rval );
01395
01396 reference_surface_ID[index] = side_number + 1; // moab is from 0 to 5, it needs 1 to 6
01397 boundary_condition_value[index] = neuVal;
01398 index++;
01399 }
01400 }
01401 }
01402
01403 if( index != *surface_BC_length )
01404 {
01405 return moab::MB_FAILURE;
01406 } // error in array allocations
01407
01408 return moab::MB_SUCCESS;
01409 }
01410
01411 ErrCode iMOAB_GetPointerToVertexBC( iMOAB_AppID pid,
01412 int* vertex_BC_length,
01413 iMOAB_LocalID* local_vertex_ID,
01414 int* boundary_condition_value )
01415 {
01416 ErrorCode rval;
01417
01418 // it was counted above, in GetMeshInfo
01419 appData& data = context.appDatas[*pid];
01420 int numDiriSets = (int)data.diri_sets.size();
01421 int index = 0; // index [0, *vertex_BC_length) for the arrays returned
01422
01423 for( int i = 0; i < numDiriSets; i++ )
01424 {
01425 Range verts;
01426 EntityHandle diset = data.diri_sets[i];
01427 rval = context.MBI->get_entities_by_dimension( diset, 0, verts );MB_CHK_ERR( rval );
01428
01429 int diriVal;
01430 rval = context.MBI->tag_get_data( context.dirichlet_tag, &diset, 1, &diriVal );MB_CHK_ERR( rval );
01431
01432 for( Range::iterator vit = verts.begin(); vit != verts.end(); ++vit )
01433 {
01434 EntityHandle vt = *vit;
01435 /*int vgid;
01436 rval = context.MBI->tag_get_data(gtags[3], &vt, 1, &vgid);
01437 if (MB_SUCCESS!=rval)
01438 return moab::MB_FAILURE;
01439 global_vertext_ID[index] = vgid;*/
01440 local_vertex_ID[index] = data.all_verts.index( vt );
01441
01442 if( -1 == local_vertex_ID[index] )
01443 {
01444 return moab::MB_FAILURE;
01445 } // vertex was not found
01446
01447 boundary_condition_value[index] = diriVal;
01448 index++;
01449 }
01450 }
01451
01452 if( *vertex_BC_length != index )
01453 {
01454 return moab::MB_FAILURE;
01455 } // array allocation issue
01456
01457 return moab::MB_SUCCESS;
01458 }
01459
01460 ErrCode iMOAB_DuplicateAppMesh( iMOAB_AppID pid, iMOAB_AppID poid )
01461 {
01462 // the file set , parallel comm are all in vectors indexed by *pid
01463 appData& data = context.appDatas[*pid];
01464 appData& dataout = context.appDatas[*poid];
01465 int rankHere = 0;
01466 #ifdef MOAB_HAVE_MPI
01467 ParallelComm* pco = context.pcomms[*pid];
01468 ParallelComm* pcout = context.pcomms[*poid];
01469 rankHere = pco->rank();
01470 #endif
01471
01472 #ifdef VERBOSE
01473 if( !rankHere )
01474 std::cout << " Mesh for application with ID: " << *pid << " global id: " << data.global_id
01475 << " name: " << data.name << "\n is copied in application with ID " << *poid << " name "
01476 << dataout.name << "\n";
01477 #endif
01478 EntityHandle fileSet = data.file_set;
01479 EntityHandle outFileSet = dataout.file_set;
01480 // get all entities part of the file set
01481 Range verts;
01482 ErrorCode rval = context.MBI->get_entities_by_dimension( fileSet, 0, verts );MB_CHK_ERR( rval );
01483 Range primaryCells;
01484 rval = context.MBI->get_entities_by_dimension( fileSet, data.dimension, primaryCells );MB_CHK_ERR( rval );
01485 Range connVerts;
01486 rval = context.MBI->get_connectivity( primaryCells, connVerts );MB_CHK_ERR( rval );
01487 verts.merge( connVerts );
01488 // first, deep copy vertices
01489 std::vector< double > coords;
01490 coords.resize( verts.size() * 3 );
01491
01492 rval = context.MBI->get_coords( verts, &coords[0] );MB_CHK_ERR( rval );
01493 std::vector< int > globalIds;
01494 globalIds.resize( verts.size() );
01495 Tag gid = context.MBI->globalId_tag();
01496 rval = context.MBI->tag_get_data( gid, verts, &globalIds[0] );MB_CHK_ERR( rval );
01497
01498 Range newVerts;
01499 int nverts = (int)verts.size();
01500 rval = context.MBI->create_vertices( &coords[0], nverts, newVerts );MB_CHK_ERR( rval );
01501 // set global ID the same
01502 rval = context.MBI->tag_set_data( gid, newVerts, &globalIds[0] );MB_CHK_ERR( rval );
01503 rval = context.MBI->add_entities( outFileSet, newVerts );MB_CHK_ERR( rval );
01504 // create new cells, cell by cell, and add them to the file set, and set the global id too
01505 // use the vertex global id for identification
01506 std::map< EntityHandle, int > oldMap;
01507 std::map< int, EntityHandle > newMap;
01508 int i = 0;
01509 for( auto it = verts.begin(); it != verts.end(); ++it, ++i )
01510 {
01511 EntityHandle oldVert = *it;
01512 EntityHandle newVert = newVerts[i];
01513 int globalId = globalIds[i];
01514 oldMap[oldVert] = globalId;
01515 newMap[globalId] = newVert;
01516 }
01517 Range newCells;
01518 for( auto it = primaryCells.begin(); it != primaryCells.end(); ++it )
01519 {
01520 EntityHandle oldCell = *it;
01521 int nnodes;
01522 const EntityHandle* conn = NULL;
01523 rval = context.MBI->get_connectivity( oldCell, conn, nnodes );MB_CHK_ERR( rval );
01524 std::vector< EntityHandle > newConn;
01525 newConn.resize( nnodes );
01526 EntityType type = context.MBI->type_from_handle( oldCell );
01527 for( int i = 0; i < nnodes; i++ )
01528 {
01529 newConn[i] = newMap[oldMap[conn[i]]];
01530 }
01531 EntityHandle newCell;
01532 rval = context.MBI->create_element( type, &newConn[0], nnodes, newCell );MB_CHK_ERR( rval );
01533 rval = context.MBI->add_entities( outFileSet, &newCell, 1 );MB_CHK_ERR( rval );
01534 int globalIdCell = 0;
01535 rval = context.MBI->tag_get_data( gid, &oldCell, 1, &globalIdCell );MB_CHK_ERR( rval );
01536 rval = context.MBI->tag_set_data( gid, &newCell, 1, &globalIdCell );MB_CHK_ERR( rval );
01537 newCells.insert( newCell );
01538 }
01539 // adjacencies need to be added explicitly
01540 Core* mb = (Core*)context.MBI;
01541 AEntityFactory* adj_fact = mb->a_entity_factory();
01542 if( !adj_fact->vert_elem_adjacencies() )
01543 adj_fact->create_vert_elem_adjacencies();
01544 else
01545 {
01546 for( Range::iterator it = newCells.begin(); it != newCells.end(); ++it )
01547 {
01548 EntityHandle eh = *it;
01549 const EntityHandle* conn = NULL;
01550 int num_nodes = 0;
01551 rval = mb->get_connectivity( eh, conn, num_nodes );MB_CHK_ERR( rval );
01552 adj_fact->notify_create_entity( eh, conn, num_nodes );
01553 }
01554 }
01555
01556 #ifdef MOAB_HAVE_MPI
01557 rval = iMOAB_ResolveSharedEntities( poid, &nverts, &globalIds[0] );MB_CHK_ERR( rval );
01558 #endif
01559
01560 rval = iMOAB_UpdateMeshInfo( poid );MB_CHK_ERR( rval );
01561 return moab::MB_SUCCESS;
01562 }
01563
01564 ErrCode iMOAB_DefineTagStorage( iMOAB_AppID pid,
01565 const iMOAB_String tag_storage_name,
01566 int* tag_type,
01567 int* components_per_entity,
01568 int* tag_index )
01569 {
01570 // see if the tag is already existing, and if yes, check the type, length
01571 if( *tag_type < DENSE_INTEGER || *tag_type > SPARSE_ENTITYHANDLE )
01572 {
01573 return moab::MB_FAILURE;
01574 } // we have 6 types of tags supported so far in enum MOAB_TAG_TYPE
01575
01576 DataType tagDataType;
01577 TagType tagType;
01578 void* defaultVal = NULL;
01579 int* defInt = new int[*components_per_entity];
01580 double* defDouble = new double[*components_per_entity];
01581 EntityHandle* defHandle = new EntityHandle[*components_per_entity];
01582
01583 for( int i = 0; i < *components_per_entity; i++ )
01584 {
01585 defInt[i] = 0;
01586 defDouble[i] = -1e+10;
01587 defHandle[i] = (EntityHandle)0;
01588 }
01589
01590 switch( *tag_type )
01591 {
01592 case DENSE_INTEGER:
01593 tagDataType = MB_TYPE_INTEGER;
01594 tagType = MB_TAG_DENSE;
01595 defaultVal = defInt;
01596 break;
01597
01598 case DENSE_DOUBLE:
01599 tagDataType = MB_TYPE_DOUBLE;
01600 tagType = MB_TAG_DENSE;
01601 defaultVal = defDouble;
01602 break;
01603
01604 case DENSE_ENTITYHANDLE:
01605 tagDataType = MB_TYPE_HANDLE;
01606 tagType = MB_TAG_DENSE;
01607 defaultVal = defHandle;
01608 break;
01609
01610 case SPARSE_INTEGER:
01611 tagDataType = MB_TYPE_INTEGER;
01612 tagType = MB_TAG_SPARSE;
01613 defaultVal = defInt;
01614 break;
01615
01616 case SPARSE_DOUBLE:
01617 tagDataType = MB_TYPE_DOUBLE;
01618 tagType = MB_TAG_SPARSE;
01619 defaultVal = defDouble;
01620 break;
01621
01622 case SPARSE_ENTITYHANDLE:
01623 tagDataType = MB_TYPE_HANDLE;
01624 tagType = MB_TAG_SPARSE;
01625 defaultVal = defHandle;
01626 break;
01627
01628 default: {
01629 delete[] defInt;
01630 delete[] defDouble;
01631 delete[] defHandle;
01632 return moab::MB_FAILURE;
01633 } // error
01634 }
01635
01636 Tag tagHandle;
01637 // split storage names if separated list
01638
01639 std::string tag_name( tag_storage_name );
01640
01641 // first separate the names of the tags
01642 // we assume that there are separators ":" between the tag names
01643 std::vector< std::string > tagNames;
01644 std::string separator( ":" );
01645 split_tag_names( tag_name, separator, tagNames );
01646
01647 ErrorCode rval = moab::MB_SUCCESS; // assume success already :)
01648 appData& data = context.appDatas[*pid];
01649 int already_defined_tags = 0;
01650
01651 for( size_t i = 0; i < tagNames.size(); i++ )
01652 {
01653 rval = context.MBI->tag_get_handle( tagNames[i].c_str(), *components_per_entity, tagDataType, tagHandle,
01654 tagType | MB_TAG_EXCL | MB_TAG_CREAT, defaultVal );
01655
01656 if( MB_ALREADY_ALLOCATED == rval )
01657 {
01658 std::map< std::string, Tag >& mTags = data.tagMap;
01659 std::map< std::string, Tag >::iterator mit = mTags.find( tagNames[i].c_str() );
01660
01661 if( mit == mTags.end() )
01662 {
01663 // add it to the map
01664 mTags[tagNames[i]] = tagHandle;
01665 // push it to the list of tags, too
01666 *tag_index = (int)data.tagList.size();
01667 data.tagList.push_back( tagHandle );
01668 }
01669 rval = MB_SUCCESS;
01670 already_defined_tags++;
01671 }
01672 else if( MB_SUCCESS == rval )
01673 {
01674 data.tagMap[tagNames[i]] = tagHandle;
01675 *tag_index = (int)data.tagList.size();
01676 data.tagList.push_back( tagHandle );
01677 }
01678 else
01679 {
01680 rval = moab::MB_FAILURE; // some tags were not created
01681 }
01682 }
01683 // we don't need default values anymore, avoid leaks
01684 int rankHere = 0;
01685 #ifdef MOAB_HAVE_MPI
01686 ParallelComm* pco = context.pcomms[*pid];
01687 rankHere = pco->rank();
01688 #endif
01689 if( !rankHere && already_defined_tags )
01690 std::cout << " application with ID: " << *pid << " global id: " << data.global_id << " name: " << data.name
01691 << " has " << already_defined_tags << " already defined tags out of " << tagNames.size()
01692 << " tags \n";
01693 delete[] defInt;
01694 delete[] defDouble;
01695 delete[] defHandle;
01696 return rval;
01697 }
01698
01699 ErrCode iMOAB_SetIntTagStorage( iMOAB_AppID pid,
01700 const iMOAB_String tag_storage_name,
01701 int* num_tag_storage_length,
01702 int* ent_type,
01703 int* tag_storage_data )
01704 {
01705 std::string tag_name( tag_storage_name );
01706
01707 // Get the application data
01708 appData& data = context.appDatas[*pid];
01709
01710 if( data.tagMap.find( tag_name ) == data.tagMap.end() )
01711 {
01712 return moab::MB_FAILURE;
01713 } // tag not defined
01714
01715 Tag tag = data.tagMap[tag_name];
01716
01717 int tagLength = 0;
01718 ErrorCode rval = context.MBI->tag_get_length( tag, tagLength );MB_CHK_ERR( rval );
01719
01720 DataType dtype;
01721 rval = context.MBI->tag_get_data_type( tag, dtype );
01722
01723 if( MB_SUCCESS != rval || dtype != MB_TYPE_INTEGER )
01724 {
01725 return moab::MB_FAILURE;
01726 }
01727
01728 // set it on a subset of entities, based on type and length
01729 Range* ents_to_set;
01730 if( *ent_type == TAG_VERTEX ) // vertices
01731 {
01732 ents_to_set = &data.all_verts;
01733 }
01734 else // if (*ent_type == TAG_ELEMENT) // *ent_type can be TAG_VERTEX or TAG_ELEMENT
01735 {
01736 ents_to_set = &data.primary_elems;
01737 }
01738
01739 int nents_to_be_set = *num_tag_storage_length / tagLength;
01740
01741 if( nents_to_be_set > (int)ents_to_set->size() || nents_to_be_set < 1 )
01742 {
01743 return moab::MB_FAILURE;
01744 } // to many entities to be set or too few
01745
01746 // restrict the range; everything is contiguous; or not?
01747
01748 // Range contig_range ( * ( ents_to_set->begin() ), * ( ents_to_set->begin() + nents_to_be_set -
01749 // 1 ) );
01750 rval = context.MBI->tag_set_data( tag, *ents_to_set, tag_storage_data );MB_CHK_ERR( rval );
01751
01752 return moab::MB_SUCCESS; // no error
01753 }
01754
01755 ErrCode iMOAB_GetIntTagStorage( iMOAB_AppID pid,
01756 const iMOAB_String tag_storage_name,
01757 int* num_tag_storage_length,
01758 int* ent_type,
01759 int* tag_storage_data )
01760 {
01761 ErrorCode rval;
01762 std::string tag_name( tag_storage_name );
01763
01764 appData& data = context.appDatas[*pid];
01765
01766 if( data.tagMap.find( tag_name ) == data.tagMap.end() )
01767 {
01768 return moab::MB_FAILURE;
01769 } // tag not defined
01770
01771 Tag tag = data.tagMap[tag_name];
01772
01773 int tagLength = 0;
01774 rval = context.MBI->tag_get_length( tag, tagLength );MB_CHK_ERR( rval );
01775
01776 DataType dtype;
01777 rval = context.MBI->tag_get_data_type( tag, dtype );MB_CHK_ERR( rval );
01778
01779 if( dtype != MB_TYPE_INTEGER )
01780 {
01781 return moab::MB_FAILURE;
01782 }
01783
01784 // set it on a subset of entities, based on type and length
01785 Range* ents_to_get;
01786 if( *ent_type == TAG_VERTEX ) // vertices
01787 {
01788 ents_to_get = &data.all_verts;
01789 }
01790 else // if (*ent_type == TAG_ELEMENT)
01791 {
01792 ents_to_get = &data.primary_elems;
01793 }
01794
01795 int nents_to_get = *num_tag_storage_length / tagLength;
01796
01797 if( nents_to_get > (int)ents_to_get->size() || nents_to_get < 1 )
01798 {
01799 return moab::MB_FAILURE;
01800 } // to many entities to get, or too little
01801
01802 // restrict the range; everything is contiguous; or not?
01803 // Range contig_range ( * ( ents_to_get->begin() ), * ( ents_to_get->begin() + nents_to_get - 1
01804 // ) );
01805
01806 rval = context.MBI->tag_get_data( tag, *ents_to_get, tag_storage_data );MB_CHK_ERR( rval );
01807
01808 return moab::MB_SUCCESS; // no error
01809 }
01810
01811 ErrCode iMOAB_SetDoubleTagStorage( iMOAB_AppID pid,
01812 const iMOAB_String tag_storage_names,
01813 int* num_tag_storage_length,
01814 int* ent_type,
01815 double* tag_storage_data )
01816 {
01817 ErrorCode rval;
01818 std::string tag_names( tag_storage_names );
01819 // exactly the same code as for int tag :) maybe should check the type of tag too
01820 std::vector< std::string > tagNames;
01821 std::vector< Tag > tagHandles;
01822 std::string separator( ":" );
01823 split_tag_names( tag_names, separator, tagNames );
01824
01825 appData& data = context.appDatas[*pid];
01826 Range* ents_to_set = NULL;
01827
01828 if( *ent_type == TAG_VERTEX ) // vertices
01829 {
01830 ents_to_set = &data.all_verts;
01831 }
01832 else // TAG_ELEMENT
01833 {
01834 ents_to_set = &data.primary_elems;
01835 }
01836
01837 int nents_to_be_set = (int)( *ents_to_set ).size();
01838 int position = 0;
01839
01840 for( size_t i = 0; i < tagNames.size(); i++ )
01841 {
01842 if( data.tagMap.find( tagNames[i] ) == data.tagMap.end() )
01843 {
01844 return moab::MB_FAILURE;
01845 } // some tag not defined yet in the app
01846
01847 Tag tag = data.tagMap[tagNames[i]];
01848
01849 int tagLength = 0;
01850 rval = context.MBI->tag_get_length( tag, tagLength );MB_CHK_ERR( rval );
01851
01852 DataType dtype;
01853 rval = context.MBI->tag_get_data_type( tag, dtype );MB_CHK_ERR( rval );
01854
01855 if( dtype != MB_TYPE_DOUBLE )
01856 {
01857 return moab::MB_FAILURE;
01858 }
01859
01860 // set it on the subset of entities, based on type and length
01861 if( position + tagLength * nents_to_be_set > *num_tag_storage_length )
01862 return moab::MB_FAILURE; // too many entity values to be set
01863
01864 rval = context.MBI->tag_set_data( tag, *ents_to_set, &tag_storage_data[position] );MB_CHK_ERR( rval );
01865 // increment position to next tag
01866 position = position + tagLength * nents_to_be_set;
01867 }
01868 return moab::MB_SUCCESS; // no error
01869 }
01870
01871 ErrCode iMOAB_SetDoubleTagStorageWithGid( iMOAB_AppID pid,
01872 const iMOAB_String tag_storage_names,
01873 int* num_tag_storage_length,
01874 int* ent_type,
01875 double* tag_storage_data,
01876 int* globalIds )
01877 {
01878 ErrorCode rval;
01879 std::string tag_names( tag_storage_names );
01880 // exactly the same code as for int tag :) maybe should check the type of tag too
01881 std::vector< std::string > tagNames;
01882 std::vector< Tag > tagHandles;
01883 std::string separator( ":" );
01884 split_tag_names( tag_names, separator, tagNames );
01885
01886 appData& data = context.appDatas[*pid];
01887 Range* ents_to_set = NULL;
01888
01889 if( *ent_type == TAG_VERTEX ) // vertices
01890 {
01891 ents_to_set = &data.all_verts;
01892 }
01893 else // TAG_ELEMENT
01894 {
01895 ents_to_set = &data.primary_elems;
01896 }
01897
01898 int nents_to_be_set = (int)( *ents_to_set ).size();
01899
01900 Tag gidTag = context.MBI->globalId_tag();
01901 std::vector< int > gids;
01902 gids.resize( nents_to_be_set );
01903 rval = context.MBI->tag_get_data( gidTag, *ents_to_set, &gids[0] );MB_CHK_ERR( rval );
01904
01905 // so we will need to set the tags according to the global id passed;
01906 // so the order in tag_storage_data is the same as the order in globalIds, but the order
01907 // in local range is gids
01908 std::map< int, EntityHandle > eh_by_gid;
01909 int i = 0;
01910 for( Range::iterator it = ents_to_set->begin(); it != ents_to_set->end(); ++it, ++i )
01911 {
01912 eh_by_gid[gids[i]] = *it;
01913 }
01914
01915 std::vector< int > tagLengths( tagNames.size() );
01916 std::vector< Tag > tagList;
01917 size_t total_tag_len = 0;
01918 for( size_t i = 0; i < tagNames.size(); i++ )
01919 {
01920 if( data.tagMap.find( tagNames[i] ) == data.tagMap.end() )
01921 {
01922 MB_SET_ERR( moab::MB_FAILURE, "tag missing" );
01923 } // some tag not defined yet in the app
01924
01925 Tag tag = data.tagMap[tagNames[i]];
01926 tagList.push_back( tag );
01927
01928 int tagLength = 0;
01929 rval = context.MBI->tag_get_length( tag, tagLength );MB_CHK_ERR( rval );
01930
01931 total_tag_len += tagLength;
01932 tagLengths[i] = tagLength;
01933 DataType dtype;
01934 rval = context.MBI->tag_get_data_type( tag, dtype );MB_CHK_ERR( rval );
01935
01936 if( dtype != MB_TYPE_DOUBLE )
01937 {
01938 MB_SET_ERR( moab::MB_FAILURE, "tag not double type" );
01939 }
01940 }
01941 bool serial = true;
01942 #ifdef MOAB_HAVE_MPI
01943 ParallelComm* pco = context.pcomms[*pid];
01944 unsigned num_procs = pco->size();
01945 if( num_procs > 1 ) serial = false;
01946 #endif
01947
01948 if( serial )
01949 {
01950 assert( total_tag_len * nents_to_be_set - *num_tag_storage_length == 0 );
01951 // tags are unrolled, we loop over global ids first, then careful about tags
01952 for( int i = 0; i < nents_to_be_set; i++ )
01953 {
01954 int gid = globalIds[i];
01955 EntityHandle eh = eh_by_gid[gid];
01956 // now loop over tags
01957 int indexInTagValues = 0; //
01958 for( size_t j = 0; j < tagList.size(); j++ )
01959 {
01960 indexInTagValues += i * tagLengths[j];
01961 rval = context.MBI->tag_set_data( tagList[j], &eh, 1, &tag_storage_data[indexInTagValues] );MB_CHK_ERR( rval );
01962 // advance the pointer/index
01963 indexInTagValues += ( nents_to_be_set - i ) * tagLengths[j]; // at the end of tag data
01964 }
01965 }
01966 }
01967 #ifdef MOAB_HAVE_MPI
01968 else // it can be not serial only if pco->size() > 1, parallel
01969 {
01970 // in this case, we have to use 2 crystal routers, to send data to the processor that needs it
01971 // we will create first a tuple to rendevous points, then from there send to the processor that requested it
01972 // it is a 2-hop global gather scatter
01973 int nbLocalVals = *num_tag_storage_length / ( (int)tagNames.size() );
01974 assert( nbLocalVals * tagNames.size() - *num_tag_storage_length == 0 );
01975 TupleList TLsend;
01976 TLsend.initialize( 2, 0, 0, total_tag_len, nbLocalVals ); // to proc, marker(gid), total_tag_len doubles
01977 TLsend.enableWriteAccess();
01978 // the processor id that processes global_id is global_id / num_ents_per_proc
01979
01980 int indexInRealLocal = 0;
01981 for( int i = 0; i < nbLocalVals; i++ )
01982 {
01983 // to proc, marker, element local index, index in el
01984 int marker = globalIds[i];
01985 int to_proc = marker % num_procs;
01986 int n = TLsend.get_n();
01987 TLsend.vi_wr[2 * n] = to_proc; // send to processor
01988 TLsend.vi_wr[2 * n + 1] = marker;
01989 int indexInTagValues = 0;
01990 // tag data collect by number of tags
01991 for( size_t j = 0; j < tagList.size(); j++ )
01992 {
01993 indexInTagValues += i * tagLengths[j];
01994 for( int k = 0; k < tagLengths[j]; k++ )
01995 {
01996 TLsend.vr_wr[indexInRealLocal++] = tag_storage_data[indexInTagValues + k];
01997 }
01998 indexInTagValues += ( nbLocalVals - i ) * tagLengths[j];
01999 }
02000 TLsend.inc_n();
02001 }
02002
02003 assert( nbLocalVals * total_tag_len - indexInRealLocal == 0 );
02004 // send now requests, basically inform the rendez-vous point who needs a particular global id
02005 // send the data to the other processors:
02006 ( pco->proc_config().crystal_router() )->gs_transfer( 1, TLsend, 0 );
02007 TupleList TLreq;
02008 TLreq.initialize( 2, 0, 0, 0, nents_to_be_set );
02009 TLreq.enableWriteAccess();
02010 for( int i = 0; i < nents_to_be_set; i++ )
02011 {
02012 // to proc, marker
02013 int marker = gids[i];
02014 int to_proc = marker % num_procs;
02015 int n = TLreq.get_n();
02016 TLreq.vi_wr[2 * n] = to_proc; // send to processor
02017 TLreq.vi_wr[2 * n + 1] = marker;
02018 // tag data collect by number of tags
02019 TLreq.inc_n();
02020 }
02021 ( pco->proc_config().crystal_router() )->gs_transfer( 1, TLreq, 0 );
02022
02023 // we know now that process TLreq.vi_wr[2 * n] needs tags for gid TLreq.vi_wr[2 * n + 1]
02024 // we should first order by global id, and then build the new TL with send to proc, global id and
02025 // tags for it
02026 // sort by global ids the tuple lists
02027 moab::TupleList::buffer sort_buffer;
02028 sort_buffer.buffer_init( TLreq.get_n() );
02029 TLreq.sort( 1, &sort_buffer );
02030 sort_buffer.reset();
02031 sort_buffer.buffer_init( TLsend.get_n() );
02032 TLsend.sort( 1, &sort_buffer );
02033 sort_buffer.reset();
02034 // now send the tag values to the proc that requested it
02035 // in theory, for a full partition, TLreq and TLsend should have the same size, and
02036 // each dof should have exactly one target proc. Is that true or not in general ?
02037 // how do we plan to use this? Is it better to store the comm graph for future
02038
02039 // start copy from comm graph settle
02040 TupleList TLBack;
02041 TLBack.initialize( 3, 0, 0, total_tag_len, 0 ); // to proc, marker, tag from proc , tag values
02042 TLBack.enableWriteAccess();
02043
02044 int n1 = TLreq.get_n();
02045 int n2 = TLsend.get_n();
02046
02047 int indexInTLreq = 0;
02048 int indexInTLsend = 0; // advance both, according to the marker
02049 if( n1 > 0 && n2 > 0 )
02050 {
02051
02052 while( indexInTLreq < n1 && indexInTLsend < n2 ) // if any is over, we are done
02053 {
02054 int currentValue1 = TLreq.vi_rd[2 * indexInTLreq + 1];
02055 int currentValue2 = TLsend.vi_rd[2 * indexInTLsend + 1];
02056 if( currentValue1 < currentValue2 )
02057 {
02058 // we have a big problem; basically, we are saying that
02059 // dof currentValue is on one model and not on the other
02060 // std::cout << " currentValue1:" << currentValue1 << " missing in comp2" << "\n";
02061 indexInTLreq++;
02062 continue;
02063 }
02064 if( currentValue1 > currentValue2 )
02065 {
02066 // std::cout << " currentValue2:" << currentValue2 << " missing in comp1" << "\n";
02067 indexInTLsend++;
02068 continue;
02069 }
02070 int size1 = 1;
02071 int size2 = 1;
02072 while( indexInTLreq + size1 < n1 && currentValue1 == TLreq.vi_rd[2 * ( indexInTLreq + size1 ) + 1] )
02073 size1++;
02074 while( indexInTLsend + size2 < n2 && currentValue2 == TLsend.vi_rd[2 * ( indexInTLsend + size2 ) + 1] )
02075 size2++;
02076 // must be found in both lists, find the start and end indices
02077 for( int i1 = 0; i1 < size1; i1++ )
02078 {
02079 for( int i2 = 0; i2 < size2; i2++ )
02080 {
02081 // send the info back to components
02082 int n = TLBack.get_n();
02083 TLBack.reserve();
02084 TLBack.vi_wr[3 * n] = TLreq.vi_rd[2 * ( indexInTLreq + i1 )]; // send back to the proc marker
02085 // came from, info from comp2
02086 TLBack.vi_wr[3 * n + 1] = currentValue1; // initial value (resend, just for verif ?)
02087 TLBack.vi_wr[3 * n + 2] = TLsend.vi_rd[2 * ( indexInTLsend + i2 )]; // from proc on comp2
02088 // also fill tag values
02089 for( size_t k = 0; k < total_tag_len; k++ )
02090 {
02091 TLBack.vr_rd[total_tag_len * n + k] =
02092 TLsend.vr_rd[total_tag_len * indexInTLsend + k]; // deep copy of tag values
02093 }
02094 }
02095 }
02096 indexInTLreq += size1;
02097 indexInTLsend += size2;
02098 }
02099 }
02100 ( pco->proc_config().crystal_router() )->gs_transfer( 1, TLBack, 0 );
02101 // end copy from comm graph
02102 // after we are done sending, we need to set those tag values, in a reverse process compared to send
02103 n1 = TLBack.get_n();
02104 double* ptrVal = &TLBack.vr_rd[0]; //
02105 for( int i = 0; i < n1; i++ )
02106 {
02107 int gid = TLBack.vi_rd[3 * i + 1]; // marker
02108 EntityHandle eh = eh_by_gid[gid];
02109 // now loop over tags
02110
02111 for( size_t j = 0; j < tagList.size(); j++ )
02112 {
02113 rval = context.MBI->tag_set_data( tagList[j], &eh, 1, (void*)ptrVal );MB_CHK_ERR( rval );
02114 // advance the pointer/index
02115 ptrVal += tagLengths[j]; // at the end of tag data per call
02116 }
02117 }
02118 }
02119 #endif
02120 return MB_SUCCESS;
02121 }
02122 ErrCode iMOAB_GetDoubleTagStorage( iMOAB_AppID pid,
02123 const iMOAB_String tag_storage_names,
02124 int* num_tag_storage_length,
02125 int* ent_type,
02126 double* tag_storage_data )
02127 {
02128 ErrorCode rval;
02129 // exactly the same code, except tag type check
02130 std::string tag_names( tag_storage_names );
02131 // exactly the same code as for int tag :) maybe should check the type of tag too
02132 std::vector< std::string > tagNames;
02133 std::vector< Tag > tagHandles;
02134 std::string separator( ":" );
02135 split_tag_names( tag_names, separator, tagNames );
02136
02137 appData& data = context.appDatas[*pid];
02138
02139 // set it on a subset of entities, based on type and length
02140 Range* ents_to_get = NULL;
02141 if( *ent_type == TAG_VERTEX ) // vertices
02142 {
02143 ents_to_get = &data.all_verts;
02144 }
02145 else // TAG_ELEMENT
02146 {
02147 ents_to_get = &data.primary_elems;
02148 }
02149
02150 int nents_to_get = (int)ents_to_get->size();
02151 int position = 0;
02152 for( size_t i = 0; i < tagNames.size(); i++ )
02153 {
02154 if( data.tagMap.find( tagNames[i] ) == data.tagMap.end() )
02155 {
02156 return moab::MB_FAILURE;
02157 } // tag not defined
02158
02159 Tag tag = data.tagMap[tagNames[i]];
02160
02161 int tagLength = 0;
02162 rval = context.MBI->tag_get_length( tag, tagLength );MB_CHK_ERR( rval );
02163
02164 DataType dtype;
02165 rval = context.MBI->tag_get_data_type( tag, dtype );MB_CHK_ERR( rval );
02166
02167 if( dtype != MB_TYPE_DOUBLE )
02168 {
02169 return moab::MB_FAILURE;
02170 }
02171
02172 if( position + nents_to_get * tagLength > *num_tag_storage_length )
02173 return moab::MB_FAILURE; // too many entity values to get
02174
02175 rval = context.MBI->tag_get_data( tag, *ents_to_get, &tag_storage_data[position] );MB_CHK_ERR( rval );
02176 position = position + nents_to_get * tagLength;
02177 }
02178
02179 return moab::MB_SUCCESS; // no error
02180 }
02181
02182 ErrCode iMOAB_SynchronizeTags( iMOAB_AppID pid, int* num_tag, int* tag_indices, int* ent_type )
02183 {
02184 #ifdef MOAB_HAVE_MPI
02185 appData& data = context.appDatas[*pid];
02186 Range ent_exchange;
02187 std::vector< Tag > tags;
02188
02189 for( int i = 0; i < *num_tag; i++ )
02190 {
02191 if( tag_indices[i] < 0 || tag_indices[i] >= (int)data.tagList.size() )
02192 {
02193 return moab::MB_FAILURE;
02194 } // error in tag index
02195
02196 tags.push_back( data.tagList[tag_indices[i]] );
02197 }
02198
02199 if( *ent_type == 0 )
02200 {
02201 ent_exchange = data.all_verts;
02202 }
02203 else if( *ent_type == 1 )
02204 {
02205 ent_exchange = data.primary_elems;
02206 }
02207 else
02208 {
02209 return moab::MB_FAILURE;
02210 } // unexpected type
02211
02212 ParallelComm* pco = context.pcomms[*pid];
02213
02214 ErrorCode rval = pco->exchange_tags( tags, tags, ent_exchange );MB_CHK_ERR( rval );
02215
02216 #else
02217 /* do nothing if serial */
02218 // just silence the warning
02219 // do not call sync tags in serial!
02220 int k = *pid + *num_tag + *tag_indices + *ent_type;
02221 k++;
02222 #endif
02223
02224 return moab::MB_SUCCESS;
02225 }
02226
02227 ErrCode iMOAB_ReduceTagsMax( iMOAB_AppID pid, int* tag_index, int* ent_type )
02228 {
02229 #ifdef MOAB_HAVE_MPI
02230 appData& data = context.appDatas[*pid];
02231 Range ent_exchange;
02232
02233 if( *tag_index < 0 || *tag_index >= (int)data.tagList.size() )
02234 {
02235 return moab::MB_FAILURE;
02236 } // error in tag index
02237
02238 Tag tagh = data.tagList[*tag_index];
02239
02240 if( *ent_type == 0 )
02241 {
02242 ent_exchange = data.all_verts;
02243 }
02244 else if( *ent_type == 1 )
02245 {
02246 ent_exchange = data.primary_elems;
02247 }
02248 else
02249 {
02250 return moab::MB_FAILURE;
02251 } // unexpected type
02252
02253 ParallelComm* pco = context.pcomms[*pid];
02254 // we could do different MPI_Op; do not bother now, we will call from fortran
02255 ErrorCode rval = pco->reduce_tags( tagh, MPI_MAX, ent_exchange );MB_CHK_ERR( rval );
02256
02257 #else
02258 /* do nothing if serial */
02259 // just silence the warning
02260 // do not call sync tags in serial!
02261 int k = *pid + *tag_index + *ent_type;
02262 k++; // just do junk, to avoid complaints
02263 #endif
02264 return moab::MB_SUCCESS;
02265 }
02266
02267 ErrCode iMOAB_GetNeighborElements( iMOAB_AppID pid,
02268 iMOAB_LocalID* local_index,
02269 int* num_adjacent_elements,
02270 iMOAB_LocalID* adjacent_element_IDs )
02271 {
02272 ErrorCode rval;
02273
02274 // one neighbor for each subentity of dimension-1
02275 MeshTopoUtil mtu( context.MBI );
02276 appData& data = context.appDatas[*pid];
02277 EntityHandle eh = data.primary_elems[*local_index];
02278 Range adjs;
02279 rval = mtu.get_bridge_adjacencies( eh, data.dimension - 1, data.dimension, adjs );MB_CHK_ERR( rval );
02280
02281 if( *num_adjacent_elements < (int)adjs.size() )
02282 {
02283 return moab::MB_FAILURE;
02284 } // not dimensioned correctly
02285
02286 *num_adjacent_elements = (int)adjs.size();
02287
02288 for( int i = 0; i < *num_adjacent_elements; i++ )
02289 {
02290 adjacent_element_IDs[i] = data.primary_elems.index( adjs[i] );
02291 }
02292
02293 return moab::MB_SUCCESS;
02294 }
02295
02296 #if 0
02297
02298 ErrCode iMOAB_GetNeighborVertices ( iMOAB_AppID pid, iMOAB_LocalID* local_vertex_ID, int* num_adjacent_vertices, iMOAB_LocalID* adjacent_vertex_IDs )
02299 {
02300 return moab::MB_SUCCESS;
02301 }
02302
02303 #endif
02304
02305 ErrCode iMOAB_CreateVertices( iMOAB_AppID pid, int* coords_len, int* dim, double* coordinates )
02306 {
02307 ErrorCode rval;
02308 appData& data = context.appDatas[*pid];
02309
02310 if( !data.local_verts.empty() ) // we should have no vertices in the app
02311 {
02312 return moab::MB_FAILURE;
02313 }
02314
02315 int nverts = *coords_len / *dim;
02316
02317 rval = context.MBI->create_vertices( coordinates, nverts, data.local_verts );MB_CHK_ERR( rval );
02318
02319 rval = context.MBI->add_entities( data.file_set, data.local_verts );MB_CHK_ERR( rval );
02320
02321 // also add the vertices to the all_verts range
02322 data.all_verts.merge( data.local_verts );
02323 return moab::MB_SUCCESS;
02324 }
02325
02326 ErrCode iMOAB_CreateElements( iMOAB_AppID pid,
02327 int* num_elem,
02328 int* type,
02329 int* num_nodes_per_element,
02330 int* connectivity,
02331 int* block_ID )
02332 {
02333 // Create elements
02334 appData& data = context.appDatas[*pid];
02335
02336 ReadUtilIface* read_iface;
02337 ErrorCode rval = context.MBI->query_interface( read_iface );MB_CHK_ERR( rval );
02338
02339 EntityType mbtype = ( EntityType )( *type );
02340 EntityHandle actual_start_handle;
02341 EntityHandle* array = NULL;
02342 rval = read_iface->get_element_connect( *num_elem, *num_nodes_per_element, mbtype, 1, actual_start_handle, array );MB_CHK_ERR( rval );
02343
02344 // fill up with actual connectivity from input; assume the vertices are in order, and start
02345 // vertex is the first in the current data vertex range
02346 EntityHandle firstVertex = data.local_verts[0];
02347
02348 for( int j = 0; j < *num_elem * ( *num_nodes_per_element ); j++ )
02349 {
02350 array[j] = connectivity[j] + firstVertex - 1;
02351 } // assumes connectivity uses 1 based array (from fortran, mostly)
02352
02353 Range new_elems( actual_start_handle, actual_start_handle + *num_elem - 1 );
02354
02355 rval = context.MBI->add_entities( data.file_set, new_elems );MB_CHK_ERR( rval );
02356
02357 data.primary_elems.merge( new_elems );
02358
02359 // add to adjacency
02360 rval = read_iface->update_adjacencies( actual_start_handle, *num_elem, *num_nodes_per_element, array );MB_CHK_ERR( rval );
02361 // organize all new elements in block, with the given block ID; if the block set is not
02362 // existing, create a new mesh set;
02363 Range sets;
02364 int set_no = *block_ID;
02365 const void* setno_ptr = &set_no;
02366 rval = context.MBI->get_entities_by_type_and_tag( data.file_set, MBENTITYSET, &context.material_tag, &setno_ptr, 1,
02367 sets );
02368 EntityHandle block_set;
02369
02370 if( MB_FAILURE == rval || sets.empty() )
02371 {
02372 // create a new set, with this block ID
02373 rval = context.MBI->create_meshset( MESHSET_SET, block_set );MB_CHK_ERR( rval );
02374
02375 rval = context.MBI->tag_set_data( context.material_tag, &block_set, 1, &set_no );MB_CHK_ERR( rval );
02376
02377 // add the material set to file set
02378 rval = context.MBI->add_entities( data.file_set, &block_set, 1 );MB_CHK_ERR( rval );
02379 }
02380 else
02381 {
02382 block_set = sets[0];
02383 } // first set is the one we want
02384
02385 /// add the new ents to the clock set
02386 rval = context.MBI->add_entities( block_set, new_elems );MB_CHK_ERR( rval );
02387
02388 return moab::MB_SUCCESS;
02389 }
02390
02391 ErrCode iMOAB_SetGlobalInfo( iMOAB_AppID pid, int* num_global_verts, int* num_global_elems )
02392 {
02393 appData& data = context.appDatas[*pid];
02394 data.num_global_vertices = *num_global_verts;
02395 data.num_global_elements = *num_global_elems;
02396 return moab::MB_SUCCESS;
02397 }
02398
02399 ErrCode iMOAB_GetGlobalInfo( iMOAB_AppID pid, int* num_global_verts, int* num_global_elems )
02400 {
02401 appData& data = context.appDatas[*pid];
02402 if( NULL != num_global_verts )
02403 {
02404 *num_global_verts = data.num_global_vertices;
02405 }
02406 if( NULL != num_global_elems )
02407 {
02408 *num_global_elems = data.num_global_elements;
02409 }
02410
02411 return moab::MB_SUCCESS;
02412 }
02413
02414 #ifdef MOAB_HAVE_MPI
02415
02416 // this makes sense only for parallel runs
02417 ErrCode iMOAB_ResolveSharedEntities( iMOAB_AppID pid, int* num_verts, int* marker )
02418 {
02419 appData& data = context.appDatas[*pid];
02420 ParallelComm* pco = context.pcomms[*pid];
02421 EntityHandle cset = data.file_set;
02422 int dum_id = 0;
02423 ErrorCode rval;
02424 if( data.primary_elems.empty() )
02425 {
02426 // skip actual resolve, assume vertices are distributed already ,
02427 // no need to share them
02428 }
02429 else
02430 {
02431 // create an integer tag for resolving ; maybe it can be a long tag in the future
02432 // (more than 2 B vertices;)
02433
02434 Tag stag;
02435 rval = context.MBI->tag_get_handle( "__sharedmarker", 1, MB_TYPE_INTEGER, stag, MB_TAG_CREAT | MB_TAG_DENSE,
02436 &dum_id );MB_CHK_ERR( rval );
02437
02438 if( *num_verts > (int)data.local_verts.size() )
02439 {
02440 return moab::MB_FAILURE;
02441 } // we are not setting the size
02442
02443 rval = context.MBI->tag_set_data( stag, data.local_verts, (void*)marker );MB_CHK_ERR( rval ); // assumes integer tag
02444
02445 rval = pco->resolve_shared_ents( cset, -1, -1, &stag );MB_CHK_ERR( rval );
02446
02447 rval = context.MBI->tag_delete( stag );MB_CHK_ERR( rval );
02448 }
02449 // provide partition tag equal to rank
02450 Tag part_tag;
02451 dum_id = -1;
02452 rval = context.MBI->tag_get_handle( "PARALLEL_PARTITION", 1, MB_TYPE_INTEGER, part_tag,
02453 MB_TAG_CREAT | MB_TAG_SPARSE, &dum_id );
02454
02455 if( part_tag == NULL || ( ( rval != MB_SUCCESS ) && ( rval != MB_ALREADY_ALLOCATED ) ) )
02456 {
02457 std::cout << " can't get par part tag.\n";
02458 return moab::MB_FAILURE;
02459 }
02460
02461 int rank = pco->rank();
02462 rval = context.MBI->tag_set_data( part_tag, &cset, 1, &rank );MB_CHK_ERR( rval );
02463
02464 return moab::MB_SUCCESS;
02465 }
02466
02467 // this assumes that this was not called before
02468 ErrCode iMOAB_DetermineGhostEntities( iMOAB_AppID pid, int* ghost_dim, int* num_ghost_layers, int* bridge_dim )
02469 {
02470 ErrorCode rval;
02471
02472 // verify we have valid ghost layers input specified. If invalid, exit quick.
02473 if( *num_ghost_layers <= 0 )
02474 {
02475 return moab::MB_SUCCESS;
02476 } // nothing to do
02477
02478 appData& data = context.appDatas[*pid];
02479 ParallelComm* pco = context.pcomms[*pid];
02480
02481 int addl_ents =
02482 0; // maybe we should be passing this too; most of the time we do not need additional ents collective call
02483 rval =
02484 pco->exchange_ghost_cells( *ghost_dim, *bridge_dim, *num_ghost_layers, addl_ents, true, true, &data.file_set );MB_CHK_ERR( rval );
02485
02486 // now re-establish all mesh info; will reconstruct mesh info, based solely on what is in the file set
02487 return iMOAB_UpdateMeshInfo( pid );
02488 }
02489
02490 ErrCode iMOAB_SendMesh( iMOAB_AppID pid, MPI_Comm* join, MPI_Group* receivingGroup, int* rcompid, int* method )
02491 {
02492 assert( join != nullptr );
02493 assert( receivingGroup != nullptr );
02494 assert( rcompid != nullptr );
02495
02496 ErrorCode rval;
02497 int ierr;
02498 appData& data = context.appDatas[*pid];
02499 ParallelComm* pco = context.pcomms[*pid];
02500
02501 MPI_Comm global = ( data.is_fortran ? MPI_Comm_f2c( *reinterpret_cast< MPI_Fint* >( join ) ) : *join );
02502 MPI_Group recvGroup =
02503 ( data.is_fortran ? MPI_Group_f2c( *reinterpret_cast< MPI_Fint* >( receivingGroup ) ) : *receivingGroup );
02504 MPI_Comm sender = pco->comm(); // the sender comm is obtained from parallel comm in moab; no need to pass it along
02505 // first see what are the processors in each group; get the sender group too, from the sender communicator
02506 MPI_Group senderGroup;
02507 ierr = MPI_Comm_group( sender, &senderGroup );
02508 if( ierr != 0 ) return moab::MB_FAILURE;
02509
02510 // instantiate the par comm graph
02511 // ParCommGraph::ParCommGraph(MPI_Comm joincomm, MPI_Group group1, MPI_Group group2, int coid1,
02512 // int coid2)
02513 ParCommGraph* cgraph =
02514 new ParCommGraph( global, senderGroup, recvGroup, context.appDatas[*pid].global_id, *rcompid );
02515 // we should search if we have another pcomm with the same comp ids in the list already
02516 // sort of check existing comm graphs in the map context.appDatas[*pid].pgraph
02517 context.appDatas[*pid].pgraph[*rcompid] = cgraph;
02518
02519 int sender_rank = -1;
02520 MPI_Comm_rank( sender, &sender_rank );
02521
02522 // decide how to distribute elements to each processor
02523 // now, get the entities on local processor, and pack them into a buffer for various processors
02524 // we will do trivial partition: first get the total number of elements from "sender"
02525 std::vector< int > number_elems_per_part;
02526 // how to distribute local elements to receiving tasks?
02527 // trivial partition: compute first the total number of elements need to be sent
02528 Range owned = context.appDatas[*pid].owned_elems;
02529 std::vector< char > zoltanBuffer;
02530 if( owned.size() == 0 )
02531 {
02532 // must be vertices that we want to send then
02533 owned = context.appDatas[*pid].local_verts;
02534 // we should have some vertices here
02535 }
02536
02537 if( *method == 0 ) // trivial partitioning, old method
02538 {
02539 int local_owned_elem = (int)owned.size();
02540 int size = pco->size();
02541 int rank = pco->rank();
02542 number_elems_per_part.resize( size ); //
02543 number_elems_per_part[rank] = local_owned_elem;
02544 #if( MPI_VERSION >= 2 )
02545 // Use "in place" option
02546 ierr = MPI_Allgather( MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, &number_elems_per_part[0], 1, MPI_INT, sender );
02547 #else
02548 {
02549 std::vector< int > all_tmp( size );
02550 ierr = MPI_Allgather( &number_elems_per_part[rank], 1, MPI_INT, &all_tmp[0], 1, MPI_INT, sender );
02551 number_elems_per_part = all_tmp;
02552 }
02553 #endif
02554
02555 if( ierr != 0 )
02556 {
02557 return moab::MB_FAILURE;
02558 }
02559
02560 // every sender computes the trivial partition, it is cheap, and we need to send it anyway
02561 // to each sender
02562 rval = cgraph->compute_trivial_partition( number_elems_per_part );MB_CHK_ERR( rval );
02563
02564 // nothing in z buff, just to compile
02565 rval = cgraph->send_graph( global, zoltanBuffer );MB_CHK_ERR( rval );
02566 }
02567 #ifdef MOAB_HAVE_ZOLTAN
02568 else // *method != 0, so it is either graph or geometric, parallel
02569 {
02570 // it is assumed the method 4 was called in advance
02571 if( *method == 5 )
02572 {
02573 zoltanBuffer = context.uniqueZoltanBuffer;
02574 }
02575 rval = cgraph->compute_partition( pco, owned, *method, zoltanBuffer );MB_CHK_ERR( rval );
02576 // basically, send the graph to the receiver side, with unblocking send
02577 rval = cgraph->send_graph_partition( pco, global, zoltanBuffer );MB_CHK_ERR( rval );
02578 }
02579 #endif // #ifdef MOAB_HAVE_ZOLTAN
02580 // pco is needed to pack, not for communication
02581 rval = cgraph->send_mesh_parts( global, pco, owned );MB_CHK_ERR( rval );
02582
02583 // mark for deletion
02584 MPI_Group_free( &senderGroup );
02585 return moab::MB_SUCCESS;
02586 }
02587
02588 ErrCode iMOAB_ReceiveMesh( iMOAB_AppID pid, MPI_Comm* join, MPI_Group* sendingGroup, int* scompid )
02589 {
02590 assert( join != nullptr );
02591 assert( sendingGroup != nullptr );
02592 assert( scompid != nullptr );
02593
02594 ErrorCode rval;
02595 appData& data = context.appDatas[*pid];
02596 ParallelComm* pco = context.pcomms[*pid];
02597 MPI_Comm receive = pco->comm();
02598 EntityHandle local_set = data.file_set;
02599
02600 MPI_Comm global = ( data.is_fortran ? MPI_Comm_f2c( *reinterpret_cast< MPI_Fint* >( join ) ) : *join );
02601 MPI_Group sendGroup =
02602 ( data.is_fortran ? MPI_Group_f2c( *reinterpret_cast< MPI_Fint* >( sendingGroup ) ) : *sendingGroup );
02603
02604 // first see what are the processors in each group; get the sender group too, from the sender
02605 // communicator
02606 MPI_Group receiverGroup;
02607 int ierr = MPI_Comm_group( receive, &receiverGroup );CHK_MPI_ERR( ierr );
02608
02609 // instantiate the par comm graph
02610 ParCommGraph* cgraph =
02611 new ParCommGraph( global, sendGroup, receiverGroup, *scompid, context.appDatas[*pid].global_id );
02612 // TODO we should search if we have another pcomm with the same comp ids in the list already
02613 // sort of check existing comm graphs in the map context.appDatas[*pid].pgraph
02614 context.appDatas[*pid].pgraph[*scompid] = cgraph;
02615
02616 int receiver_rank = -1;
02617 MPI_Comm_rank( receive, &receiver_rank );
02618
02619 // first, receive from sender_rank 0, the communication graph (matrix), so each receiver
02620 // knows what data to expect
02621 std::vector< int > pack_array;
02622 std::vector< char > zoltanBuff;
02623 rval = cgraph->receive_comm_graph( global, pco, pack_array, zoltanBuff );MB_CHK_ERR( rval );
02624
02625 // senders across for the current receiver
02626 int current_receiver = cgraph->receiver( receiver_rank );
02627 #ifdef MOAB_HAVE_ZOLTAN
02628 if( zoltanBuff.size() > 0 ) // it could happen only on root of receiver; store it in a global context member
02629 // the corresponding send it with method 4, for sure
02630 context.uniqueZoltanBuffer = zoltanBuff;
02631 #endif
02632 std::vector< int > senders_local;
02633 size_t n = 0;
02634
02635 while( n < pack_array.size() - 1 ) // now, the last int was already processed, if it has zoltan or not
02636 {
02637 if( current_receiver == pack_array[n] )
02638 {
02639 for( int j = 0; j < pack_array[n + 1]; j++ )
02640 {
02641 senders_local.push_back( pack_array[n + 2 + j] );
02642 }
02643
02644 break;
02645 }
02646
02647 n = n + 2 + pack_array[n + 1];
02648 }
02649
02650 #ifdef VERBOSE
02651 std::cout << " receiver " << current_receiver << " at rank " << receiver_rank << " will receive from "
02652 << senders_local.size() << " tasks: ";
02653
02654 for( int k = 0; k < (int)senders_local.size(); k++ )
02655 {
02656 std::cout << " " << senders_local[k];
02657 }
02658
02659 std::cout << "\n";
02660 #endif
02661
02662 if( senders_local.empty() )
02663 {
02664 std::cout << " we do not have any senders for receiver rank " << receiver_rank << "\n";
02665 }
02666 rval = cgraph->receive_mesh( global, pco, local_set, senders_local );MB_CHK_ERR( rval );
02667
02668 // after we are done, we could merge vertices that come from different senders, but
02669 // have the same global id
02670 Tag idtag;
02671 rval = context.MBI->tag_get_handle( "GLOBAL_ID", idtag );MB_CHK_ERR( rval );
02672
02673 // data.point_cloud = false;
02674 Range local_ents;
02675 rval = context.MBI->get_entities_by_handle( local_set, local_ents );MB_CHK_ERR( rval );
02676
02677 // do not do merge if point cloud
02678 if( !local_ents.empty() )
02679 {
02680 if( !local_ents.all_of_type( MBVERTEX ) )
02681 {
02682 if( (int)senders_local.size() >= 2 ) // need to remove duplicate vertices
02683 // that might come from different senders
02684 {
02685
02686 Range local_verts = local_ents.subset_by_type( MBVERTEX );
02687 Range local_elems = subtract( local_ents, local_verts );
02688
02689 // remove from local set the vertices
02690 rval = context.MBI->remove_entities( local_set, local_verts );MB_CHK_ERR( rval );
02691
02692 #ifdef VERBOSE
02693 std::cout << "current_receiver " << current_receiver << " local verts: " << local_verts.size() << "\n";
02694 #endif
02695 MergeMesh mm( context.MBI );
02696
02697 rval = mm.merge_using_integer_tag( local_verts, idtag );MB_CHK_ERR( rval );
02698
02699 Range new_verts; // local elems are local entities without vertices
02700 rval = context.MBI->get_connectivity( local_elems, new_verts );MB_CHK_ERR( rval );
02701
02702 #ifdef VERBOSE
02703 std::cout << "after merging: new verts: " << new_verts.size() << "\n";
02704 #endif
02705 rval = context.MBI->add_entities( local_set, new_verts );MB_CHK_ERR( rval );
02706 }
02707 }
02708 else
02709 data.point_cloud = true;
02710 }
02711 // it could be point cloud empty ?
02712 if( !data.point_cloud )
02713 {
02714 // still need to resolve shared entities (in this case, vertices )
02715 rval = pco->resolve_shared_ents( local_set, -1, -1, &idtag );MB_CHK_ERR( rval );
02716 }
02717 else
02718 {
02719 // if partition tag exists, set it to current rank; just to make it visible in VisIt
02720 Tag densePartTag;
02721 rval = context.MBI->tag_get_handle( "partition", densePartTag );
02722 if( NULL != densePartTag && MB_SUCCESS == rval )
02723 {
02724 Range local_verts;
02725 rval = context.MBI->get_entities_by_dimension( local_set, 0, local_verts );MB_CHK_ERR( rval );
02726 std::vector< int > vals;
02727 int rank = pco->rank();
02728 vals.resize( local_verts.size(), rank );
02729 rval = context.MBI->tag_set_data( densePartTag, local_verts, &vals[0] );MB_CHK_ERR( rval );
02730 }
02731 }
02732 // set the parallel partition tag
02733 Tag part_tag;
02734 int dum_id = -1;
02735 rval = context.MBI->tag_get_handle( "PARALLEL_PARTITION", 1, MB_TYPE_INTEGER, part_tag,
02736 MB_TAG_CREAT | MB_TAG_SPARSE, &dum_id );
02737
02738 if( part_tag == NULL || ( ( rval != MB_SUCCESS ) && ( rval != MB_ALREADY_ALLOCATED ) ) )
02739 {
02740 std::cout << " can't get par part tag.\n";
02741 return moab::MB_FAILURE;
02742 }
02743
02744 int rank = pco->rank();
02745 rval = context.MBI->tag_set_data( part_tag, &local_set, 1, &rank );MB_CHK_ERR( rval );
02746
02747 // populate the mesh with current data info
02748 rval = iMOAB_UpdateMeshInfo( pid );MB_CHK_ERR( rval );
02749
02750 // mark for deletion
02751 MPI_Group_free( &receiverGroup );
02752
02753 return moab::MB_SUCCESS;
02754 }
02755
02756 // need to send the zoltan buffer from coupler root towards the component root
02757 ErrCode iMOAB_RetrieveZBuffer( MPI_Group* cmpGrp, MPI_Group* cplGrp, MPI_Comm* joint, int* is_fortran )
02758 {
02759 // need to use MPI_Group_translate_ranks to find the rank of sender root and the rank of receiver root,
02760 // in the joint communicator
02761 assert( cmpGrp != nullptr );
02762 assert( cplGrp != nullptr );
02763 assert( joint != nullptr );
02764
02765 MPI_Group cmpGroup = ( *is_fortran ? MPI_Group_f2c( *reinterpret_cast< MPI_Fint* >( cmpGrp ) ) : *cmpGrp );
02766 MPI_Group cplGroup = ( *is_fortran ? MPI_Group_f2c( *reinterpret_cast< MPI_Fint* >( cplGrp ) ) : *cplGrp );
02767 MPI_Comm jointComm = ( *is_fortran ? MPI_Comm_f2c( *reinterpret_cast< MPI_Fint* >( joint ) ) : *joint );
02768
02769 int rootRank = 0;
02770 int rankCompRoot = -1; // this will receive the buffer
02771 int rankCouplerRoot = -1; // this will send the coupler
02772 int rank, ierr;
02773 MPI_Group global_grp;
02774 MPI_Comm_group( jointComm, &global_grp );
02775 MPI_Group_translate_ranks( cmpGroup, 1, &rootRank, global_grp, &rankCompRoot );
02776 MPI_Group_translate_ranks( cplGroup, 1, &rootRank, global_grp, &rankCouplerRoot );
02777 MPI_Comm_rank( jointComm, &rank );
02778 MPI_Group_free( &global_grp ); // we do not need the global group anymore
02779 #ifdef MOAB_HAVE_ZOLTAN
02780 // send from root of coupler, towards the root of component
02781 if( rankCouplerRoot != rankCompRoot ) // we do not send / receive if we do not have to; it is a blocking send/recv
02782 {
02783 if( rank == rankCouplerRoot )
02784 {
02785 // do a send of context.uniqueZoltanBuffer, towards the rankCompRoot
02786 ierr = MPI_Send( &context.uniqueZoltanBuffer[0], (int)context.uniqueZoltanBuffer.size(), MPI_CHAR,
02787 rankCompRoot, 123, jointComm );CHK_MPI_ERR( ierr );
02788 }
02789 if( rank == rankCompRoot )
02790 {
02791 // first a probe, then a MPI_Recv
02792 MPI_Status status;
02793 ierr = MPI_Probe( rankCouplerRoot, 123, jointComm, &status );CHK_MPI_ERR( ierr );
02794 // get the count of data received from the MPI_Status structure
02795 int size_buff;
02796 ierr = MPI_Get_count( &status, MPI_CHAR, &size_buff );CHK_MPI_ERR( ierr );
02797
02798 context.uniqueZoltanBuffer.resize( size_buff );
02799 ierr = MPI_Recv( &context.uniqueZoltanBuffer[0], size_buff, MPI_CHAR, rankCouplerRoot, 123, jointComm,
02800 &status );CHK_MPI_ERR( ierr );
02801 }
02802 }
02803 #endif
02804 return moab::MB_SUCCESS;
02805 }
02806
02807 ErrCode iMOAB_SendElementTag( iMOAB_AppID pid, const iMOAB_String tag_storage_name, MPI_Comm* join, int* context_id )
02808 {
02809
02810 appData& data = context.appDatas[*pid];
02811 std::map< int, ParCommGraph* >::iterator mt = data.pgraph.find( *context_id );
02812 if( mt == data.pgraph.end() )
02813 {
02814 return moab::MB_FAILURE;
02815 }
02816 ParCommGraph* cgraph = mt->second;
02817 ParallelComm* pco = context.pcomms[*pid];
02818 Range owned = data.owned_elems;
02819 ErrorCode rval;
02820 EntityHandle cover_set;
02821
02822 MPI_Comm global = ( data.is_fortran ? MPI_Comm_f2c( *reinterpret_cast< MPI_Fint* >( join ) ) : *join );
02823 if( data.point_cloud )
02824 {
02825 owned = data.local_verts;
02826 }
02827
02828 // another possibility is for par comm graph to be computed from iMOAB_ComputeCommGraph, for
02829 // after atm ocn intx, from phys (case from imoab_phatm_ocn_coupler.cpp) get then the cover set
02830 // from ints remapper
02831 #ifdef MOAB_HAVE_TEMPESTREMAP
02832 if( data.tempestData.remapper != NULL ) // this is the case this is part of intx;;
02833 {
02834 cover_set = data.tempestData.remapper->GetMeshSet( Remapper::CoveringMesh );
02835 rval = context.MBI->get_entities_by_dimension( cover_set, 2, owned );MB_CHK_ERR( rval );
02836 // should still have only quads ?
02837 }
02838 #else
02839 // now, in case we are sending from intx between ocn and atm, we involve coverage set
02840 // how do I know if this receiver already participated in an intersection driven by coupler?
02841 // also, what if this was the "source" mesh in intx?
02842 // in that case, the elements might have been instantiated in the coverage set locally, the
02843 // "owned" range can be different the elements are now in tempestRemap coverage_set
02844 cover_set = cgraph->get_cover_set(); // this will be non null only for intx app ?
02845
02846 if( 0 != cover_set )
02847 {
02848 rval = context.MBI->get_entities_by_dimension( cover_set, 2, owned );MB_CHK_ERR( rval );
02849 }
02850 #endif
02851
02852 std::string tag_name( tag_storage_name );
02853
02854 // basically, we assume everything is defined already on the tag,
02855 // and we can get the tags just by its name
02856 // we assume that there are separators ":" between the tag names
02857 std::vector< std::string > tagNames;
02858 std::vector< Tag > tagHandles;
02859 std::string separator( ":" );
02860 split_tag_names( tag_name, separator, tagNames );
02861 for( size_t i = 0; i < tagNames.size(); i++ )
02862 {
02863 Tag tagHandle;
02864 rval = context.MBI->tag_get_handle( tagNames[i].c_str(), tagHandle );
02865 if( MB_SUCCESS != rval || NULL == tagHandle )
02866 {
02867 std::cout << " can't get tag handle for tag named:" << tagNames[i].c_str() << " at index " << i << "\n";MB_CHK_SET_ERR( rval, "can't get tag handle" );
02868 }
02869 tagHandles.push_back( tagHandle );
02870 }
02871
02872 // pco is needed to pack, and for moab instance, not for communication!
02873 // still use nonblocking communication, over the joint comm
02874 rval = cgraph->send_tag_values( global, pco, owned, tagHandles );MB_CHK_ERR( rval );
02875 // now, send to each corr_tasks[i] tag data for corr_sizes[i] primary entities
02876
02877 return moab::MB_SUCCESS;
02878 }
02879
02880 ErrCode iMOAB_ReceiveElementTag( iMOAB_AppID pid, const iMOAB_String tag_storage_name, MPI_Comm* join, int* context_id )
02881 {
02882 appData& data = context.appDatas[*pid];
02883
02884 std::map< int, ParCommGraph* >::iterator mt = data.pgraph.find( *context_id );
02885 if( mt == data.pgraph.end() )
02886 {
02887 return moab::MB_FAILURE;
02888 }
02889 ParCommGraph* cgraph = mt->second;
02890
02891 MPI_Comm global = ( data.is_fortran ? MPI_Comm_f2c( *reinterpret_cast< MPI_Fint* >( join ) ) : *join );
02892 ParallelComm* pco = context.pcomms[*pid];
02893 Range owned = data.owned_elems;
02894
02895 // how do I know if this receiver already participated in an intersection driven by coupler?
02896 // also, what if this was the "source" mesh in intx?
02897 // in that case, the elements might have been instantiated in the coverage set locally, the
02898 // "owned" range can be different the elements are now in tempestRemap coverage_set
02899 EntityHandle cover_set = cgraph->get_cover_set();
02900 ErrorCode rval;
02901 if( 0 != cover_set )
02902 {
02903 rval = context.MBI->get_entities_by_dimension( cover_set, 2, owned );MB_CHK_ERR( rval );
02904 }
02905 if( data.point_cloud )
02906 {
02907 owned = data.local_verts;
02908 }
02909 // another possibility is for par comm graph to be computed from iMOAB_ComputeCommGraph, for
02910 // after atm ocn intx, from phys (case from imoab_phatm_ocn_coupler.cpp) get then the cover set
02911 // from ints remapper
02912 #ifdef MOAB_HAVE_TEMPESTREMAP
02913 if( data.tempestData.remapper != NULL ) // this is the case this is part of intx;;
02914 {
02915 cover_set = data.tempestData.remapper->GetMeshSet( Remapper::CoveringMesh );
02916 rval = context.MBI->get_entities_by_dimension( cover_set, 2, owned );MB_CHK_ERR( rval );
02917 // should still have only quads ?
02918 }
02919 #endif
02920 /*
02921 * data_intx.remapper exists though only on the intersection application
02922 * how do we get from here ( we know the pid that receives, and the commgraph used by migrate
02923 * mesh )
02924 */
02925
02926 std::string tag_name( tag_storage_name );
02927
02928 // we assume that there are separators ";" between the tag names
02929 std::vector< std::string > tagNames;
02930 std::vector< Tag > tagHandles;
02931 std::string separator( ":" );
02932 split_tag_names( tag_name, separator, tagNames );
02933 for( size_t i = 0; i < tagNames.size(); i++ )
02934 {
02935 Tag tagHandle;
02936 rval = context.MBI->tag_get_handle( tagNames[i].c_str(), tagHandle );
02937 if( MB_SUCCESS != rval || NULL == tagHandle )
02938 {
02939 std::cout << " can't get tag handle for tag named:" << tagNames[i].c_str() << " at index " << i << "\n";MB_CHK_SET_ERR( rval, "can't get tag handle" );
02940 }
02941 tagHandles.push_back( tagHandle );
02942 }
02943
02944 #ifdef VERBOSE
02945 std::cout << pco->rank() << ". Looking to receive data for tags: " << tag_name
02946 << " and file set = " << ( data.file_set ) << "\n";
02947 #endif
02948 // pco is needed to pack, and for moab instance, not for communication!
02949 // still use nonblocking communication
02950 rval = cgraph->receive_tag_values( global, pco, owned, tagHandles );MB_CHK_ERR( rval );
02951
02952 #ifdef VERBOSE
02953 std::cout << pco->rank() << ". Looking to receive data for tags: " << tag_name << "\n";
02954 #endif
02955
02956 return moab::MB_SUCCESS;
02957 }
02958
02959 ErrCode iMOAB_FreeSenderBuffers( iMOAB_AppID pid, int* context_id )
02960 {
02961 // need first to find the pgraph that holds the information we need
02962 // this will be called on sender side only
02963 appData& data = context.appDatas[*pid];
02964 std::map< int, ParCommGraph* >::iterator mt = data.pgraph.find( *context_id );
02965 if( mt == data.pgraph.end() ) return moab::MB_FAILURE; // error
02966
02967 mt->second->release_send_buffers();
02968 return moab::MB_SUCCESS;
02969 }
02970
02971 /**
02972 \brief compute a comm graph between 2 moab apps, based on ID matching
02973 Operations: Collective
02974 */
02975 //#define VERBOSE
02976 ErrCode iMOAB_ComputeCommGraph( iMOAB_AppID pid1,
02977 iMOAB_AppID pid2,
02978 MPI_Comm* join,
02979 MPI_Group* group1,
02980 MPI_Group* group2,
02981 int* type1,
02982 int* type2,
02983 int* comp1,
02984 int* comp2 )
02985 {
02986 assert( join );
02987 assert( group1 );
02988 assert( group2 );
02989 ErrorCode rval = MB_SUCCESS;
02990 int localRank = 0, numProcs = 1;
02991
02992 bool isFortran = false;
02993 if( *pid1 >= 0 ) isFortran = isFortran || context.appDatas[*pid1].is_fortran;
02994 if( *pid2 >= 0 ) isFortran = isFortran || context.appDatas[*pid2].is_fortran;
02995
02996 MPI_Comm global = ( isFortran ? MPI_Comm_f2c( *reinterpret_cast< MPI_Fint* >( join ) ) : *join );
02997 MPI_Group srcGroup = ( isFortran ? MPI_Group_f2c( *reinterpret_cast< MPI_Fint* >( group1 ) ) : *group1 );
02998 MPI_Group tgtGroup = ( isFortran ? MPI_Group_f2c( *reinterpret_cast< MPI_Fint* >( group2 ) ) : *group2 );
02999
03000 MPI_Comm_rank( global, &localRank );
03001 MPI_Comm_size( global, &numProcs );
03002 // instantiate the par comm graph
03003
03004 // we should search if we have another pcomm with the same comp ids in the list already
03005 // sort of check existing comm graphs in the map context.appDatas[*pid].pgraph
03006 bool already_exists = false;
03007 if( *pid1 >= 0 )
03008 {
03009 appData& data = context.appDatas[*pid1];
03010 std::map< int, ParCommGraph* >::iterator mt = data.pgraph.find( *comp2 );
03011 if( mt != data.pgraph.end() ) already_exists = true;
03012 }
03013 if( *pid2 >= 0 )
03014 {
03015 appData& data = context.appDatas[*pid2];
03016 std::map< int, ParCommGraph* >::iterator mt = data.pgraph.find( *comp1 );
03017 if( mt != data.pgraph.end() ) already_exists = true;
03018 }
03019 // nothing to do if it already exists
03020 if( already_exists )
03021 {
03022 #ifdef VERBOSE
03023 if( !localRank )
03024 std::cout << " parcomgraph already existing between components " << *comp1 << " and " << *comp2
03025 << ". Do not compute again\n";
03026 #endif
03027 return moab::MB_SUCCESS;
03028 }
03029
03030 // ParCommGraph::ParCommGraph(MPI_Comm joincomm, MPI_Group group1, MPI_Group group2, int coid1,
03031 // int coid2)
03032 ParCommGraph* cgraph = NULL;
03033 if( *pid1 >= 0 ) cgraph = new ParCommGraph( global, srcGroup, tgtGroup, *comp1, *comp2 );
03034 ParCommGraph* cgraph_rev = NULL;
03035 if( *pid2 >= 0 ) cgraph_rev = new ParCommGraph( global, tgtGroup, srcGroup, *comp2, *comp1 );
03036
03037 if( *pid1 >= 0 ) context.appDatas[*pid1].pgraph[*comp2] = cgraph; // the context will be the other comp
03038 if( *pid2 >= 0 ) context.appDatas[*pid2].pgraph[*comp1] = cgraph_rev; // from 2 to 1
03039 // each model has a list of global ids that will need to be sent by gs to rendezvous the other
03040 // model on the joint comm
03041 TupleList TLcomp1;
03042 TLcomp1.initialize( 2, 0, 0, 0, 0 ); // to proc, marker
03043 TupleList TLcomp2;
03044 TLcomp2.initialize( 2, 0, 0, 0, 0 ); // to proc, marker
03045 // will push_back a new tuple, if needed
03046
03047 TLcomp1.enableWriteAccess();
03048
03049 // tags of interest are either GLOBAL_DOFS or GLOBAL_ID
03050 Tag gdsTag;
03051 // find the values on first cell
03052 int lenTagType1 = 1;
03053 if( 1 == *type1 || 1 == *type2 )
03054 {
03055 rval = context.MBI->tag_get_handle( "GLOBAL_DOFS", gdsTag );MB_CHK_ERR( rval );
03056 rval = context.MBI->tag_get_length( gdsTag, lenTagType1 );MB_CHK_ERR( rval ); // usually it is 16
03057 }
03058 Tag tagType2 = context.MBI->globalId_tag();
03059
03060 std::vector< int > valuesComp1;
03061 // populate first tuple
03062 if( *pid1 >= 0 )
03063 {
03064 appData& data1 = context.appDatas[*pid1];
03065 EntityHandle fset1 = data1.file_set;
03066 // in case of tempest remap, get the coverage set
03067 #ifdef MOAB_HAVE_TEMPESTREMAP
03068 if( data1.tempestData.remapper != NULL ) // this is the case this is part of intx;;
03069 {
03070 fset1 = data1.tempestData.remapper->GetMeshSet( Remapper::CoveringMesh );
03071 // should still have only quads ?
03072 }
03073 #endif
03074 Range ents_of_interest;
03075 if( *type1 == 1 )
03076 {
03077 assert( gdsTag );
03078 rval = context.MBI->get_entities_by_type( fset1, MBQUAD, ents_of_interest );MB_CHK_ERR( rval );
03079 valuesComp1.resize( ents_of_interest.size() * lenTagType1 );
03080 rval = context.MBI->tag_get_data( gdsTag, ents_of_interest, &valuesComp1[0] );MB_CHK_ERR( rval );
03081 }
03082 else if( *type1 == 2 )
03083 {
03084 rval = context.MBI->get_entities_by_type( fset1, MBVERTEX, ents_of_interest );MB_CHK_ERR( rval );
03085 valuesComp1.resize( ents_of_interest.size() );
03086 rval = context.MBI->tag_get_data( tagType2, ents_of_interest, &valuesComp1[0] );MB_CHK_ERR( rval ); // just global ids
03087 }
03088 else if( *type1 == 3 ) // for FV meshes, just get the global id of cell
03089 {
03090 rval = context.MBI->get_entities_by_dimension( fset1, 2, ents_of_interest );MB_CHK_ERR( rval );
03091 valuesComp1.resize( ents_of_interest.size() );
03092 rval = context.MBI->tag_get_data( tagType2, ents_of_interest, &valuesComp1[0] );MB_CHK_ERR( rval ); // just global ids
03093 }
03094 else
03095 {
03096 MB_CHK_ERR( MB_FAILURE ); // we know only type 1 or 2 or 3
03097 }
03098 // now fill the tuple list with info and markers
03099 // because we will send only the ids, order and compress the list
03100 std::set< int > uniq( valuesComp1.begin(), valuesComp1.end() );
03101 TLcomp1.resize( uniq.size() );
03102 for( std::set< int >::iterator sit = uniq.begin(); sit != uniq.end(); sit++ )
03103 {
03104 // to proc, marker, element local index, index in el
03105 int marker = *sit;
03106 int to_proc = marker % numProcs;
03107 int n = TLcomp1.get_n();
03108 TLcomp1.vi_wr[2 * n] = to_proc; // send to processor
03109 TLcomp1.vi_wr[2 * n + 1] = marker;
03110 TLcomp1.inc_n();
03111 }
03112 }
03113
03114 ProcConfig pc( global ); // proc config does the crystal router
03115 pc.crystal_router()->gs_transfer( 1, TLcomp1,
03116 0 ); // communication towards joint tasks, with markers
03117 // sort by value (key 1)
03118 #ifdef VERBOSE
03119 std::stringstream ff1;
03120 ff1 << "TLcomp1_" << localRank << ".txt";
03121 TLcomp1.print_to_file( ff1.str().c_str() ); // it will append!
03122 #endif
03123 moab::TupleList::buffer sort_buffer;
03124 sort_buffer.buffer_init( TLcomp1.get_n() );
03125 TLcomp1.sort( 1, &sort_buffer );
03126 sort_buffer.reset();
03127 #ifdef VERBOSE
03128 // after sorting
03129 TLcomp1.print_to_file( ff1.str().c_str() ); // it will append!
03130 #endif
03131 // do the same, for the other component, number2, with type2
03132 // start copy
03133 TLcomp2.enableWriteAccess();
03134 // populate second tuple
03135 std::vector< int > valuesComp2;
03136 if( *pid2 >= 0 )
03137 {
03138 appData& data2 = context.appDatas[*pid2];
03139 EntityHandle fset2 = data2.file_set;
03140 // in case of tempest remap, get the coverage set
03141 #ifdef MOAB_HAVE_TEMPESTREMAP
03142 if( data2.tempestData.remapper != NULL ) // this is the case this is part of intx;;
03143 {
03144 fset2 = data2.tempestData.remapper->GetMeshSet( Remapper::CoveringMesh );
03145 // should still have only quads ?
03146 }
03147 #endif
03148
03149 Range ents_of_interest;
03150 if( *type2 == 1 )
03151 {
03152 assert( gdsTag );
03153 rval = context.MBI->get_entities_by_type( fset2, MBQUAD, ents_of_interest );MB_CHK_ERR( rval );
03154 valuesComp2.resize( ents_of_interest.size() * lenTagType1 );
03155 rval = context.MBI->tag_get_data( gdsTag, ents_of_interest, &valuesComp2[0] );MB_CHK_ERR( rval );
03156 }
03157 else if( *type2 == 2 )
03158 {
03159 rval = context.MBI->get_entities_by_type( fset2, MBVERTEX, ents_of_interest );MB_CHK_ERR( rval );
03160 valuesComp2.resize( ents_of_interest.size() ); // stride is 1 here
03161 rval = context.MBI->tag_get_data( tagType2, ents_of_interest, &valuesComp2[0] );MB_CHK_ERR( rval ); // just global ids
03162 }
03163 else if( *type2 == 3 )
03164 {
03165 rval = context.MBI->get_entities_by_dimension( fset2, 2, ents_of_interest );MB_CHK_ERR( rval );
03166 valuesComp2.resize( ents_of_interest.size() ); // stride is 1 here
03167 rval = context.MBI->tag_get_data( tagType2, ents_of_interest, &valuesComp2[0] );MB_CHK_ERR( rval ); // just global ids
03168 }
03169 else
03170 {
03171 MB_CHK_ERR( MB_FAILURE ); // we know only type 1 or 2
03172 }
03173 // now fill the tuple list with info and markers
03174 std::set< int > uniq( valuesComp2.begin(), valuesComp2.end() );
03175 TLcomp2.resize( uniq.size() );
03176 for( std::set< int >::iterator sit = uniq.begin(); sit != uniq.end(); sit++ )
03177 {
03178 // to proc, marker, element local index, index in el
03179 int marker = *sit;
03180 int to_proc = marker % numProcs;
03181 int n = TLcomp2.get_n();
03182 TLcomp2.vi_wr[2 * n] = to_proc; // send to processor
03183 TLcomp2.vi_wr[2 * n + 1] = marker;
03184 TLcomp2.inc_n();
03185 }
03186 }
03187 pc.crystal_router()->gs_transfer( 1, TLcomp2,
03188 0 ); // communication towards joint tasks, with markers
03189 // sort by value (key 1)
03190 #ifdef VERBOSE
03191 std::stringstream ff2;
03192 ff2 << "TLcomp2_" << localRank << ".txt";
03193 TLcomp2.print_to_file( ff2.str().c_str() );
03194 #endif
03195 sort_buffer.buffer_reserve( TLcomp2.get_n() );
03196 TLcomp2.sort( 1, &sort_buffer );
03197 sort_buffer.reset();
03198 // end copy
03199 #ifdef VERBOSE
03200 TLcomp2.print_to_file( ff2.str().c_str() );
03201 #endif
03202 // need to send back the info, from the rendezvous point, for each of the values
03203 /* so go over each value, on local process in joint communicator
03204
03205 now have to send back the info needed for communication;
03206 loop in in sync over both TLComp1 and TLComp2, in local process;
03207 So, build new tuple lists, to send synchronous communication
03208 populate them at the same time, based on marker, that is indexed
03209 */
03210
03211 TupleList TLBackToComp1;
03212 TLBackToComp1.initialize( 3, 0, 0, 0, 0 ); // to proc, marker, from proc on comp2,
03213 TLBackToComp1.enableWriteAccess();
03214
03215 TupleList TLBackToComp2;
03216 TLBackToComp2.initialize( 3, 0, 0, 0, 0 ); // to proc, marker, from proc,
03217 TLBackToComp2.enableWriteAccess();
03218
03219 int n1 = TLcomp1.get_n();
03220 int n2 = TLcomp2.get_n();
03221
03222 int indexInTLComp1 = 0;
03223 int indexInTLComp2 = 0; // advance both, according to the marker
03224 if( n1 > 0 && n2 > 0 )
03225 {
03226
03227 while( indexInTLComp1 < n1 && indexInTLComp2 < n2 ) // if any is over, we are done
03228 {
03229 int currentValue1 = TLcomp1.vi_rd[2 * indexInTLComp1 + 1];
03230 int currentValue2 = TLcomp2.vi_rd[2 * indexInTLComp2 + 1];
03231 if( currentValue1 < currentValue2 )
03232 {
03233 // we have a big problem; basically, we are saying that
03234 // dof currentValue is on one model and not on the other
03235 // std::cout << " currentValue1:" << currentValue1 << " missing in comp2" << "\n";
03236 indexInTLComp1++;
03237 continue;
03238 }
03239 if( currentValue1 > currentValue2 )
03240 {
03241 // std::cout << " currentValue2:" << currentValue2 << " missing in comp1" << "\n";
03242 indexInTLComp2++;
03243 continue;
03244 }
03245 int size1 = 1;
03246 int size2 = 1;
03247 while( indexInTLComp1 + size1 < n1 && currentValue1 == TLcomp1.vi_rd[2 * ( indexInTLComp1 + size1 ) + 1] )
03248 size1++;
03249 while( indexInTLComp2 + size2 < n2 && currentValue2 == TLcomp2.vi_rd[2 * ( indexInTLComp2 + size2 ) + 1] )
03250 size2++;
03251 // must be found in both lists, find the start and end indices
03252 for( int i1 = 0; i1 < size1; i1++ )
03253 {
03254 for( int i2 = 0; i2 < size2; i2++ )
03255 {
03256 // send the info back to components
03257 int n = TLBackToComp1.get_n();
03258 TLBackToComp1.reserve();
03259 TLBackToComp1.vi_wr[3 * n] =
03260 TLcomp1.vi_rd[2 * ( indexInTLComp1 + i1 )]; // send back to the proc marker
03261 // came from, info from comp2
03262 TLBackToComp1.vi_wr[3 * n + 1] = currentValue1; // initial value (resend?)
03263 TLBackToComp1.vi_wr[3 * n + 2] = TLcomp2.vi_rd[2 * ( indexInTLComp2 + i2 )]; // from proc on comp2
03264 n = TLBackToComp2.get_n();
03265 TLBackToComp2.reserve();
03266 TLBackToComp2.vi_wr[3 * n] =
03267 TLcomp2.vi_rd[2 * ( indexInTLComp2 + i2 )]; // send back info to original
03268 TLBackToComp2.vi_wr[3 * n + 1] = currentValue1; // initial value (resend?)
03269 TLBackToComp2.vi_wr[3 * n + 2] = TLcomp1.vi_rd[2 * ( indexInTLComp1 + i1 )]; // from proc on comp1
03270 // what if there are repeated markers in TLcomp2? increase just index2
03271 }
03272 }
03273 indexInTLComp1 += size1;
03274 indexInTLComp2 += size2;
03275 }
03276 }
03277 pc.crystal_router()->gs_transfer( 1, TLBackToComp1, 0 ); // communication towards original tasks, with info about
03278 pc.crystal_router()->gs_transfer( 1, TLBackToComp2, 0 );
03279
03280 if( *pid1 >= 0 )
03281 {
03282 // we are on original comp 1 tasks
03283 // before ordering
03284 // now for each value in TLBackToComp1.vi_rd[3*i+1], on current proc, we know the
03285 // processors it communicates with
03286 #ifdef VERBOSE
03287 std::stringstream f1;
03288 f1 << "TLBack1_" << localRank << ".txt";
03289 TLBackToComp1.print_to_file( f1.str().c_str() );
03290 #endif
03291 sort_buffer.buffer_reserve( TLBackToComp1.get_n() );
03292 TLBackToComp1.sort( 1, &sort_buffer );
03293 sort_buffer.reset();
03294 #ifdef VERBOSE
03295 TLBackToComp1.print_to_file( f1.str().c_str() );
03296 #endif
03297 // so we are now on pid1, we know now each marker were it has to go
03298 // add a new method to ParCommGraph, to set up the involved_IDs_map
03299 cgraph->settle_comm_by_ids( *comp1, TLBackToComp1, valuesComp1 );
03300 }
03301 if( *pid2 >= 0 )
03302 {
03303 // we are on original comp 1 tasks
03304 // before ordering
03305 // now for each value in TLBackToComp1.vi_rd[3*i+1], on current proc, we know the
03306 // processors it communicates with
03307 #ifdef VERBOSE
03308 std::stringstream f2;
03309 f2 << "TLBack2_" << localRank << ".txt";
03310 TLBackToComp2.print_to_file( f2.str().c_str() );
03311 #endif
03312 sort_buffer.buffer_reserve( TLBackToComp2.get_n() );
03313 TLBackToComp2.sort( 2, &sort_buffer );
03314 sort_buffer.reset();
03315 #ifdef VERBOSE
03316 TLBackToComp2.print_to_file( f2.str().c_str() );
03317 #endif
03318 cgraph_rev->settle_comm_by_ids( *comp2, TLBackToComp2, valuesComp2 );
03319 //
03320 }
03321 return moab::MB_SUCCESS;
03322 }
03323
03324 //#undef VERBOSE
03325
03326 ErrCode iMOAB_MergeVertices( iMOAB_AppID pid )
03327 {
03328 appData& data = context.appDatas[*pid];
03329 ParallelComm* pco = context.pcomms[*pid];
03330 // collapse vertices and transform cells into triangles/quads /polys
03331 // tags we care about: area, frac, global id
03332 std::vector< Tag > tagsList;
03333 Tag tag;
03334 ErrorCode rval = context.MBI->tag_get_handle( "GLOBAL_ID", tag );
03335 if( !tag || rval != MB_SUCCESS ) return moab::MB_FAILURE; // fatal error, abort
03336 tagsList.push_back( tag );
03337 rval = context.MBI->tag_get_handle( "area", tag );
03338 if( tag && rval == MB_SUCCESS ) tagsList.push_back( tag );
03339 rval = context.MBI->tag_get_handle( "frac", tag );
03340 if( tag && rval == MB_SUCCESS ) tagsList.push_back( tag );
03341 double tol = 1.0e-9;
03342 rval = IntxUtils::remove_duplicate_vertices( context.MBI, data.file_set, tol, tagsList );MB_CHK_ERR( rval );
03343
03344 // clean material sets of cells that were deleted
03345 rval = context.MBI->get_entities_by_type_and_tag( data.file_set, MBENTITYSET, &( context.material_tag ), 0, 1,
03346 data.mat_sets, Interface::UNION );MB_CHK_ERR( rval );
03347
03348 if( !data.mat_sets.empty() )
03349 {
03350 EntityHandle matSet = data.mat_sets[0];
03351 Range elems;
03352 rval = context.MBI->get_entities_by_dimension( matSet, 2, elems );MB_CHK_ERR( rval );
03353 rval = context.MBI->remove_entities( matSet, elems );MB_CHK_ERR( rval );
03354 // put back only cells from data.file_set
03355 elems.clear();
03356 rval = context.MBI->get_entities_by_dimension( data.file_set, 2, elems );MB_CHK_ERR( rval );
03357 rval = context.MBI->add_entities( matSet, elems );MB_CHK_ERR( rval );
03358 }
03359 rval = iMOAB_UpdateMeshInfo( pid );MB_CHK_ERR( rval );
03360
03361 ParallelMergeMesh pmm( pco, tol );
03362 rval = pmm.merge( data.file_set,
03363 /* do not do local merge*/ false,
03364 /* 2d cells*/ 2 );MB_CHK_ERR( rval );
03365
03366 // assign global ids only for vertices, cells have them fine
03367 rval = pco->assign_global_ids( data.file_set, /*dim*/ 0 );MB_CHK_ERR( rval );
03368
03369 // set the partition tag on the file set
03370 Tag part_tag;
03371 int dum_id = -1;
03372 rval = context.MBI->tag_get_handle( "PARALLEL_PARTITION", 1, MB_TYPE_INTEGER, part_tag,
03373 MB_TAG_CREAT | MB_TAG_SPARSE, &dum_id );
03374
03375 if( part_tag == NULL || ( ( rval != MB_SUCCESS ) && ( rval != MB_ALREADY_ALLOCATED ) ) )
03376 {
03377 std::cout << " can't get par part tag.\n";
03378 return moab::MB_FAILURE;
03379 }
03380
03381 int rank = pco->rank();
03382 rval = context.MBI->tag_set_data( part_tag, &data.file_set, 1, &rank );MB_CHK_ERR( rval );
03383
03384 return moab::MB_SUCCESS;
03385 }
03386
03387 #ifdef MOAB_HAVE_TEMPESTREMAP
03388
03389 // this call must be collective on the joint communicator
03390 // intersection tasks on coupler will need to send to the components tasks the list of
03391 // id elements that are relevant: they intersected some of the target elements (which are not needed
03392 // here)
03393 // in the intersection
03394 ErrCode iMOAB_CoverageGraph( MPI_Comm* join,
03395 iMOAB_AppID pid_src,
03396 iMOAB_AppID pid_migr,
03397 iMOAB_AppID pid_intx,
03398 int* src_id,
03399 int* migr_id,
03400 int* context_id )
03401 {
03402 // first, based on the scompid and migrcomp, find the parCommGraph corresponding to this
03403 // exchange
03404 ErrorCode rval;
03405 std::vector< int > srcSenders;
03406 std::vector< int > receivers;
03407 ParCommGraph* sendGraph = NULL;
03408 int ierr;
03409 int default_context_id = -1;
03410 bool is_fortran_context = false;
03411
03412 // First, find the original graph between PE sets
03413 // And based on this one, we will build the newly modified one for coverage
03414 if( *pid_src >= 0 )
03415 {
03416 default_context_id = *migr_id; // the other one
03417 assert( context.appDatas[*pid_src].global_id == *src_id );
03418 is_fortran_context = context.appDatas[*pid_src].is_fortran || is_fortran_context;
03419 sendGraph = context.appDatas[*pid_src].pgraph[default_context_id]; // maybe check if it does not exist
03420
03421 // report the sender and receiver tasks in the joint comm
03422 srcSenders = sendGraph->senders();
03423 receivers = sendGraph->receivers();
03424 #ifdef VERBOSE
03425 std::cout << "senders: " << srcSenders.size() << " first sender: " << srcSenders[0] << std::endl;
03426 #endif
03427 }
03428
03429 ParCommGraph* recvGraph = NULL; // will be non null on receiver tasks (intx tasks)
03430 if( *pid_migr >= 0 )
03431 {
03432 is_fortran_context = context.appDatas[*pid_migr].is_fortran || is_fortran_context;
03433 // find the original one
03434 default_context_id = *src_id;
03435 assert( context.appDatas[*pid_migr].global_id == *migr_id );
03436 recvGraph = context.appDatas[*pid_migr].pgraph[default_context_id];
03437 // report the sender and receiver tasks in the joint comm, from migrated mesh pt of view
03438 srcSenders = recvGraph->senders();
03439 receivers = recvGraph->receivers();
03440 #ifdef VERBOSE
03441 std::cout << "receivers: " << receivers.size() << " first receiver: " << receivers[0] << std::endl;
03442 #endif
03443 }
03444
03445 if( *pid_intx >= 0 ) is_fortran_context = context.appDatas[*pid_intx].is_fortran || is_fortran_context;
03446
03447 // loop over pid_intx elements, to see what original processors in joint comm have sent the
03448 // coverage mesh;
03449 // If we are on intx tasks, send coverage info towards original component tasks,
03450 // about needed cells
03451 TupleList TLcovIDs;
03452 TLcovIDs.initialize( 2, 0, 0, 0, 0 ); // to proc, GLOBAL ID; estimate about 100 IDs to be sent
03453 // will push_back a new tuple, if needed
03454 TLcovIDs.enableWriteAccess();
03455 // the crystal router will send ID cell to the original source, on the component task
03456 // if we are on intx tasks, loop over all intx elements and
03457
03458 MPI_Comm global = ( is_fortran_context ? MPI_Comm_f2c( *reinterpret_cast< MPI_Fint* >( join ) ) : *join );
03459 int currentRankInJointComm = -1;
03460 ierr = MPI_Comm_rank( global, ¤tRankInJointComm );CHK_MPI_ERR( ierr );
03461
03462 // if currentRankInJointComm is in receivers list, it means that we are on intx tasks too, we
03463 // need to send information towards component tasks
03464 if( find( receivers.begin(), receivers.end(), currentRankInJointComm ) !=
03465 receivers.end() ) // we are on receivers tasks, we can request intx info
03466 {
03467 // find the pcomm for the intx pid
03468 if( *pid_intx >= (int)context.appDatas.size() ) return moab::MB_FAILURE;
03469
03470 appData& dataIntx = context.appDatas[*pid_intx];
03471 Tag parentTag, orgSendProcTag;
03472
03473 rval = context.MBI->tag_get_handle( "SourceParent", parentTag );MB_CHK_ERR( rval ); // global id of the blue, source element
03474 if( !parentTag ) return moab::MB_FAILURE; // fatal error, abort
03475
03476 rval = context.MBI->tag_get_handle( "orig_sending_processor", orgSendProcTag );MB_CHK_ERR( rval );
03477 if( !orgSendProcTag ) return moab::MB_FAILURE; // fatal error, abort
03478
03479 // find the file set, red parents for intx cells, and put them in tuples
03480 EntityHandle intxSet = dataIntx.file_set;
03481 Range cells;
03482 // get all entities from the set, and look at their RedParent
03483 rval = context.MBI->get_entities_by_dimension( intxSet, 2, cells );MB_CHK_ERR( rval );
03484
03485 std::map< int, std::set< int > > idsFromProcs; // send that info back to enhance parCommGraph cache
03486 for( Range::iterator it = cells.begin(); it != cells.end(); it++ )
03487 {
03488 EntityHandle intx_cell = *it;
03489 int gidCell, origProc; // look at receivers
03490
03491 rval = context.MBI->tag_get_data( parentTag, &intx_cell, 1, &gidCell );MB_CHK_ERR( rval );
03492 rval = context.MBI->tag_get_data( orgSendProcTag, &intx_cell, 1, &origProc );MB_CHK_ERR( rval );
03493 // we have augmented the overlap set with ghost cells ; in that case, the
03494 // orig_sending_processor is not set so it will be -1;
03495 if( origProc < 0 ) continue;
03496
03497 std::set< int >& setInts = idsFromProcs[origProc];
03498 setInts.insert( gidCell );
03499 }
03500 // questionable ??
03501 #if 0
03502 // if we have no intx cells, it means we are on point clouds; quick fix just use all cells
03503 // from coverage set
03504 if( cells.empty() )
03505 {
03506 // get coverage set
03507 assert( *pid_intx >= 0 );
03508 appData& dataIntx = context.appDatas[*pid_intx];
03509 EntityHandle cover_set = dataIntx.tempestData.remapper->GetMeshSet( Remapper::CoveringMesh );
03510
03511 // get all cells from coverage set
03512 Tag gidTag;
03513 rval = context.MBI->tag_get_handle( "GLOBAL_ID", gidTag );MB_CHK_ERR( rval );
03514 rval = context.MBI->get_entities_by_dimension( cover_set, 2, cells );MB_CHK_ERR( rval );
03515 // look at their orig_sending_processor
03516 for( Range::iterator it = cells.begin(); it != cells.end(); it++ )
03517 {
03518 EntityHandle covCell = *it;
03519 int gidCell, origProc; // look at o
03520
03521 rval = context.MBI->tag_get_data( gidTag, &covCell, 1, &gidCell );MB_CHK_ERR( rval );
03522 rval = context.MBI->tag_get_data( orgSendProcTag, &covCell, 1, &origProc );MB_CHK_ERR( rval );
03523 // we have augmented the overlap set with ghost cells ; in that case, the
03524 // orig_sending_processor is not set so it will be -1;
03525 if( origProc < 0 ) // it cannot < 0, I think
03526 continue;
03527 std::set< int >& setInts = idsFromProcs[origProc];
03528 setInts.insert( gidCell );
03529 }
03530 }
03531 #endif // #if 0
03532
03533 #ifdef VERBOSE
03534 std::ofstream dbfile;
03535 std::stringstream outf;
03536 outf << "idsFromProc_0" << currentRankInJointComm << ".txt";
03537 dbfile.open( outf.str().c_str() );
03538 dbfile << "Writing this to a file.\n";
03539
03540 dbfile << " map size:" << idsFromProcs.size()
03541 << std::endl; // on the receiver side, these show how much data to receive
03542 // from the sender (how many ids, and how much tag data later; we need to size up the
03543 // receiver buffer) arrange in tuples , use map iterators to send the ids
03544 for( std::map< int, std::set< int > >::iterator mt = idsFromProcs.begin(); mt != idsFromProcs.end(); mt++ )
03545 {
03546 std::set< int >& setIds = mt->second;
03547 dbfile << "from id: " << mt->first << " receive " << setIds.size() << " cells \n";
03548 int counter = 0;
03549 for( std::set< int >::iterator st = setIds.begin(); st != setIds.end(); st++ )
03550 {
03551 int valueID = *st;
03552 dbfile << " " << valueID;
03553 counter++;
03554 if( counter % 10 == 0 ) dbfile << "\n";
03555 }
03556 dbfile << "\n";
03557 }
03558 dbfile.close();
03559 #endif
03560 if( NULL != recvGraph )
03561 {
03562 ParCommGraph* recvGraph1 = new ParCommGraph( *recvGraph ); // just copy
03563 recvGraph1->set_context_id( *context_id );
03564 recvGraph1->SetReceivingAfterCoverage( idsFromProcs );
03565 // this par comm graph will need to use the coverage set
03566 // so we are for sure on intx pes (the receiver is the coupler mesh)
03567 assert( *pid_intx >= 0 );
03568 appData& dataIntx = context.appDatas[*pid_intx];
03569 EntityHandle cover_set = dataIntx.tempestData.remapper->GetMeshSet( Remapper::CoveringMesh );
03570 recvGraph1->set_cover_set( cover_set );
03571 context.appDatas[*pid_migr].pgraph[*context_id] = recvGraph1; // possible memory leak if context_id is same
03572 }
03573 // initial loop to see how much space we need for TLcovIDs
03574 size_t nbIds = 0;
03575 for( std::map< int, std::set< int > >::iterator mit = idsFromProcs.begin(); mit != idsFromProcs.end(); mit++ )
03576 {
03577 std::set< int >& idSet = mit->second;
03578 nbIds += idSet.size();
03579 }
03580
03581 TLcovIDs.resize( nbIds );
03582
03583 for( std::map< int, std::set< int > >::iterator mit = idsFromProcs.begin(); mit != idsFromProcs.end(); mit++ )
03584 {
03585 int procToSendTo = mit->first;
03586 std::set< int >& idSet = mit->second;
03587 for( std::set< int >::iterator sit = idSet.begin(); sit != idSet.end(); sit++ )
03588 {
03589 int n = TLcovIDs.get_n();
03590 TLcovIDs.vi_wr[2 * n] = procToSendTo; // send to processor
03591 TLcovIDs.vi_wr[2 * n + 1] = *sit; // global id needs index in the local_verts range
03592 TLcovIDs.inc_n();
03593 }
03594 }
03595 }
03596
03597 ProcConfig pc( global ); // proc config does the crystal router
03598 pc.crystal_router()->gs_transfer( 1, TLcovIDs,
03599 0 ); // communication towards component tasks, with what ids are needed
03600 // for each task from receiver
03601
03602 // a test to know if we are on the sender tasks (original component, in this case, atmosphere)
03603 if( NULL != sendGraph )
03604 {
03605 // collect TLcovIDs tuple, will set in a local map/set, the ids that are sent to each
03606 // receiver task
03607 ParCommGraph* sendGraph1 = new ParCommGraph( *sendGraph ); // just copy
03608 sendGraph1->set_context_id( *context_id );
03609 context.appDatas[*pid_src].pgraph[*context_id] = sendGraph1;
03610 rval = sendGraph1->settle_send_graph( TLcovIDs );MB_CHK_ERR( rval );
03611 }
03612 return moab::MB_SUCCESS; // success
03613 }
03614
03615 ErrCode iMOAB_DumpCommGraph( iMOAB_AppID pid, int* context_id, int* is_sender, int* verbose, const iMOAB_String prefix )
03616 {
03617
03618 ParCommGraph* cgraph = context.appDatas[*pid].pgraph[*context_id];
03619 std::string prefix_str( prefix );
03620
03621 if( NULL != cgraph )
03622 cgraph->dump_comm_information( prefix_str, *is_sender, *verbose );
03623 else
03624 {
03625 std::cout << " cannot find ParCommGraph on app with pid " << *pid << " name: " << context.appDatas[*pid].name
03626 << " context: " << *context_id << "\n";
03627 }
03628 return moab::MB_SUCCESS;
03629 }
03630
03631 #endif // #ifdef MOAB_HAVE_TEMPESTREMAP
03632
03633 #endif // #ifdef MOAB_HAVE_MPI
03634
03635 #ifdef MOAB_HAVE_TEMPESTREMAP
03636
03637 #ifdef MOAB_HAVE_NETCDF
03638 ErrCode iMOAB_LoadMappingWeightsFromFile(
03639 iMOAB_AppID pid_intersection,
03640 iMOAB_AppID pid_cpl,
03641 int* col_or_row,
03642 int* type,
03643 const iMOAB_String solution_weights_identifier, /* "scalar", "flux", "custom" */
03644 const iMOAB_String remap_weights_filename )
03645 {
03646 ErrorCode rval;
03647 bool row_based_partition = true;
03648 if( *col_or_row == 1 ) row_based_partition = false; // do a column based partition;
03649
03650 // get the local degrees of freedom, from the pid_cpl and type of mesh
03651
03652 // Get the source and target data and pcomm objects
03653 appData& data_intx = context.appDatas[*pid_intersection];
03654 TempestMapAppData& tdata = data_intx.tempestData;
03655
03656 // Get the handle to the remapper object
03657 if( tdata.remapper == NULL )
03658 {
03659 // Now allocate and initialize the remapper object
03660 #ifdef MOAB_HAVE_MPI
03661 ParallelComm* pco = context.pcomms[*pid_intersection];
03662 tdata.remapper = new moab::TempestRemapper( context.MBI, pco );
03663 #else
03664 tdata.remapper = new moab::TempestRemapper( context.MBI );
03665 #endif
03666 tdata.remapper->meshValidate = true;
03667 tdata.remapper->constructEdgeMap = true;
03668 // Do not create new filesets; Use the sets from our respective applications
03669 tdata.remapper->initialize( false );
03670 tdata.remapper->GetMeshSet( moab::Remapper::OverlapMesh ) = data_intx.file_set;
03671 }
03672
03673 // Setup loading of weights onto TempestOnlineMap
03674 // Set the context for the remapping weights computation
03675 tdata.weightMaps[std::string( solution_weights_identifier )] = new moab::TempestOnlineMap( tdata.remapper );
03676
03677 // Now allocate and initialize the remapper object
03678 moab::TempestOnlineMap* weightMap = tdata.weightMaps[std::string( solution_weights_identifier )];
03679 assert( weightMap != NULL );
03680
03681 if( *pid_cpl >= 0 ) // it means we are looking for how to distribute the degrees of freedom, new map reader
03682 {
03683 appData& data1 = context.appDatas[*pid_cpl];
03684 EntityHandle fset1 = data1.file_set; // this is source or target, depending on direction
03685
03686 // tags of interest are either GLOBAL_DOFS or GLOBAL_ID
03687 Tag gdsTag;
03688
03689 // find the values on first cell
03690 int lenTagType1 = 1;
03691 if( *type == 1 )
03692 {
03693 rval = context.MBI->tag_get_handle( "GLOBAL_DOFS", gdsTag );MB_CHK_ERR( rval );
03694 rval = context.MBI->tag_get_length( gdsTag, lenTagType1 );MB_CHK_ERR( rval ); // usually it is 16
03695 }
03696 Tag tagType2 = context.MBI->globalId_tag();
03697
03698 std::vector< int > dofValues;
03699
03700 // populate first tuple
03701 Range
03702 ents_of_interest; // will be filled with entities on coupler, from which we will get the DOFs, based on type
03703 int ndofPerEl = 1;
03704
03705 if( *type == 1 )
03706 {
03707 assert( gdsTag );
03708 rval = context.MBI->get_entities_by_type( fset1, MBQUAD, ents_of_interest );MB_CHK_ERR( rval );
03709 dofValues.resize( ents_of_interest.size() * lenTagType1 );
03710 rval = context.MBI->tag_get_data( gdsTag, ents_of_interest, &dofValues[0] );MB_CHK_ERR( rval );
03711 ndofPerEl = lenTagType1;
03712 }
03713 else if( *type == 2 )
03714 {
03715 rval = context.MBI->get_entities_by_type( fset1, MBVERTEX, ents_of_interest );MB_CHK_ERR( rval );
03716 dofValues.resize( ents_of_interest.size() );
03717 rval = context.MBI->tag_get_data( tagType2, ents_of_interest, &dofValues[0] );MB_CHK_ERR( rval ); // just global ids
03718 }
03719 else if( *type == 3 ) // for FV meshes, just get the global id of cell
03720 {
03721 rval = context.MBI->get_entities_by_dimension( fset1, 2, ents_of_interest );MB_CHK_ERR( rval );
03722 dofValues.resize( ents_of_interest.size() );
03723 rval = context.MBI->tag_get_data( tagType2, ents_of_interest, &dofValues[0] );MB_CHK_ERR( rval ); // just global ids
03724 }
03725 else
03726 {
03727 MB_CHK_ERR( MB_FAILURE ); // we know only type 1 or 2 or 3
03728 }
03729 // pass ordered dofs, and unique
03730 std::vector< int > orderDofs( dofValues.begin(), dofValues.end() );
03731
03732 std::sort( orderDofs.begin(), orderDofs.end() );
03733 orderDofs.erase( std::unique( orderDofs.begin(), orderDofs.end() ), orderDofs.end() ); // remove duplicates
03734
03735 rval = weightMap->ReadParallelMap( remap_weights_filename, orderDofs, row_based_partition );MB_CHK_ERR( rval );
03736
03737 // if we are on target mesh (row based partition)
03738 if( row_based_partition )
03739 {
03740 tdata.pid_dest = pid_cpl;
03741 tdata.remapper->SetMeshSet( Remapper::TargetMesh, fset1, ents_of_interest );
03742 weightMap->SetDestinationNDofsPerElement( ndofPerEl );
03743 weightMap->set_row_dc_dofs( dofValues ); // will set row_dtoc_dofmap
03744 }
03745 else
03746 {
03747 tdata.pid_src = pid_cpl;
03748 tdata.remapper->SetMeshSet( Remapper::SourceMesh, fset1, ents_of_interest );
03749 weightMap->SetSourceNDofsPerElement( ndofPerEl );
03750 weightMap->set_col_dc_dofs( dofValues ); // will set col_dtoc_dofmap
03751 }
03752 }
03753 else // old reader, trivial distribution by row
03754 {
03755 std::vector< int > tmp_owned_ids; // this will do a trivial row distribution
03756 rval = weightMap->ReadParallelMap( remap_weights_filename, tmp_owned_ids, row_based_partition );MB_CHK_ERR( rval );
03757 }
03758
03759 return moab::MB_SUCCESS;
03760 }
03761
03762 ErrCode iMOAB_WriteMappingWeightsToFile(
03763 iMOAB_AppID pid_intersection,
03764 const iMOAB_String solution_weights_identifier, /* "scalar", "flux", "custom" */
03765 const iMOAB_String remap_weights_filename )
03766 {
03767 assert( solution_weights_identifier && strlen( solution_weights_identifier ) );
03768 assert( remap_weights_filename && strlen( remap_weights_filename ) );
03769
03770 ErrorCode rval;
03771
03772 // Get the source and target data and pcomm objects
03773 appData& data_intx = context.appDatas[*pid_intersection];
03774 TempestMapAppData& tdata = data_intx.tempestData;
03775
03776 // Get the handle to the remapper object
03777 assert( tdata.remapper != NULL );
03778
03779 // Now get online weights object and ensure it is valid
03780 moab::TempestOnlineMap* weightMap = tdata.weightMaps[std::string( solution_weights_identifier )];
03781 assert( weightMap != NULL );
03782
03783 std::string filename = std::string( remap_weights_filename );
03784
03785 // Write the map file to disk in parallel using either HDF5 or SCRIP interface
03786 rval = weightMap->WriteParallelMap( filename );MB_CHK_ERR( rval );
03787
03788 return moab::MB_SUCCESS;
03789 }
03790
03791 #ifdef MOAB_HAVE_MPI
03792 ErrCode iMOAB_MigrateMapMesh( iMOAB_AppID pid1,
03793 iMOAB_AppID pid2,
03794 iMOAB_AppID pid3,
03795 MPI_Comm* jointcomm,
03796 MPI_Group* groupA,
03797 MPI_Group* groupB,
03798 int* type,
03799 int* comp1,
03800 int* comp2,
03801 int* direction )
03802 {
03803 assert( jointcomm );
03804 assert( groupA );
03805 assert( groupB );
03806 bool is_fortran = false;
03807 if( *pid1 >= 0 ) is_fortran = context.appDatas[*pid1].is_fortran || is_fortran;
03808 if( *pid2 >= 0 ) is_fortran = context.appDatas[*pid2].is_fortran || is_fortran;
03809 if( *pid3 >= 0 ) is_fortran = context.appDatas[*pid3].is_fortran || is_fortran;
03810
03811 MPI_Comm joint_communicator =
03812 ( is_fortran ? MPI_Comm_f2c( *reinterpret_cast< MPI_Fint* >( jointcomm ) ) : *jointcomm );
03813 MPI_Group group_first = ( is_fortran ? MPI_Group_f2c( *reinterpret_cast< MPI_Fint* >( groupA ) ) : *groupA );
03814 MPI_Group group_second = ( is_fortran ? MPI_Group_f2c( *reinterpret_cast< MPI_Fint* >( groupB ) ) : *groupB );
03815
03816 ErrorCode rval = MB_SUCCESS;
03817 int localRank = 0, numProcs = 1;
03818
03819 // Get the local rank and number of processes in the joint communicator
03820 MPI_Comm_rank( joint_communicator, &localRank );
03821 MPI_Comm_size( joint_communicator, &numProcs );
03822
03823 // Next instantiate the par comm graph
03824 // here we need to look at direction
03825 // this direction is good for atm source -> ocn target coupler example
03826 ParCommGraph* cgraph = NULL;
03827 if( *pid1 >= 0 ) cgraph = new ParCommGraph( joint_communicator, group_first, group_second, *comp1, *comp2 );
03828
03829 ParCommGraph* cgraph_rev = NULL;
03830 if( *pid3 >= 0 ) cgraph_rev = new ParCommGraph( joint_communicator, group_second, group_first, *comp2, *comp1 );
03831
03832 // we should search if we have another pcomm with the same comp ids in the list already
03833 // sort of check existing comm graphs in the map context.appDatas[*pid].pgraph
03834 if( *pid1 >= 0 ) context.appDatas[*pid1].pgraph[*comp2] = cgraph; // the context will be the other comp
03835 if( *pid3 >= 0 ) context.appDatas[*pid3].pgraph[*comp1] = cgraph_rev; // from 2 to 1
03836
03837 // each model has a list of global ids that will need to be sent by gs to rendezvous the other
03838 // model on the joint_communicator
03839 TupleList TLcomp1;
03840 TLcomp1.initialize( 2, 0, 0, 0, 0 ); // to proc, marker
03841 TupleList TLcomp2;
03842 TLcomp2.initialize( 2, 0, 0, 0, 0 ); // to proc, marker
03843
03844 // will push_back a new tuple, if needed
03845 TLcomp1.enableWriteAccess();
03846
03847 // tags of interest are either GLOBAL_DOFS or GLOBAL_ID
03848 Tag gdsTag;
03849
03850 // find the values on first cell
03851 int lenTagType1 = 1;
03852 if( *type == 1 )
03853 {
03854 rval = context.MBI->tag_get_handle( "GLOBAL_DOFS", gdsTag );MB_CHK_ERR( rval );
03855 rval = context.MBI->tag_get_length( gdsTag, lenTagType1 );MB_CHK_ERR( rval ); // usually it is 16
03856 }
03857 Tag tagType2 = context.MBI->globalId_tag();
03858
03859 std::vector< int > valuesComp1;
03860
03861 // populate first tuple
03862 Range ents_of_interest; // will be filled with entities on pid1, that need to be distributed,
03863 // rearranged in split_ranges map
03864 if( *pid1 >= 0 )
03865 {
03866 appData& data1 = context.appDatas[*pid1];
03867 EntityHandle fset1 = data1.file_set;
03868
03869 if( *type == 1 )
03870 {
03871 assert( gdsTag );
03872 rval = context.MBI->get_entities_by_type( fset1, MBQUAD, ents_of_interest );MB_CHK_ERR( rval );
03873 valuesComp1.resize( ents_of_interest.size() * lenTagType1 );
03874 rval = context.MBI->tag_get_data( gdsTag, ents_of_interest, &valuesComp1[0] );MB_CHK_ERR( rval );
03875 }
03876 else if( *type == 2 )
03877 {
03878 rval = context.MBI->get_entities_by_type( fset1, MBVERTEX, ents_of_interest );MB_CHK_ERR( rval );
03879 valuesComp1.resize( ents_of_interest.size() );
03880 rval = context.MBI->tag_get_data( tagType2, ents_of_interest, &valuesComp1[0] );MB_CHK_ERR( rval ); // just global ids
03881 }
03882 else if( *type == 3 ) // for FV meshes, just get the global id of cell
03883 {
03884 rval = context.MBI->get_entities_by_dimension( fset1, 2, ents_of_interest );MB_CHK_ERR( rval );
03885 valuesComp1.resize( ents_of_interest.size() );
03886 rval = context.MBI->tag_get_data( tagType2, ents_of_interest, &valuesComp1[0] );MB_CHK_ERR( rval ); // just global ids
03887 }
03888 else
03889 {
03890 MB_CHK_ERR( MB_FAILURE ); // we know only type 1 or 2 or 3
03891 }
03892 // now fill the tuple list with info and markers
03893 // because we will send only the ids, order and compress the list
03894 std::set< int > uniq( valuesComp1.begin(), valuesComp1.end() );
03895 TLcomp1.resize( uniq.size() );
03896 for( std::set< int >::iterator sit = uniq.begin(); sit != uniq.end(); sit++ )
03897 {
03898 // to proc, marker, element local index, index in el
03899 int marker = *sit;
03900 int to_proc = marker % numProcs;
03901 int n = TLcomp1.get_n();
03902 TLcomp1.vi_wr[2 * n] = to_proc; // send to processor
03903 TLcomp1.vi_wr[2 * n + 1] = marker;
03904 TLcomp1.inc_n();
03905 }
03906 }
03907
03908 ProcConfig pc( joint_communicator ); // proc config does the crystal router
03909 pc.crystal_router()->gs_transfer( 1, TLcomp1,
03910 0 ); // communication towards joint tasks, with markers
03911 // sort by value (key 1)
03912 #ifdef VERBOSE
03913 std::stringstream ff1;
03914 ff1 << "TLcomp1_" << localRank << ".txt";
03915 TLcomp1.print_to_file( ff1.str().c_str() ); // it will append!
03916 #endif
03917 moab::TupleList::buffer sort_buffer;
03918 sort_buffer.buffer_init( TLcomp1.get_n() );
03919 TLcomp1.sort( 1, &sort_buffer );
03920 sort_buffer.reset();
03921 #ifdef VERBOSE
03922 // after sorting
03923 TLcomp1.print_to_file( ff1.str().c_str() ); // it will append!
03924 #endif
03925 // do the same, for the other component, number2, with type2
03926 // start copy
03927 TLcomp2.enableWriteAccess();
03928
03929 moab::TempestOnlineMap* weightMap = NULL; // declare it outside, but it will make sense only for *pid >= 0
03930 // we know that :) (or *pid2 >= 0, it means we are on the coupler PEs, read map exists, and coupler procs exist)
03931 // populate second tuple with ids from read map: we need row_gdofmap and col_gdofmap
03932 std::vector< int > valuesComp2;
03933 if( *pid2 >= 0 ) // we are now on coupler, map side
03934 {
03935 appData& data2 = context.appDatas[*pid2];
03936 TempestMapAppData& tdata = data2.tempestData;
03937 // should be only one map, read from file
03938 assert( tdata.weightMaps.size() == 1 );
03939 // maybe we need to check it is the map we expect
03940 weightMap = tdata.weightMaps.begin()->second;
03941 // std::vector ids_of_interest;
03942 // do a deep copy of the ids of interest: row ids or col ids, target or source direction
03943 if( *direction == 1 )
03944 {
03945 // we are interested in col ids, source
03946 // new method from moab::TempestOnlineMap
03947 rval = weightMap->fill_col_ids( valuesComp2 );MB_CHK_ERR( rval );
03948 }
03949 else if( *direction == 2 )
03950 {
03951 // we are interested in row ids, for target ids
03952 rval = weightMap->fill_row_ids( valuesComp2 );MB_CHK_ERR( rval );
03953 }
03954 //
03955
03956 // now fill the tuple list with info and markers
03957 std::set< int > uniq( valuesComp2.begin(), valuesComp2.end() );
03958 TLcomp2.resize( uniq.size() );
03959 for( std::set< int >::iterator sit = uniq.begin(); sit != uniq.end(); sit++ )
03960 {
03961 // to proc, marker, element local index, index in el
03962 int marker = *sit;
03963 int to_proc = marker % numProcs;
03964 int n = TLcomp2.get_n();
03965 TLcomp2.vi_wr[2 * n] = to_proc; // send to processor
03966 TLcomp2.vi_wr[2 * n + 1] = marker;
03967 TLcomp2.inc_n();
03968 }
03969 }
03970 pc.crystal_router()->gs_transfer( 1, TLcomp2,
03971 0 ); // communication towards joint tasks, with markers
03972 // sort by value (key 1)
03973 // in the rendez-vous approach, markers meet at meet point (rendez-vous) processor marker % nprocs
03974 #ifdef VERBOSE
03975 std::stringstream ff2;
03976 ff2 << "TLcomp2_" << localRank << ".txt";
03977 TLcomp2.print_to_file( ff2.str().c_str() );
03978 #endif
03979 sort_buffer.buffer_reserve( TLcomp2.get_n() );
03980 TLcomp2.sort( 1, &sort_buffer );
03981 sort_buffer.reset();
03982 // end copy
03983 #ifdef VERBOSE
03984 TLcomp2.print_to_file( ff2.str().c_str() );
03985 #endif
03986 // need to send back the info, from the rendezvous point, for each of the values
03987 /* so go over each value, on local process in joint communicator,
03988
03989 now have to send back the info needed for communication;
03990 loop in in sync over both TLComp1 and TLComp2, in local process;
03991 So, build new tuple lists, to send synchronous communication
03992 populate them at the same time, based on marker, that is indexed
03993 */
03994
03995 TupleList TLBackToComp1;
03996 TLBackToComp1.initialize( 3, 0, 0, 0, 0 ); // to proc, marker, from proc on comp2,
03997 TLBackToComp1.enableWriteAccess();
03998
03999 TupleList TLBackToComp2;
04000 TLBackToComp2.initialize( 3, 0, 0, 0, 0 ); // to proc, marker, from proc,
04001 TLBackToComp2.enableWriteAccess();
04002
04003 int n1 = TLcomp1.get_n();
04004 int n2 = TLcomp2.get_n();
04005
04006 int indexInTLComp1 = 0;
04007 int indexInTLComp2 = 0; // advance both, according to the marker
04008 if( n1 > 0 && n2 > 0 )
04009 {
04010
04011 while( indexInTLComp1 < n1 && indexInTLComp2 < n2 ) // if any is over, we are done
04012 {
04013 int currentValue1 = TLcomp1.vi_rd[2 * indexInTLComp1 + 1];
04014 int currentValue2 = TLcomp2.vi_rd[2 * indexInTLComp2 + 1];
04015 if( currentValue1 < currentValue2 )
04016 {
04017 // we have a big problem; basically, we are saying that
04018 // dof currentValue is on one model and not on the other
04019 // std::cout << " currentValue1:" << currentValue1 << " missing in comp2" << "\n";
04020 indexInTLComp1++;
04021 continue;
04022 }
04023 if( currentValue1 > currentValue2 )
04024 {
04025 // std::cout << " currentValue2:" << currentValue2 << " missing in comp1" << "\n";
04026 indexInTLComp2++;
04027 continue;
04028 }
04029 int size1 = 1;
04030 int size2 = 1;
04031 while( indexInTLComp1 + size1 < n1 && currentValue1 == TLcomp1.vi_rd[2 * ( indexInTLComp1 + size1 ) + 1] )
04032 size1++;
04033 while( indexInTLComp2 + size2 < n2 && currentValue2 == TLcomp2.vi_rd[2 * ( indexInTLComp2 + size2 ) + 1] )
04034 size2++;
04035 // must be found in both lists, find the start and end indices
04036 for( int i1 = 0; i1 < size1; i1++ )
04037 {
04038 for( int i2 = 0; i2 < size2; i2++ )
04039 {
04040 // send the info back to components
04041 int n = TLBackToComp1.get_n();
04042 TLBackToComp1.reserve();
04043 TLBackToComp1.vi_wr[3 * n] =
04044 TLcomp1.vi_rd[2 * ( indexInTLComp1 + i1 )]; // send back to the proc marker
04045 // came from, info from comp2
04046 TLBackToComp1.vi_wr[3 * n + 1] = currentValue1; // initial value (resend?)
04047 TLBackToComp1.vi_wr[3 * n + 2] = TLcomp2.vi_rd[2 * ( indexInTLComp2 + i2 )]; // from proc on comp2
04048 n = TLBackToComp2.get_n();
04049 TLBackToComp2.reserve();
04050 TLBackToComp2.vi_wr[3 * n] =
04051 TLcomp2.vi_rd[2 * ( indexInTLComp2 + i2 )]; // send back info to original
04052 TLBackToComp2.vi_wr[3 * n + 1] = currentValue1; // initial value (resend?)
04053 TLBackToComp2.vi_wr[3 * n + 2] = TLcomp1.vi_rd[2 * ( indexInTLComp1 + i1 )]; // from proc on comp1
04054 // what if there are repeated markers in TLcomp2? increase just index2
04055 }
04056 }
04057 indexInTLComp1 += size1;
04058 indexInTLComp2 += size2;
04059 }
04060 }
04061 pc.crystal_router()->gs_transfer( 1, TLBackToComp1, 0 ); // communication towards original tasks, with info about
04062 pc.crystal_router()->gs_transfer( 1, TLBackToComp2, 0 );
04063
04064 TupleList TLv; // vertices
04065 TupleList TLc; // cells if needed (not type 2)
04066
04067 if( *pid1 >= 0 )
04068 {
04069 // we are on original comp 1 tasks
04070 // before ordering
04071 // now for each value in TLBackToComp1.vi_rd[3*i+1], on current proc, we know the
04072 // processors it communicates with
04073 #ifdef VERBOSE
04074 std::stringstream f1;
04075 f1 << "TLBack1_" << localRank << ".txt";
04076 TLBackToComp1.print_to_file( f1.str().c_str() );
04077 #endif
04078 // so we are now on pid1, we know now each marker were it has to go
04079 // add a new method to ParCommGraph, to set up the split_ranges and involved_IDs_map
04080 rval = cgraph->set_split_ranges( *comp1, TLBackToComp1, valuesComp1, lenTagType1, ents_of_interest, *type );MB_CHK_ERR( rval );
04081 // we can just send vertices and elements, with crystal routers;
04082 // on the receiving end, make sure they are not duplicated, by looking at the global id
04083 // if *type is 1, also send global_dofs tag in the element tuple
04084 rval = cgraph->form_tuples_to_migrate_mesh( context.MBI, TLv, TLc, *type, lenTagType1 );MB_CHK_ERR( rval );
04085 }
04086 else
04087 {
04088 TLv.initialize( 2, 0, 0, 3, 0 ); // no vertices here, for sure
04089 TLv.enableWriteAccess(); // to be able to receive stuff, even if nothing is here yet, on this task
04090 if( *type != 2 ) // for point cloud, we do not need to initialize TLc (for cells)
04091 {
04092 // we still need to initialize the tuples with the right size, as in form_tuples_to_migrate_mesh
04093 int size_tuple = 2 + ( ( *type != 1 ) ? 0 : lenTagType1 ) + 1 +
04094 10; // 10 is the max number of vertices in cell; kind of arbitrary
04095 TLc.initialize( size_tuple, 0, 0, 0, 0 );
04096 TLc.enableWriteAccess();
04097 }
04098 }
04099 pc.crystal_router()->gs_transfer( 1, TLv, 0 ); // communication towards coupler tasks, with mesh vertices
04100 if( *type != 2 ) pc.crystal_router()->gs_transfer( 1, TLc, 0 ); // those are cells
04101
04102 if( *pid3 >= 0 ) // will receive the mesh, on coupler pes!
04103 {
04104 appData& data3 = context.appDatas[*pid3];
04105 EntityHandle fset3 = data3.file_set;
04106 Range primary_ents3; // vertices for type 2, cells of dim 2 for type 1 or 3
04107 std::vector< int > values_entities; // will be the size of primary_ents3 * lenTagType1
04108 rval = cgraph_rev->form_mesh_from_tuples( context.MBI, TLv, TLc, *type, lenTagType1, fset3, primary_ents3,
04109 values_entities );MB_CHK_ERR( rval );
04110 iMOAB_UpdateMeshInfo( pid3 );
04111 int ndofPerEl = 1;
04112 if( 1 == *type ) ndofPerEl = (int)( sqrt( lenTagType1 ) );
04113 // because we are on the coupler, we know that the read map pid2 exists
04114 assert( *pid2 >= 0 );
04115 appData& dataIntx = context.appDatas[*pid2];
04116 TempestMapAppData& tdata = dataIntx.tempestData;
04117
04118 // if we are on source coverage, direction 1, we can set covering mesh, covering cells
04119 if( 1 == *direction )
04120 {
04121 tdata.pid_src = pid3;
04122 tdata.remapper->SetMeshSet( Remapper::CoveringMesh, fset3, primary_ents3 );
04123 weightMap->SetSourceNDofsPerElement( ndofPerEl );
04124 weightMap->set_col_dc_dofs( values_entities ); // will set col_dtoc_dofmap
04125 }
04126 // if we are on target, we can set the target cells
04127 else
04128 {
04129 tdata.pid_dest = pid3;
04130 tdata.remapper->SetMeshSet( Remapper::TargetMesh, fset3, primary_ents3 );
04131 weightMap->SetDestinationNDofsPerElement( ndofPerEl );
04132 weightMap->set_row_dc_dofs( values_entities ); // will set row_dtoc_dofmap
04133 }
04134 }
04135
04136 return moab::MB_SUCCESS;
04137 }
04138
04139 #endif // #ifdef MOAB_HAVE_MPI
04140
04141 #endif // #ifdef MOAB_HAVE_NETCDF
04142
04143 #define USE_API
04144 static ErrCode ComputeSphereRadius( iMOAB_AppID pid, double* radius )
04145 {
04146 ErrorCode rval;
04147 moab::CartVect pos;
04148
04149 Range& verts = context.appDatas[*pid].all_verts;
04150 moab::EntityHandle firstVertex = ( verts[0] );
04151
04152 // coordinate data
04153 rval = context.MBI->get_coords( &( firstVertex ), 1, (double*)&( pos[0] ) );MB_CHK_ERR( rval );
04154
04155 // compute the distance from origin
04156 // TODO: we could do this in a loop to verify if the pid represents a spherical mesh
04157 *radius = pos.length();
04158 return moab::MB_SUCCESS;
04159 }
04160
04161 ErrCode iMOAB_ComputeMeshIntersectionOnSphere( iMOAB_AppID pid_src, iMOAB_AppID pid_tgt, iMOAB_AppID pid_intx )
04162 {
04163 ErrorCode rval;
04164 ErrCode ierr;
04165 bool validate = true;
04166
04167 double radius_source = 1.0;
04168 double radius_target = 1.0;
04169
04170 const double epsrel = ReferenceTolerance; // ReferenceTolerance is defined in Defines.h in tempestremap source ;
04171 const double boxeps = 1.e-6;
04172
04173 // Get the source and target data and pcomm objects
04174 appData& data_src = context.appDatas[*pid_src];
04175 appData& data_tgt = context.appDatas[*pid_tgt];
04176 appData& data_intx = context.appDatas[*pid_intx];
04177 #ifdef MOAB_HAVE_MPI
04178 ParallelComm* pco_intx = context.pcomms[*pid_intx];
04179 #endif
04180
04181 // Mesh intersection has already been computed; Return early.
04182 TempestMapAppData& tdata = data_intx.tempestData;
04183 if( tdata.remapper != NULL ) return moab::MB_SUCCESS; // nothing to do
04184
04185 bool is_parallel = false, is_root = true;
04186 int rank = 0;
04187 #ifdef MOAB_HAVE_MPI
04188 if( pco_intx )
04189 {
04190 rank = pco_intx->rank();
04191 is_parallel = ( pco_intx->size() > 1 );
04192 is_root = ( rank == 0 );
04193 rval = pco_intx->check_all_shared_handles();MB_CHK_ERR( rval );
04194 }
04195 #endif
04196
04197 moab::DebugOutput outputFormatter( std::cout, rank, 0 );
04198 outputFormatter.set_prefix( "[iMOAB_ComputeMeshIntersectionOnSphere]: " );
04199
04200 ierr = iMOAB_UpdateMeshInfo( pid_src );MB_CHK_ERR( ierr );
04201 ierr = iMOAB_UpdateMeshInfo( pid_tgt );MB_CHK_ERR( ierr );
04202
04203 // Rescale the radius of both to compute the intersection
04204 ComputeSphereRadius( pid_src, &radius_source );
04205 ComputeSphereRadius( pid_tgt, &radius_target );
04206 #ifdef VERBOSE
04207 if( is_root )
04208 outputFormatter.printf( 0, "Radius of spheres: source = %12.14f, and target = %12.14f\n", radius_source,
04209 radius_target );
04210 #endif
04211
04212 /* Let make sure that the radius match for source and target meshes. If not, rescale now and
04213 * unscale later. */
04214 double defaultradius = 1.0;
04215 if( fabs( radius_source - radius_target ) > 1e-10 )
04216 { /* the radii are different */
04217 rval = IntxUtils::ScaleToRadius( context.MBI, data_src.file_set, defaultradius );MB_CHK_ERR( rval );
04218 rval = IntxUtils::ScaleToRadius( context.MBI, data_tgt.file_set, defaultradius );MB_CHK_ERR( rval );
04219 }
04220
04221 // Default area_method = lHuiller; Options: Girard, GaussQuadrature (if TR is available)
04222 #ifdef MOAB_HAVE_TEMPESTREMAP
04223 IntxAreaUtils areaAdaptor( IntxAreaUtils::GaussQuadrature );
04224 #else
04225 IntxAreaUtils areaAdaptor( IntxAreaUtils::lHuiller );
04226 #endif
04227
04228 // print verbosely about the problem setting
04229 bool use_kdtree_search = false;
04230 double srctgt_areas[2], srctgt_areas_glb[2];
04231 {
04232 moab::Range rintxverts, rintxelems;
04233 rval = context.MBI->get_entities_by_dimension( data_src.file_set, 0, rintxverts );MB_CHK_ERR( rval );
04234 rval = context.MBI->get_entities_by_dimension( data_src.file_set, data_src.dimension, rintxelems );MB_CHK_ERR( rval );
04235 rval = IntxUtils::fix_degenerate_quads( context.MBI, data_src.file_set );MB_CHK_ERR( rval );
04236 rval =
04237 areaAdaptor.positive_orientation( context.MBI, data_src.file_set, defaultradius /*radius_source*/, rank );MB_CHK_ERR( rval );
04238 srctgt_areas[0] = areaAdaptor.area_on_sphere( context.MBI, data_src.file_set, defaultradius /*radius_source*/ );
04239 #ifdef VERBOSE
04240 if( is_root )
04241 outputFormatter.printf( 0, "The red set contains %d vertices and %d elements \n", rintxverts.size(),
04242 rintxelems.size() );
04243 #endif
04244
04245 moab::Range bintxverts, bintxelems;
04246 rval = context.MBI->get_entities_by_dimension( data_tgt.file_set, 0, bintxverts );MB_CHK_ERR( rval );
04247 rval = context.MBI->get_entities_by_dimension( data_tgt.file_set, data_tgt.dimension, bintxelems );MB_CHK_ERR( rval );
04248 rval = IntxUtils::fix_degenerate_quads( context.MBI, data_tgt.file_set );MB_CHK_ERR( rval );
04249 rval =
04250 areaAdaptor.positive_orientation( context.MBI, data_tgt.file_set, defaultradius /*radius_target*/, rank );MB_CHK_ERR( rval );
04251 srctgt_areas[1] = areaAdaptor.area_on_sphere( context.MBI, data_tgt.file_set, defaultradius /*radius_target*/ );
04252 #ifdef VERBOSE
04253 if( is_root )
04254 outputFormatter.printf( 0, "The blue set contains %d vertices and %d elements \n", bintxverts.size(),
04255 bintxelems.size() );
04256 #endif
04257 #ifdef MOAB_HAVE_MPI
04258 MPI_Allreduce( &srctgt_areas[0], &srctgt_areas_glb[0], 2, MPI_DOUBLE, MPI_SUM, pco_intx->comm() );
04259 #else
04260 srctgt_areas_glb[0] = srctgt_areas[0];
04261 srctgt_areas_glb[1] = srctgt_areas[1];
04262 #endif
04263 use_kdtree_search = ( srctgt_areas_glb[0] < srctgt_areas_glb[1] );
04264 }
04265
04266 data_intx.dimension = data_tgt.dimension;
04267 // set the context for the source and destination applications
04268 tdata.pid_src = pid_src;
04269 tdata.pid_dest = pid_tgt;
04270
04271 // Now allocate and initialize the remapper object
04272 #ifdef MOAB_HAVE_MPI
04273 tdata.remapper = new moab::TempestRemapper( context.MBI, pco_intx );
04274 #else
04275 tdata.remapper = new moab::TempestRemapper( context.MBI );
04276 #endif
04277 tdata.remapper->meshValidate = true;
04278 tdata.remapper->constructEdgeMap = true;
04279
04280 tdata.remapper->set_intx_name( data_intx.name );
04281 // Do not create new filesets; Use the sets from our respective applications
04282 tdata.remapper->initialize( false );
04283 tdata.remapper->GetMeshSet( moab::Remapper::SourceMesh ) = data_src.file_set;
04284 tdata.remapper->GetMeshSet( moab::Remapper::TargetMesh ) = data_tgt.file_set;
04285 tdata.remapper->GetMeshSet( moab::Remapper::OverlapMesh ) = data_intx.file_set;
04286
04287 rval = tdata.remapper->ConvertMeshToTempest( moab::Remapper::SourceMesh );MB_CHK_ERR( rval );
04288 rval = tdata.remapper->ConvertMeshToTempest( moab::Remapper::TargetMesh );MB_CHK_ERR( rval );
04289
04290 #ifdef VERBOSE_ZOLTAN_TIMINGS
04291 #ifdef MOAB_HAVE_MPI
04292 double t1;
04293 if( is_root ) t1 = MPI_Wtime();
04294 #endif
04295 #endif
04296 // First, compute the covering source set.
04297 rval = tdata.remapper->ConstructCoveringSet( epsrel, 1.0, 1.0, boxeps, false );MB_CHK_ERR( rval );
04298 #ifdef VERBOSE_ZOLTAN_TIMINGS
04299 #ifdef MOAB_HAVE_MPI
04300 double t2;
04301 if( is_root )
04302 {
04303 t2 = MPI_Wtime();
04304 std::cout << "[LOG] Time: coverage mesh:" << t2 - t1 << "\n";
04305 }
04306 #endif
04307 #endif
04308 // Next, compute intersections with MOAB.
04309 rval = tdata.remapper->ComputeOverlapMesh( use_kdtree_search, false );MB_CHK_ERR( rval );
04310
04311 // Mapping computation done
04312 if( validate )
04313 {
04314 double local_area,
04315 global_areas[3]; // Array for Initial area, and through Method 1 and Method 2
04316 local_area = areaAdaptor.area_on_sphere( context.MBI, data_intx.file_set, radius_source, rank );
04317
04318 global_areas[0] = srctgt_areas_glb[0];
04319 global_areas[1] = srctgt_areas_glb[1];
04320
04321 #ifdef MOAB_HAVE_MPI
04322 if( is_parallel )
04323 {
04324 MPI_Reduce( &local_area, &global_areas[2], 1, MPI_DOUBLE, MPI_SUM, 0, pco_intx->comm() );
04325 }
04326 else
04327 {
04328 global_areas[2] = local_area;
04329 }
04330 #else
04331 global_areas[2] = local_area;
04332 #endif
04333 if( is_root )
04334 {
04335 outputFormatter.printf( 0,
04336 "initial area: source mesh = %12.14f, target mesh = %12.14f, "
04337 "overlap mesh = %12.14f\n",
04338 global_areas[0], global_areas[1], global_areas[2] );
04339 outputFormatter.printf( 0, " relative error w.r.t source = %12.14e, and target = %12.14e\n",
04340 fabs( global_areas[0] - global_areas[2] ) / global_areas[0],
04341 fabs( global_areas[1] - global_areas[2] ) / global_areas[1] );
04342 }
04343 }
04344
04345 return moab::MB_SUCCESS;
04346 }
04347
04348 ErrCode iMOAB_ComputePointDoFIntersection( iMOAB_AppID pid_src, iMOAB_AppID pid_tgt, iMOAB_AppID pid_intx )
04349 {
04350 ErrorCode rval;
04351 ErrCode ierr;
04352
04353 double radius_source = 1.0;
04354 double radius_target = 1.0;
04355
04356 const double epsrel = ReferenceTolerance; // ReferenceTolerance is defined in Defines.h in tempestremap source ;
04357 const double boxeps = 1.e-8;
04358
04359 // Get the source and target data and pcomm objects
04360 appData& data_src = context.appDatas[*pid_src];
04361 appData& data_tgt = context.appDatas[*pid_tgt];
04362 appData& data_intx = context.appDatas[*pid_intx];
04363 int rank = 0;
04364 #ifdef MOAB_HAVE_MPI
04365 ParallelComm* pco_intx = context.pcomms[*pid_intx];
04366 rank = pco_intx->rank();
04367 #endif
04368
04369 // Mesh intersection has already been computed; Return early.
04370 TempestMapAppData& tdata = data_intx.tempestData;
04371 if( tdata.remapper != NULL ) return moab::MB_SUCCESS; // nothing to do
04372
04373 #ifdef MOAB_HAVE_MPI
04374 if( pco_intx )
04375 {
04376 rval = pco_intx->check_all_shared_handles();MB_CHK_ERR( rval );
04377 }
04378 #endif
04379
04380 ierr = iMOAB_UpdateMeshInfo( pid_src );MB_CHK_ERR( ierr );
04381 ierr = iMOAB_UpdateMeshInfo( pid_tgt );MB_CHK_ERR( ierr );
04382
04383 // Rescale the radius of both to compute the intersection
04384 ComputeSphereRadius( pid_src, &radius_source );
04385 ComputeSphereRadius( pid_tgt, &radius_target );
04386
04387 IntxAreaUtils areaAdaptor;
04388 // print verbosely about the problem setting
04389 {
04390 moab::Range rintxverts, rintxelems;
04391 rval = context.MBI->get_entities_by_dimension( data_src.file_set, 0, rintxverts );MB_CHK_ERR( rval );
04392 rval = context.MBI->get_entities_by_dimension( data_src.file_set, 2, rintxelems );MB_CHK_ERR( rval );
04393 rval = IntxUtils::fix_degenerate_quads( context.MBI, data_src.file_set );MB_CHK_ERR( rval );
04394 rval = areaAdaptor.positive_orientation( context.MBI, data_src.file_set, radius_source, rank );MB_CHK_ERR( rval );
04395 #ifdef VERBOSE
04396 std::cout << "The red set contains " << rintxverts.size() << " vertices and " << rintxelems.size()
04397 << " elements \n";
04398 #endif
04399
04400 moab::Range bintxverts, bintxelems;
04401 rval = context.MBI->get_entities_by_dimension( data_tgt.file_set, 0, bintxverts );MB_CHK_ERR( rval );
04402 rval = context.MBI->get_entities_by_dimension( data_tgt.file_set, 2, bintxelems );MB_CHK_ERR( rval );
04403 rval = IntxUtils::fix_degenerate_quads( context.MBI, data_tgt.file_set );MB_CHK_ERR( rval );
04404 rval = areaAdaptor.positive_orientation( context.MBI, data_tgt.file_set, radius_target, rank );MB_CHK_ERR( rval );
04405 #ifdef VERBOSE
04406 std::cout << "The blue set contains " << bintxverts.size() << " vertices and " << bintxelems.size()
04407 << " elements \n";
04408 #endif
04409 }
04410
04411 data_intx.dimension = data_tgt.dimension;
04412 // set the context for the source and destination applications
04413 // set the context for the source and destination applications
04414 tdata.pid_src = pid_src;
04415 tdata.pid_dest = pid_tgt;
04416 data_intx.point_cloud = ( data_src.point_cloud || data_tgt.point_cloud );
04417 assert( data_intx.point_cloud == true );
04418
04419 // Now allocate and initialize the remapper object
04420 #ifdef MOAB_HAVE_MPI
04421 tdata.remapper = new moab::TempestRemapper( context.MBI, pco_intx );
04422 #else
04423 tdata.remapper = new moab::TempestRemapper( context.MBI );
04424 #endif
04425 tdata.remapper->meshValidate = true;
04426 tdata.remapper->constructEdgeMap = true;
04427
04428 // Do not create new filesets; Use the sets from our respective applications
04429 tdata.remapper->initialize( false );
04430 tdata.remapper->GetMeshSet( moab::Remapper::SourceMesh ) = data_src.file_set;
04431 tdata.remapper->GetMeshSet( moab::Remapper::TargetMesh ) = data_tgt.file_set;
04432 tdata.remapper->GetMeshSet( moab::Remapper::OverlapMesh ) = data_intx.file_set;
04433
04434 /* Let make sure that the radius match for source and target meshes. If not, rescale now and
04435 * unscale later. */
04436 if( fabs( radius_source - radius_target ) > 1e-10 )
04437 { /* the radii are different */
04438 rval = IntxUtils::ScaleToRadius( context.MBI, data_src.file_set, 1.0 );MB_CHK_ERR( rval );
04439 rval = IntxUtils::ScaleToRadius( context.MBI, data_tgt.file_set, 1.0 );MB_CHK_ERR( rval );
04440 }
04441
04442 rval = tdata.remapper->ConvertMeshToTempest( moab::Remapper::SourceMesh );MB_CHK_ERR( rval );
04443 rval = tdata.remapper->ConvertMeshToTempest( moab::Remapper::TargetMesh );MB_CHK_ERR( rval );
04444
04445 // First, compute the covering source set.
04446 rval = tdata.remapper->ConstructCoveringSet( epsrel, 1.0, 1.0, boxeps, false );MB_CHK_ERR( rval );
04447
04448 #ifdef MOAB_HAVE_MPI
04449 /* VSM: This context should be set on the data_src but it would overwrite the source
04450 covering set context in case it is coupled to another APP as well.
04451 This needs a redesign. */
04452 // data_intx.covering_set = tdata.remapper->GetCoveringSet();
04453 // data_src.covering_set = tdata.remapper->GetCoveringSet();
04454 #endif
04455
04456 // Now let us re-convert the MOAB mesh back to Tempest representation
04457 rval = tdata.remapper->ComputeGlobalLocalMaps();MB_CHK_ERR( rval );
04458
04459 return moab::MB_SUCCESS;
04460 }
04461
04462 ErrCode iMOAB_ComputeScalarProjectionWeights(
04463 iMOAB_AppID pid_intx,
04464 const iMOAB_String solution_weights_identifier, /* "scalar", "flux", "custom" */
04465 const iMOAB_String disc_method_source,
04466 int* disc_order_source,
04467 const iMOAB_String disc_method_target,
04468 int* disc_order_target,
04469 int* fNoBubble,
04470 int* fMonotoneTypeID,
04471 int* fVolumetric,
04472 int* fInverseDistanceMap,
04473 int* fNoConservation,
04474 int* fValidate,
04475 const iMOAB_String source_solution_tag_dof_name,
04476 const iMOAB_String target_solution_tag_dof_name )
04477 {
04478 moab::ErrorCode rval;
04479
04480 assert( disc_order_source && disc_order_target && *disc_order_source > 0 && *disc_order_target > 0 );
04481 assert( solution_weights_identifier && strlen( solution_weights_identifier ) );
04482 assert( disc_method_source && strlen( disc_method_source ) );
04483 assert( disc_method_target && strlen( disc_method_target ) );
04484 assert( source_solution_tag_dof_name && strlen( source_solution_tag_dof_name ) );
04485 assert( target_solution_tag_dof_name && strlen( target_solution_tag_dof_name ) );
04486
04487 // Get the source and target data and pcomm objects
04488 appData& data_intx = context.appDatas[*pid_intx];
04489 TempestMapAppData& tdata = data_intx.tempestData;
04490
04491 // Setup computation of weights
04492 // Set the context for the remapping weights computation
04493 tdata.weightMaps[std::string( solution_weights_identifier )] = new moab::TempestOnlineMap( tdata.remapper );
04494
04495 // Call to generate the remap weights with the tempest meshes
04496 moab::TempestOnlineMap* weightMap = tdata.weightMaps[std::string( solution_weights_identifier )];
04497 assert( weightMap != NULL );
04498
04499 GenerateOfflineMapAlgorithmOptions mapOptions;
04500 mapOptions.nPin = *disc_order_source;
04501 mapOptions.nPout = *disc_order_target;
04502 mapOptions.fSourceConcave = false;
04503 mapOptions.fTargetConcave = false;
04504
04505 mapOptions.strMethod = "";
04506 if( fMonotoneTypeID )
04507 {
04508 switch( *fMonotoneTypeID )
04509 {
04510 case 0:
04511 mapOptions.fMonotone = false;
04512 break;
04513 case 3:
04514 mapOptions.strMethod += "mono3;";
04515 break;
04516 case 2:
04517 mapOptions.strMethod += "mono2;";
04518 break;
04519 default:
04520 mapOptions.fMonotone = true;
04521 }
04522 }
04523 else
04524 mapOptions.fMonotone = false;
04525
04526 mapOptions.fNoBubble = ( fNoBubble ? *fNoBubble : false );
04527 mapOptions.fNoConservation = ( fNoConservation ? *fNoConservation > 0 : false );
04528 mapOptions.fNoCorrectAreas = false;
04529 mapOptions.fNoCheck = !( fValidate ? *fValidate : true );
04530 if( fVolumetric && *fVolumetric ) mapOptions.strMethod += "volumetric;";
04531 if( fInverseDistanceMap && *fInverseDistanceMap ) mapOptions.strMethod += "invdist;";
04532
04533 // Now let us compute the local-global mapping and store it in the context
04534 // We need this mapping when computing matvec products and to do reductions in parallel
04535 // Additionally, the call below will also compute weights with TempestRemap
04536 rval = weightMap->GenerateRemappingWeights(
04537 std::string( disc_method_source ), // const std::string& strInputType
04538 std::string( disc_method_target ), // const std::string& strOutputType
04539 mapOptions, // GenerateOfflineMapAlgorithmOptions& mapOptions
04540 std::string( source_solution_tag_dof_name ), // const std::string& srcDofTagName = "GLOBAL_ID"
04541 std::string( target_solution_tag_dof_name ) // const std::string& tgtDofTagName = "GLOBAL_ID"
04542 );MB_CHK_ERR( rval );
04543
04544 return moab::MB_SUCCESS;
04545 }
04546
04547 ErrCode iMOAB_ApplyScalarProjectionWeights(
04548 iMOAB_AppID pid_intersection,
04549 const iMOAB_String solution_weights_identifier, /* "scalar", "flux", "custom" */
04550 const iMOAB_String source_solution_tag_name,
04551 const iMOAB_String target_solution_tag_name )
04552 {
04553 assert( solution_weights_identifier && strlen( solution_weights_identifier ) );
04554 assert( source_solution_tag_name && strlen( source_solution_tag_name ) );
04555 assert( target_solution_tag_name && strlen( target_solution_tag_name ) );
04556
04557 moab::ErrorCode rval;
04558
04559 // Get the source and target data and pcomm objects
04560 appData& data_intx = context.appDatas[*pid_intersection];
04561 TempestMapAppData& tdata = data_intx.tempestData;
04562
04563 // Now allocate and initialize the remapper object
04564 moab::TempestRemapper* remapper = tdata.remapper;
04565 moab::TempestOnlineMap* weightMap = tdata.weightMaps[std::string( solution_weights_identifier )];
04566
04567 // we assume that there are separators ";" between the tag names
04568 std::vector< std::string > srcNames;
04569 std::vector< std::string > tgtNames;
04570 std::vector< Tag > srcTagHandles;
04571 std::vector< Tag > tgtTagHandles;
04572 std::string separator( ":" );
04573 std::string src_name( source_solution_tag_name );
04574 std::string tgt_name( target_solution_tag_name );
04575 split_tag_names( src_name, separator, srcNames );
04576 split_tag_names( tgt_name, separator, tgtNames );
04577 if( srcNames.size() != tgtNames.size() )
04578 {
04579 std::cout << " error in parsing source and target tag names. \n";
04580 return moab::MB_FAILURE;
04581 }
04582
04583 for( size_t i = 0; i < srcNames.size(); i++ )
04584 {
04585 Tag tagHandle;
04586 rval = context.MBI->tag_get_handle( srcNames[i].c_str(), tagHandle );
04587 if( MB_SUCCESS != rval || NULL == tagHandle )
04588 {
04589 return moab::MB_FAILURE;
04590 }
04591 srcTagHandles.push_back( tagHandle );
04592 rval = context.MBI->tag_get_handle( tgtNames[i].c_str(), tagHandle );
04593 if( MB_SUCCESS != rval || NULL == tagHandle )
04594 {
04595 return moab::MB_FAILURE;
04596 }
04597 tgtTagHandles.push_back( tagHandle );
04598 }
04599
04600 std::vector< double > solSTagVals;
04601 std::vector< double > solTTagVals;
04602
04603 moab::Range sents, tents;
04604 if( data_intx.point_cloud )
04605 {
04606 appData& data_src = context.appDatas[*tdata.pid_src];
04607 appData& data_tgt = context.appDatas[*tdata.pid_dest];
04608 if( data_src.point_cloud )
04609 {
04610 moab::Range& covSrcEnts = remapper->GetMeshVertices( moab::Remapper::CoveringMesh );
04611 solSTagVals.resize( covSrcEnts.size(), -1.0 );
04612 sents = covSrcEnts;
04613 }
04614 else
04615 {
04616 moab::Range& covSrcEnts = remapper->GetMeshEntities( moab::Remapper::CoveringMesh );
04617 solSTagVals.resize( covSrcEnts.size() * weightMap->GetSourceNDofsPerElement() *
04618 weightMap->GetSourceNDofsPerElement(),
04619 -1.0 );
04620 sents = covSrcEnts;
04621 }
04622 if( data_tgt.point_cloud )
04623 {
04624 moab::Range& tgtEnts = remapper->GetMeshVertices( moab::Remapper::TargetMesh );
04625 solTTagVals.resize( tgtEnts.size(), -1.0 );
04626 tents = tgtEnts;
04627 }
04628 else
04629 {
04630 moab::Range& tgtEnts = remapper->GetMeshEntities( moab::Remapper::TargetMesh );
04631 solTTagVals.resize( tgtEnts.size() * weightMap->GetDestinationNDofsPerElement() *
04632 weightMap->GetDestinationNDofsPerElement(),
04633 -1.0 );
04634 tents = tgtEnts;
04635 }
04636 }
04637 else
04638 {
04639 moab::Range& covSrcEnts = remapper->GetMeshEntities( moab::Remapper::CoveringMesh );
04640 moab::Range& tgtEnts = remapper->GetMeshEntities( moab::Remapper::TargetMesh );
04641 solSTagVals.resize(
04642 covSrcEnts.size() * weightMap->GetSourceNDofsPerElement() * weightMap->GetSourceNDofsPerElement(), -1.0 );
04643 solTTagVals.resize( tgtEnts.size() * weightMap->GetDestinationNDofsPerElement() *
04644 weightMap->GetDestinationNDofsPerElement(),
04645 -1.0 );
04646
04647 sents = covSrcEnts;
04648 tents = tgtEnts;
04649 }
04650
04651 for( size_t i = 0; i < srcTagHandles.size(); i++ )
04652 {
04653 // The tag data is np*np*n_el_src
04654 Tag ssolnTag = srcTagHandles[i];
04655 Tag tsolnTag = tgtTagHandles[i];
04656 rval = context.MBI->tag_get_data( ssolnTag, sents, &solSTagVals[0] );MB_CHK_ERR( rval );
04657
04658 // Compute the application of weights on the suorce solution data and store it in the
04659 // destination solution vector data Optionally, can also perform the transpose application
04660 // of the weight matrix. Set the 3rd argument to true if this is needed
04661 rval = weightMap->ApplyWeights( solSTagVals, solTTagVals, false );MB_CHK_ERR( rval );
04662
04663 // The tag data is np*np*n_el_dest
04664 rval = context.MBI->tag_set_data( tsolnTag, tents, &solTTagVals[0] );MB_CHK_ERR( rval );
04665 }
04666
04667 // #define VERBOSE
04668 #ifdef VERBOSE
04669 ParallelComm* pco_intx = context.pcomms[*pid_intersection];
04670
04671 int ivar = 0;
04672 {
04673 Tag ssolnTag = srcTagHandles[ivar];
04674 std::stringstream sstr;
04675 sstr << "covsrcTagData_" << *pid_intersection << "_" << ivar << "_" << pco_intx->rank() << ".txt";
04676 std::ofstream output_file( sstr.str().c_str() );
04677 for( unsigned i = 0; i < sents.size(); ++i )
04678 {
04679 EntityHandle elem = sents[i];
04680 std::vector< double > locsolSTagVals( 16 );
04681 rval = context.MBI->tag_get_data( ssolnTag, &elem, 1, &locsolSTagVals[0] );MB_CHK_ERR( rval );
04682 output_file << "\n" << remapper->GetGlobalID( Remapper::CoveringMesh, i ) << "-- \n\t";
04683 for( unsigned j = 0; j < 16; ++j )
04684 output_file << locsolSTagVals[j] << " ";
04685 }
04686 output_file.flush(); // required here
04687 output_file.close();
04688 }
04689 {
04690 std::stringstream sstr;
04691 sstr << "outputSrcDest_" << *pid_intersection << "_" << ivar << "_" << pco_intx->rank() << ".h5m";
04692 EntityHandle sets[2] = {context.appDatas[*tdata.pid_src].file_set, context.appDatas[*tdata.pid_dest].file_set};
04693 rval = context.MBI->write_file( sstr.str().c_str(), NULL, "", sets, 2 );MB_CHK_ERR( rval );
04694 }
04695 {
04696 std::stringstream sstr;
04697 sstr << "outputCovSrcDest_" << *pid_intersection << "_" << ivar << "_" << pco_intx->rank() << ".h5m";
04698 // EntityHandle sets[2] = {data_intx.file_set, data_intx.covering_set};
04699 EntityHandle covering_set = remapper->GetCoveringSet();
04700 EntityHandle sets[2] = {covering_set, context.appDatas[*tdata.pid_dest].file_set};
04701 rval = context.MBI->write_file( sstr.str().c_str(), NULL, "", sets, 2 );MB_CHK_ERR( rval );
04702 }
04703 {
04704 std::stringstream sstr;
04705 sstr << "covMesh_" << *pid_intersection << "_" << pco_intx->rank() << ".vtk";
04706 // EntityHandle sets[2] = {data_intx.file_set, data_intx.covering_set};
04707 EntityHandle covering_set = remapper->GetCoveringSet();
04708 rval = context.MBI->write_file( sstr.str().c_str(), NULL, "", &covering_set, 1 );MB_CHK_ERR( rval );
04709 }
04710 {
04711 std::stringstream sstr;
04712 sstr << "tgtMesh_" << *pid_intersection << "_" << pco_intx->rank() << ".vtk";
04713 // EntityHandle sets[2] = {data_intx.file_set, data_intx.covering_set};
04714 EntityHandle target_set = remapper->GetMeshSet( Remapper::TargetMesh );
04715 rval = context.MBI->write_file( sstr.str().c_str(), NULL, "", &target_set, 1 );MB_CHK_ERR( rval );
04716 }
04717 {
04718 std::stringstream sstr;
04719 sstr << "colvector_" << *pid_intersection << "_" << ivar << "_" << pco_intx->rank() << ".txt";
04720 std::ofstream output_file( sstr.str().c_str() );
04721 for( unsigned i = 0; i < solSTagVals.size(); ++i )
04722 output_file << i << " " << weightMap->col_dofmap[i] << " " << weightMap->col_gdofmap[i] << " "
04723 << solSTagVals[i] << "\n";
04724 output_file.flush(); // required here
04725 output_file.close();
04726 }
04727 #endif
04728 // #undef VERBOSE
04729
04730 return moab::MB_SUCCESS;
04731 }
04732
04733 #endif // MOAB_HAVE_TEMPESTREMAP
04734
04735 #ifdef __cplusplus
04736 }
04737 #endif