$extrastylesheet
nemesis_io.C
Go to the documentation of this file.
00001 // The libMesh Finite Element Library.
00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
00003 
00004 // This library is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public
00006 // License as published by the Free Software Foundation; either
00007 // version 2.1 of the License, or (at your option) any later version.
00008 
00009 // This library is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // Lesser General Public License for more details.
00013 
00014 // You should have received a copy of the GNU Lesser General Public
00015 // License along with this library; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 
00019 // C++ includes
00020 #include <numeric> // std::accumulate
00021 
00022 // LibMesh includes
00023 #include "libmesh/elem.h"
00024 #include "libmesh/exodusII_io.h"
00025 #include "libmesh/libmesh_logging.h"
00026 #include "libmesh/nemesis_io.h"
00027 #include "libmesh/nemesis_io_helper.h"
00028 #include "libmesh/node.h"
00029 #include "libmesh/parallel_mesh.h"
00030 #include "libmesh/parallel.h"
00031 #include "libmesh/utility.h" // is_sorted, deallocate
00032 #include "libmesh/boundary_info.h"
00033 #include "libmesh/mesh_communication.h"
00034 
00035 namespace libMesh
00036 {
00037 
00038 
00039 //-----------------------------------------------
00040 // anonymous namespace for implementation details
00041 namespace {
00042 struct CompareGlobalIdxMappings
00043 {
00044   // strict weak ordering for a.first -> a.second mapping.  since we can only map to one
00045   // value only order the first entry
00046   bool operator()(const std::pair<unsigned int, unsigned int> &a,
00047                   const std::pair<unsigned int, unsigned int> &b) const
00048   { return a.first < b.first; }
00049 
00050   // strict weak ordering for a.first -> a.second mapping.  lookups will
00051   // be in terms of a single integer, which is why we need this method.
00052   bool operator()(const std::pair<unsigned int, unsigned int> &a,
00053                   const unsigned int b) const
00054   { return a.first < b; }
00055 };
00056 
00057 // Nemesis & ExodusII use int for all integer values, even the ones which
00058 // should never be negative.  we like to use unsigned as a force of habit,
00059 // this trivial little method saves some typing & also makes sure something
00060 // is not horribly wrong.
00061 template <typename T>
00062 inline unsigned int to_uint ( const T &t )
00063 {
00064   libmesh_assert_equal_to (t, static_cast<T>(static_cast<unsigned int>(t)));
00065 
00066   return static_cast<unsigned int>(t);
00067 }
00068 
00069 // test equality for a.first -> a.second mapping.  since we can only map to one
00070 // value only test the first entry
00071 inline bool global_idx_mapping_equality (const std::pair<unsigned int, unsigned int> &a,
00072                                          const std::pair<unsigned int, unsigned int> &b)
00073 { return a.first == b.first; }
00074 }
00075 
00076 
00077 
00078 // ------------------------------------------------------------
00079 // Nemesis_IO class members
00080 Nemesis_IO::Nemesis_IO (MeshBase& mesh,
00081 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
00082                         bool single_precision
00083 #else
00084                         bool
00085 #endif
00086                         ) :
00087   MeshInput<MeshBase> (mesh, /*is_parallel_format=*/true),
00088   MeshOutput<MeshBase> (mesh, /*is_parallel_format=*/true),
00089   ParallelObject (mesh),
00090 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
00091   nemhelper(new Nemesis_IO_Helper(*this, false, single_precision)),
00092 #endif
00093   _timestep(1),
00094   _verbose (false),
00095   _append(false)
00096 {
00097 }
00098 
00099 
00100 Nemesis_IO::~Nemesis_IO ()
00101 {
00102 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
00103 
00104   delete nemhelper;
00105 #endif
00106 }
00107 
00108 
00109 
00110 void Nemesis_IO::verbose (bool set_verbosity)
00111 {
00112   _verbose = set_verbosity;
00113 
00114 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
00115   // Set the verbose flag in the helper object
00116   // as well.
00117   nemhelper->verbose = _verbose;
00118 #endif
00119 }
00120 
00121 
00122 
00123 void Nemesis_IO::append(bool val)
00124 {
00125   _append = val;
00126 }
00127 
00128 
00129 
00130 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
00131 void Nemesis_IO::read (const std::string& base_filename)
00132 {
00133   // On one processor, Nemesis and ExodusII should be equivalent, so
00134   // let's cowardly defer to that implementation...
00135   if (this->n_processors() == 1)
00136     {
00137       // We can do this in one line but if the verbose flag was set in this
00138       // object, it will no longer be set... thus no extra print-outs for serial runs.
00139       // ExodusII_IO(this->mesh()).read (base_filename); // ambiguous when Nemesis_IO is multiply-inherited
00140 
00141       MeshBase& mesh = MeshInput<MeshBase>::mesh();
00142       ExodusII_IO(mesh).read (base_filename);
00143       return;
00144     }
00145 
00146   START_LOG ("read()","Nemesis_IO");
00147 
00148   // This function must be run on all processors at once
00149   parallel_object_only();
00150 
00151   if (_verbose)
00152     {
00153       libMesh::out << "[" << this->processor_id() << "] ";
00154       libMesh::out << "Reading Nemesis file on processor: " << this->processor_id() << std::endl;
00155     }
00156 
00157   // Construct the Nemesis filename based on the number of processors and the
00158   // current processor ID.
00159   std::string nemesis_filename = nemhelper->construct_nemesis_filename(base_filename);
00160 
00161   if (_verbose)
00162     libMesh::out << "Opening file: " << nemesis_filename << std::endl;
00163 
00164   // Open the Exodus file in EX_READ mode
00165   nemhelper->open(nemesis_filename.c_str(), /*read_only=*/true);
00166 
00167   // Get a reference to the mesh.  We need to be specific
00168   // since Nemesis_IO is multiply-inherited
00169   // MeshBase& mesh = this->mesh();
00170   MeshBase& mesh = MeshInput<MeshBase>::mesh();
00171 
00172   // We're reading a file on each processor, so our mesh is
00173   // partitioned into that many parts as it's created
00174   this->set_n_partitions(this->n_processors());
00175 
00176   // Local information: Read the following information from the standard Exodus header
00177   //  title[0]
00178   //  num_dim
00179   //  num_nodes
00180   //  num_elem
00181   //  num_elem_blk
00182   //  num_node_sets
00183   //  num_side_sets
00184   nemhelper->read_header();
00185   nemhelper->print_header();
00186 
00187   // Get global information: number of nodes, elems, blocks, nodesets and sidesets
00188   nemhelper->get_init_global();
00189 
00190   // Get "load balance" information.  This includes the number of internal & border
00191   // nodes and elements as well as the number of communication maps.
00192   nemhelper->get_loadbal_param();
00193 
00194   // Do some error checking
00195   if (nemhelper->num_external_nodes)
00196     libmesh_error_msg("ERROR: there should be no external nodes in an element-based partitioning!");
00197 
00198   libmesh_assert_equal_to (nemhelper->num_nodes,
00199                            (nemhelper->num_internal_nodes +
00200                             nemhelper->num_border_nodes));
00201 
00202   libmesh_assert_equal_to (nemhelper->num_elem,
00203                            (nemhelper->num_internal_elems +
00204                             nemhelper->num_border_elems));
00205 
00206   libmesh_assert_less_equal (nemhelper->num_nodes, nemhelper->num_nodes_global);
00207   libmesh_assert_less_equal (nemhelper->num_elem, nemhelper->num_elems_global);
00208 
00209   // Read nodes from the exodus file: this fills the nemhelper->x,y,z arrays.
00210   nemhelper->read_nodes();
00211 
00212   // Reads the nemhelper->node_num_map array, node_num_map[i] is the global node number for
00213   // local node number i.
00214   nemhelper->read_node_num_map();
00215 
00216   // The get_cmap_params() function reads in the:
00217   //  node_cmap_ids[],
00218   //  node_cmap_node_cnts[],
00219   //  elem_cmap_ids[],
00220   //  elem_cmap_elem_cnts[],
00221   nemhelper->get_cmap_params();
00222 
00223   // Read the IDs of the interior, boundary, and external nodes.  This function
00224   // fills the vectors:
00225   //  node_mapi[],
00226   //  node_mapb[],
00227   //  node_mape[]
00228   nemhelper->get_node_map();
00229 
00230   // Read each node communication map for this processor.  This function
00231   // fills the vectors of vectors named:
00232   //  node_cmap_node_ids[][]
00233   //  node_cmap_proc_ids[][]
00234   nemhelper->get_node_cmap();
00235 
00236   libmesh_assert_equal_to (to_uint(nemhelper->num_node_cmaps), nemhelper->node_cmap_node_cnts.size());
00237   libmesh_assert_equal_to (to_uint(nemhelper->num_node_cmaps), nemhelper->node_cmap_node_ids.size());
00238   libmesh_assert_equal_to (to_uint(nemhelper->num_node_cmaps), nemhelper->node_cmap_proc_ids.size());
00239 
00240 #ifndef NDEBUG
00241   // We expect the communication maps to be symmetric - e.g. if processor i thinks it
00242   // communicates with processor j, then processor j should also be expecting to
00243   // communicate with i.  We can assert that here easily enough with an alltoall,
00244   // but let's only do it when not in optimized mode to limit unnecessary communication.
00245   {
00246     std::vector<unsigned char> pid_send_partner (this->n_processors(), 0);
00247 
00248     // strictly speaking, we should expect to communicate with ourself...
00249     pid_send_partner[this->processor_id()] = 1;
00250 
00251     // mark each processor id we reference with a node cmap
00252     for (unsigned int cmap=0; cmap<to_uint(nemhelper->num_node_cmaps); cmap++)
00253       {
00254         libmesh_assert_less (to_uint(nemhelper->node_cmap_ids[cmap]), this->n_processors());
00255 
00256         pid_send_partner[nemhelper->node_cmap_ids[cmap]] = 1;
00257       }
00258 
00259     // Copy the send pairing so we can catch the receive paring and
00260     // test for equality
00261     const std::vector<unsigned char> pid_recv_partner (pid_send_partner);
00262 
00263     this->comm().alltoall (pid_send_partner);
00264 
00265     libmesh_assert (pid_send_partner == pid_recv_partner);
00266   }
00267 #endif
00268 
00269   // We now have enough information to infer node ownership.  We start by assuming
00270   // we own all the nodes on this processor.  We will then interrogate the
00271   // node cmaps and see if a lower-rank processor is associated with any of
00272   // our nodes.  If so, then that processor owns the node, not us...
00273   std::vector<processor_id_type> node_ownership (nemhelper->num_internal_nodes +
00274                                                  nemhelper->num_border_nodes,
00275                                                  this->processor_id());
00276 
00277   // a map from processor id to cmap number, to be used later
00278   std::map<unsigned int, unsigned int> pid_to_cmap_map;
00279 
00280   // For each node_cmap...
00281   for (unsigned int cmap=0; cmap<to_uint(nemhelper->num_node_cmaps); cmap++)
00282     {
00283       // Good time for error checking...
00284       libmesh_assert_equal_to (to_uint(nemhelper->node_cmap_node_cnts[cmap]),
00285                                nemhelper->node_cmap_node_ids[cmap].size());
00286 
00287       libmesh_assert_equal_to (to_uint(nemhelper->node_cmap_node_cnts[cmap]),
00288                                nemhelper->node_cmap_proc_ids[cmap].size());
00289 
00290       // In all the samples I have seen, node_cmap_ids[cmap] is the processor
00291       // rank of the remote processor...
00292       const int adjcnt_pid_idx = nemhelper->node_cmap_ids[cmap];
00293 
00294       libmesh_assert_less (adjcnt_pid_idx, this->n_processors());
00295       libmesh_assert_not_equal_to (adjcnt_pid_idx, this->processor_id());
00296 
00297       // We only expect one cmap per adjacent processor
00298       libmesh_assert (!pid_to_cmap_map.count(adjcnt_pid_idx));
00299 
00300       pid_to_cmap_map[adjcnt_pid_idx] = cmap;
00301 
00302       // ...and each node in that cmap...
00303       for (unsigned int idx=0; idx<to_uint(nemhelper->node_cmap_node_cnts[cmap]); idx++)
00304         {
00305           //  Are the node_cmap_ids and node_cmap_proc_ids really redundant?
00306           libmesh_assert_equal_to (adjcnt_pid_idx, nemhelper->node_cmap_proc_ids[cmap][idx]);
00307 
00308           // we are expecting the exodus node numbering to be 1-based...
00309           const unsigned int local_node_idx = nemhelper->node_cmap_node_ids[cmap][idx]-1;
00310 
00311           libmesh_assert_less (local_node_idx, node_ownership.size());
00312 
00313           // if the adjacent processor is lower rank than the current
00314           // owner for this node, then it will get the node...
00315           node_ownership[local_node_idx] =
00316             std::min(node_ownership[local_node_idx],
00317                      cast_int<processor_id_type>(adjcnt_pid_idx));
00318         }
00319     } // We now should have established proper node ownership.
00320 
00321   // now that ownership is established, we can figure out how many nodes we
00322   // will be responsible for numbering.
00323   unsigned int num_nodes_i_must_number = 0;
00324 
00325   for (unsigned int idx=0; idx<node_ownership.size(); idx++)
00326     if (node_ownership[idx] == this->processor_id())
00327       num_nodes_i_must_number++;
00328 
00329   // more error checking...
00330   libmesh_assert_greater_equal (num_nodes_i_must_number, to_uint(nemhelper->num_internal_nodes));
00331   libmesh_assert (num_nodes_i_must_number <= to_uint(nemhelper->num_internal_nodes +
00332                                                      nemhelper->num_border_nodes));
00333   if (_verbose)
00334     libMesh::out << "[" << this->processor_id() << "] "
00335                  << "num_nodes_i_must_number="
00336                  << num_nodes_i_must_number
00337                  << std::endl;
00338 
00339   // The call to get_loadbal_param() gets 7 pieces of information.  We allgather
00340   // these now across all processors to determine some global numberings. We should
00341   // also gather the number of nodes each processor thinks it will number so that
00342   // we can (i) determine our offset, and (ii) do some error checking.
00343   std::vector<int> all_loadbal_data ( 8 );
00344   all_loadbal_data[0] = nemhelper->num_internal_nodes;
00345   all_loadbal_data[1] = nemhelper->num_border_nodes;
00346   all_loadbal_data[2] = nemhelper->num_external_nodes;
00347   all_loadbal_data[3] = nemhelper->num_internal_elems;
00348   all_loadbal_data[4] = nemhelper->num_border_elems;
00349   all_loadbal_data[5] = nemhelper->num_node_cmaps;
00350   all_loadbal_data[6] = nemhelper->num_elem_cmaps;
00351   all_loadbal_data[7] = num_nodes_i_must_number;
00352 
00353   this->comm().allgather (all_loadbal_data, /* identical_buffer_sizes = */ true);
00354 
00355   // OK, we are now in a position to request new global indices for all the nodes
00356   // we do not own
00357 
00358   // Let's get a unique message tag to use for send()/receive()
00359   Parallel::MessageTag nodes_tag = mesh.comm().get_unique_tag(12345);
00360 
00361   std::vector<std::vector<int> >
00362     needed_node_idxs (nemhelper->num_node_cmaps); // the indices we will ask for
00363 
00364   std::vector<Parallel::Request>
00365     needed_nodes_requests (nemhelper->num_node_cmaps);
00366 
00367   for (unsigned int cmap=0; cmap<to_uint(nemhelper->num_node_cmaps); cmap++)
00368     {
00369       // We know we will need no more indices than there are nodes
00370       // in this cmap, but that number is an upper bound in general
00371       // since the neighboring processor associated with the cmap
00372       //  may not actually own it
00373       needed_node_idxs[cmap].reserve   (nemhelper->node_cmap_node_cnts[cmap]);
00374 
00375       const unsigned int adjcnt_pid_idx = nemhelper->node_cmap_ids[cmap];
00376 
00377       // ...and each node in that cmap...
00378       for (unsigned int idx=0; idx<to_uint(nemhelper->node_cmap_node_cnts[cmap]); idx++)
00379         {
00380           const unsigned int
00381             local_node_idx  = nemhelper->node_cmap_node_ids[cmap][idx]-1,
00382             owning_pid_idx  = node_ownership[local_node_idx];
00383 
00384           // add it to the request list for its owning processor.
00385           if (owning_pid_idx == adjcnt_pid_idx)
00386             {
00387               const unsigned int
00388                 global_node_idx = nemhelper->node_num_map[local_node_idx]-1;
00389               needed_node_idxs[cmap].push_back(global_node_idx);
00390             }
00391         }
00392       // now post the send for this cmap
00393       this->comm().send (adjcnt_pid_idx,              // destination
00394                          needed_node_idxs[cmap],      // send buffer
00395                          needed_nodes_requests[cmap], // request
00396                          nodes_tag);
00397     } // all communication requests for getting updated global indices for border
00398       // nodes have been initiated
00399 
00400   // Figure out how many nodes each processor thinks it will number and make sure
00401   // that it adds up to the global number of nodes. Also, set up global node
00402   // index offsets for each processor.
00403   std::vector<unsigned int>
00404     all_num_nodes_i_must_number (this->n_processors());
00405 
00406   for (unsigned int pid=0; pid<this->n_processors(); pid++)
00407     all_num_nodes_i_must_number[pid] = all_loadbal_data[8*pid + 7];
00408 
00409   // The sum of all the entries in this vector should sum to the number of global nodes
00410   libmesh_assert (std::accumulate(all_num_nodes_i_must_number.begin(),
00411                                   all_num_nodes_i_must_number.end(),
00412                                   0) == nemhelper->num_nodes_global);
00413 
00414   unsigned int my_next_node = 0;
00415   for (unsigned int pid=0; pid<this->processor_id(); pid++)
00416     my_next_node += all_num_nodes_i_must_number[pid];
00417 
00418   const unsigned int my_node_offset = my_next_node;
00419 
00420   if (_verbose)
00421     libMesh::out << "[" << this->processor_id() << "] "
00422                  << "my_node_offset="
00423                  << my_node_offset
00424                  << std::endl;
00425 
00426   // Add internal nodes to the ParallelMesh, using the node ID offset we
00427   // computed and the current processor's ID.
00428   for (unsigned int i=0; i<to_uint(nemhelper->num_internal_nodes); ++i)
00429     {
00430       const unsigned int local_node_idx  = nemhelper->node_mapi[i]-1;
00431 #ifndef NDEBUG
00432       const unsigned int owning_pid_idx  = node_ownership[local_node_idx];
00433 #endif
00434 
00435       // an internal node we do not own? huh??
00436       libmesh_assert_equal_to (owning_pid_idx, this->processor_id());
00437       libmesh_assert_less (my_next_node, to_uint(nemhelper->num_nodes_global));
00438 
00439       // "Catch" the node pointer after addition, make sure the
00440       // ID matches the requested value.
00441       Node* added_node =
00442         mesh.add_point (Point(nemhelper->x[local_node_idx],
00443                               nemhelper->y[local_node_idx],
00444                               nemhelper->z[local_node_idx]),
00445                         my_next_node,
00446                         this->processor_id());
00447 
00448       // Make sure the node we added has the ID we thought it would
00449       if (added_node->id() != my_next_node)
00450         {
00451           libMesh::err << "Error, node added with ID " << added_node->id()
00452                        << ", but we wanted ID " << my_next_node << std::endl;
00453         }
00454 
00455       // update the local->global index map, when we are done
00456       // it will be 0-based.
00457       nemhelper->node_num_map[local_node_idx] = my_next_node++;
00458     }
00459 
00460   // Now, for the boundary nodes...  We may very well own some of them,
00461   // but there may be others for which we have requested the new global
00462   // id.  We expect to be asked for the ids of the ones we own, so
00463   // we need to create a map from the old global id to the new one
00464   // we are about to create.
00465   typedef std::vector<std::pair<unsigned int, unsigned int> > global_idx_mapping_type;
00466   global_idx_mapping_type old_global_to_new_global_map;
00467   old_global_to_new_global_map.reserve (num_nodes_i_must_number // total # i will have
00468                                         - (my_next_node         // amount i have thus far
00469                                            - my_node_offset));  // this should be exact!
00470   CompareGlobalIdxMappings global_idx_mapping_comp;
00471 
00472   for (unsigned int i=0; i<to_uint(nemhelper->num_border_nodes); ++i)
00473     {
00474       const unsigned int
00475         local_node_idx  = nemhelper->node_mapb[i]-1,
00476         owning_pid_idx  = node_ownership[local_node_idx];
00477 
00478       // if we own it...
00479       if (owning_pid_idx == this->processor_id())
00480         {
00481           const unsigned int
00482             global_node_idx = nemhelper->node_num_map[local_node_idx]-1;
00483 
00484           // we will number it, and create a mapping from its old global index to
00485           // the new global index, for lookup purposes when neighbors come calling
00486           old_global_to_new_global_map.push_back(std::make_pair(global_node_idx,
00487                                                                 my_next_node));
00488 
00489           // "Catch" the node pointer after addition, make sure the
00490           // ID matches the requested value.
00491           Node* added_node =
00492             mesh.add_point (Point(nemhelper->x[local_node_idx],
00493                                   nemhelper->y[local_node_idx],
00494                                   nemhelper->z[local_node_idx]),
00495                             my_next_node,
00496                             this->processor_id());
00497 
00498           // Make sure the node we added has the ID we thought it would
00499           if (added_node->id() != my_next_node)
00500             {
00501               libMesh::err << "Error, node added with ID " << added_node->id()
00502                            << ", but we wanted ID " << my_next_node << std::endl;
00503             }
00504 
00505           // update the local->global index map, when we are done
00506           // it will be 0-based.
00507           nemhelper->node_num_map[local_node_idx] = my_next_node++;
00508         }
00509     }
00510   // That should cover numbering all the nodes which belong to us...
00511   libmesh_assert_equal_to (num_nodes_i_must_number, (my_next_node - my_node_offset));
00512 
00513   // Let's sort the mapping so we can efficiently answer requests
00514   std::sort (old_global_to_new_global_map.begin(),
00515              old_global_to_new_global_map.end(),
00516              global_idx_mapping_comp);
00517 
00518   // and it had better be unique...
00519   libmesh_assert (std::unique (old_global_to_new_global_map.begin(),
00520                                old_global_to_new_global_map.end(),
00521                                global_idx_mapping_equality) ==
00522                   old_global_to_new_global_map.end());
00523 
00524   // We can now catch incoming requests and process them. for efficiency
00525   // let's do whatever is available next
00526   std::map<unsigned int, std::vector<int> > requested_node_idxs; // the indices asked of us
00527 
00528   std::vector<Parallel::Request> requested_nodes_requests(nemhelper->num_node_cmaps);
00529 
00530   // We know we will receive the request from a given processor before
00531   // we receive its reply to our request. However, we may receive
00532   // a request and a response from one processor before getting
00533   // a request from another processor.  So what we are doing here
00534   // is processing whatever message comes next, while recognizing
00535   // we will receive a request from a processor before receiving
00536   // its reply
00537   std::vector<bool> processed_cmap (nemhelper->num_node_cmaps, false);
00538 
00539   for (unsigned int comm_step=0; comm_step<2*to_uint(nemhelper->num_node_cmaps); comm_step++)
00540     {
00541       // query the first message which is available
00542       const Parallel::Status
00543         status (this->comm().probe (Parallel::any_source,
00544                                     nodes_tag));
00545       const unsigned int
00546         requesting_pid_idx = status.source(),
00547         source_pid_idx     = status.source();
00548 
00549       // this had better be from a processor we are expecting...
00550       libmesh_assert (pid_to_cmap_map.count(requesting_pid_idx));
00551 
00552       // the local cmap which corresponds to the source processor
00553       const unsigned int cmap = pid_to_cmap_map[source_pid_idx];
00554 
00555       if (!processed_cmap[cmap])
00556         {
00557           processed_cmap[cmap] = true;
00558 
00559           // we should only get one request per paired processor
00560           libmesh_assert (!requested_node_idxs.count(requesting_pid_idx));
00561 
00562           // get a reference to the request buffer for this processor to
00563           // avoid repeated map lookups
00564           std::vector<int> &xfer_buf (requested_node_idxs[requesting_pid_idx]);
00565 
00566           // actually receive the message.
00567           this->comm().receive (requesting_pid_idx, xfer_buf, nodes_tag);
00568 
00569           // Fill the request
00570           for (unsigned int i=0; i<xfer_buf.size(); i++)
00571             {
00572               // the requested old global node index, *now 0-based*
00573               const unsigned int old_global_node_idx = xfer_buf[i];
00574 
00575               // find the new global node index for the requested node -
00576               // note that requesting_pid_idx thinks we own this node,
00577               // so we better!
00578               const global_idx_mapping_type::const_iterator it =
00579                 std::lower_bound (old_global_to_new_global_map.begin(),
00580                                   old_global_to_new_global_map.end(),
00581                                   old_global_node_idx,
00582                                   global_idx_mapping_comp);
00583 
00584               libmesh_assert (it != old_global_to_new_global_map.end());
00585               libmesh_assert_equal_to (it->first, old_global_node_idx);
00586               libmesh_assert_greater_equal (it->second, my_node_offset);
00587               libmesh_assert_less (it->second, my_next_node);
00588 
00589               // overwrite the requested old global node index with the new global index
00590               xfer_buf[i] = it->second;
00591             }
00592 
00593           // and send the new global indices back to the processor which asked for them
00594           this->comm().send (requesting_pid_idx,
00595                              xfer_buf,
00596                              requested_nodes_requests[cmap],
00597                              nodes_tag);
00598         } // done processing the request
00599 
00600       // this is the second time we have heard from this processor,
00601       // so it must be its reply to our request
00602       else
00603         {
00604           // a long time ago, we sent off our own requests.  now it is time to catch the
00605           // replies and get the new global node numbering.  note that for any reply
00606           // we receive, the corresponding nonblocking send from above *must* have been
00607           // completed, since the reply is in response to that request!!
00608 
00609           // if we have received a reply, our send *must* have completed
00610           // (note we never actually need to wait on the request)
00611           libmesh_assert (needed_nodes_requests[cmap].test());
00612           libmesh_assert_equal_to (to_uint(nemhelper->node_cmap_ids[cmap]), source_pid_idx);
00613 
00614           // now post the receive for this cmap
00615           this->comm().receive (source_pid_idx,
00616                                 needed_node_idxs[cmap],
00617                                 nodes_tag);
00618 
00619           libmesh_assert_less_equal (needed_node_idxs[cmap].size(),
00620                                      nemhelper->node_cmap_node_ids[cmap].size());
00621 
00622           for (unsigned int i=0,j=0; i<nemhelper->node_cmap_node_ids[cmap].size(); i++)
00623             {
00624               const unsigned int
00625                 local_node_idx  = nemhelper->node_cmap_node_ids[cmap][i]-1,
00626                 owning_pid_idx  = node_ownership[local_node_idx];
00627 
00628               // if this node is owned by source_pid_idx, its new global id
00629               // is in the buffer we just received
00630               if (owning_pid_idx == source_pid_idx)
00631                 {
00632                   libmesh_assert_less (j, needed_node_idxs[cmap].size());
00633 
00634                   const unsigned int // now 0-based!
00635                     global_node_idx = needed_node_idxs[cmap][j++];
00636 
00637                   // "Catch" the node pointer after addition, make sure the
00638                   // ID matches the requested value.
00639                   Node* added_node =
00640                     mesh.add_point (Point(nemhelper->x[local_node_idx],
00641                                           nemhelper->y[local_node_idx],
00642                                           nemhelper->z[local_node_idx]),
00643                                     cast_int<dof_id_type>(global_node_idx),
00644                                     cast_int<processor_id_type>(source_pid_idx));
00645 
00646                   // Make sure the node we added has the ID we thought it would
00647                   if (added_node->id() != global_node_idx)
00648                     {
00649                       libMesh::err << "Error, node added with ID " << added_node->id()
00650                                    << ", but we wanted ID " << global_node_idx << std::endl;
00651                     }
00652 
00653                   // update the local->global index map, when we are done
00654                   // it will be 0-based.
00655                   nemhelper->node_num_map[local_node_idx] = global_node_idx;
00656 
00657                   // we are not really going to use my_next_node again, but we can
00658                   // keep incrimenting it to track how many nodes we have added
00659                   // to the mesh
00660                   my_next_node++;
00661                 }
00662             }
00663         }
00664     } // end of node index communication loop
00665 
00666   // we had better have added all the nodes we need to!
00667   libmesh_assert_equal_to ((my_next_node - my_node_offset), to_uint(nemhelper->num_nodes));
00668 
00669   // After all that, we should be done with all node-related arrays *except* the
00670   // node_num_map, which we have transformed to use our new numbering...
00671   // So let's clean up the arrays we are done with.
00672   {
00673     Utility::deallocate (nemhelper->node_mapi);
00674     Utility::deallocate (nemhelper->node_mapb);
00675     Utility::deallocate (nemhelper->node_mape);
00676     Utility::deallocate (nemhelper->node_cmap_ids);
00677     Utility::deallocate (nemhelper->node_cmap_node_cnts);
00678     Utility::deallocate (nemhelper->node_cmap_node_ids);
00679     Utility::deallocate (nemhelper->node_cmap_proc_ids);
00680     Utility::deallocate (nemhelper->x);
00681     Utility::deallocate (nemhelper->y);
00682     Utility::deallocate (nemhelper->z);
00683     Utility::deallocate (needed_node_idxs);
00684     Utility::deallocate (node_ownership);
00685   }
00686 
00687   Parallel::wait (requested_nodes_requests);
00688   requested_node_idxs.clear();
00689 
00690   // See what the node count is up to now.
00691   if (_verbose)
00692     {
00693       // Report the number of nodes which have been added locally
00694       libMesh::out << "[" << this->processor_id() << "] ";
00695       libMesh::out << "mesh.n_nodes()=" << mesh.n_nodes() << std::endl;
00696 
00697       // Reports the number of nodes that have been added in total.
00698       libMesh::out << "[" << this->processor_id() << "] ";
00699       libMesh::out << "mesh.parallel_n_nodes()=" << mesh.parallel_n_nodes() << std::endl;
00700     }
00701 
00702 
00703 
00704   // --------------------------------------------------------------------------------
00705   // --------------------------------------------------------------------------------
00706   // --------------------------------------------------------------------------------
00707 
00708 
00709   // We can now read in the elements...Exodus stores them in blocks in which all
00710   // elements have the same geometric type.  This code is adapted directly from exodusII_io.C
00711 
00712   // Assertion: The sum of the border and internal elements on all processors
00713   // should equal nemhelper->num_elems_global
00714 #ifndef NDEBUG
00715   {
00716     int sum_internal_elems=0, sum_border_elems=0;
00717     for (unsigned int j=3,c=0; c<this->n_processors(); j+=8,++c)
00718       sum_internal_elems += all_loadbal_data[j];
00719 
00720     for (unsigned int j=4,c=0; c<this->n_processors(); j+=8,++c)
00721       sum_border_elems += all_loadbal_data[j];
00722 
00723     if (_verbose)
00724       {
00725         libMesh::out << "[" << this->processor_id() << "] ";
00726         libMesh::out << "sum_internal_elems=" << sum_internal_elems << std::endl;
00727 
00728         libMesh::out << "[" << this->processor_id() << "] ";
00729         libMesh::out << "sum_border_elems=" << sum_border_elems << std::endl;
00730       }
00731 
00732     libmesh_assert_equal_to (sum_internal_elems+sum_border_elems, nemhelper->num_elems_global);
00733   }
00734 #endif
00735 
00736   // We need to set the mesh dimension, but the following...
00737   // mesh.set_mesh_dimension(static_cast<unsigned int>(nemhelper->num_dim));
00738 
00739   // ... is not sufficient since some codes report num_dim==3 for two dimensional
00740   // meshes living in 3D, even though all the elements are of 2D type.  Therefore,
00741   // we instead use the dimension of the highest element found for the Mesh dimension,
00742   // similar to what is done by the Exodus reader, except here it requires a
00743   // parallel communication.
00744   elems_of_dimension.resize(4, false); // will use 1-based
00745 
00746   // Compute my_elem_offset, the amount by which to offset the local elem numbering
00747   // on my processor.
00748   unsigned int my_next_elem = 0;
00749   for (unsigned int pid=0; pid<this->processor_id(); ++pid)
00750     my_next_elem += (all_loadbal_data[8*pid + 3]+  // num_internal_elems, proc pid
00751                      all_loadbal_data[8*pid + 4]); // num_border_elems, proc pid
00752   const unsigned int my_elem_offset = my_next_elem;
00753 
00754   if (_verbose)
00755     libMesh::out << "[" << this->processor_id() << "] "
00756                  << "my_elem_offset=" << my_elem_offset << std::endl;
00757 
00758 
00759   // Fills in the:
00760   // global_elem_blk_ids[] and
00761   // global_elem_blk_cnts[] arrays.
00762   nemhelper->get_eb_info_global();
00763 
00764   //   // Fills in the vectors
00765   //   // elem_mapi[num_internal_elems]
00766   //   // elem_mapb[num_border_elems  ]
00767   //   // These tell which of the (locally-numbered) elements are internal and which are border elements.
00768   //   // In our test example these arrays are sorted (but non-contiguous), which makes it possible to
00769   //   // binary search for each element ID... however I don't think we need to distinguish between the
00770   //   // two types, since either can have nodes the boundary!
00771   //   nemhelper->get_elem_map();
00772 
00773   // Fills in the vectors of vectors:
00774   // elem_cmap_elem_ids[][]
00775   // elem_cmap_side_ids[][]
00776   // elem_cmap_proc_ids[][]
00777   // These arrays are of size num_elem_cmaps * elem_cmap_elem_cnts[i], i = 0..num_elem_cmaps
00778   nemhelper->get_elem_cmap();
00779 
00780   // Get information about the element blocks:
00781   // (read in the array nemhelper->block_ids[])
00782   nemhelper->read_block_info();
00783 
00784   // Reads the nemhelper->elem_num_map array, elem_num_map[i] is the global element number for
00785   // local element number i.
00786   nemhelper->read_elem_num_map();
00787 
00788   // Instantiate the ElementMaps interface.  This is what translates LibMesh's
00789   // element numbering scheme to Exodus's.
00790   ExodusII_IO_Helper::ElementMaps em;
00791 
00792   // Read in the element connectivity for each block by
00793   // looping over all the blocks.
00794   for (unsigned int i=0; i<to_uint(nemhelper->num_elem_blk); i++)
00795     {
00796       // Read the information for block i:  For nemhelper->block_ids[i], reads
00797       // elem_type
00798       // num_elem_this_blk
00799       // num_nodes_per_elem
00800       // num_attr
00801       // connect <-- the nodal connectivity array for each element in the block.
00802       nemhelper->read_elem_in_block(i);
00803 
00804       // Note that with parallel files it is possible we have no elements in
00805       // this block!
00806       if (!nemhelper->num_elem_this_blk) continue;
00807 
00808       // Set subdomain ID based on the block ID.
00809       subdomain_id_type subdomain_id =
00810         cast_int<subdomain_id_type>(nemhelper->block_ids[i]);
00811 
00812       // Create a type string (this uses the null-terminated string ctor).
00813       const std::string type_str ( &(nemhelper->elem_type[0]) );
00814 
00815       // Set any relevant node/edge maps for this element
00816       const ExodusII_IO_Helper::Conversion conv = em.assign_conversion(type_str);
00817 
00818       if (_verbose)
00819         libMesh::out << "Reading a block of " << type_str << " elements." << std::endl;
00820 
00821       // Loop over all the elements in this block
00822       for (unsigned int j=0; j<to_uint(nemhelper->num_elem_this_blk); j++)
00823         {
00824           Elem* elem = Elem::build (conv.get_canonical_type()).release();
00825           libmesh_assert (elem);
00826 
00827           // Assign subdomain and processor ID to the newly-created Elem.
00828           // Assigning the processor ID beforehand ensures that the Elem is
00829           // not added as an "unpartitioned" element.  Note that the element
00830           // numbering in Exodus is also 1-based.
00831           elem->subdomain_id() = subdomain_id;
00832           elem->processor_id() = this->processor_id();
00833           elem->set_id()       = my_next_elem++;
00834 
00835           // Mark that we have seen an element of the current element's
00836           // dimension.
00837           elems_of_dimension[elem->dim()] = true;
00838 
00839           // Add the created Elem to the Mesh, catch the Elem
00840           // pointer that the Mesh throws back.
00841           elem = mesh.add_elem (elem);
00842 
00843           // We are expecting the element "thrown back" by libmesh to have the ID we specified for it...
00844           // Check to see that really is the case.  Note that my_next_elem was post-incremented, so
00845           // subtract 1 when performing the check.
00846           if (elem->id() != my_next_elem-1)
00847             libmesh_error_msg("Unexpected ID "  \
00848                               << elem->id()                             \
00849                               << " set by parallel mesh. (expecting "   \
00850                               << my_next_elem-1                         \
00851                               << ").");
00852 
00853           // Set all the nodes for this element
00854           if (_verbose)
00855             libMesh::out << "[" << this->processor_id() << "] "
00856                          << "Setting nodes for Elem " << elem->id() << std::endl;
00857 
00858           for (unsigned int k=0; k<to_uint(nemhelper->num_nodes_per_elem); k++)
00859             {
00860               const unsigned int
00861                 gi              = (j*nemhelper->num_nodes_per_elem +       // index into connectivity array
00862                                    conv.get_node_map(k)),
00863                 local_node_idx  = nemhelper->connect[gi]-1,                // local node index
00864                 global_node_idx = nemhelper->node_num_map[local_node_idx]; // new global node index
00865 
00866               // Set node number
00867               elem->set_node(k) = mesh.node_ptr(global_node_idx);
00868             }
00869         } // for (unsigned int j=0; j<nemhelper->num_elem_this_blk; j++)
00870     } // end for (unsigned int i=0; i<nemhelper->num_elem_blk; i++)
00871 
00872   libmesh_assert_equal_to ((my_next_elem - my_elem_offset), to_uint(nemhelper->num_elem));
00873 
00874   if (_verbose)
00875     {
00876       // Print local elems_of_dimension information
00877       for (unsigned int i=1; i<elems_of_dimension.size(); ++i)
00878         libMesh::out << "[" << this->processor_id() << "] "
00879                      << "elems_of_dimension[" << i << "]=" << elems_of_dimension[i] << std::endl;
00880     }
00881 
00882   // Get the max dimension seen on the current processor
00883   unsigned char max_dim_seen = 0;
00884   for (unsigned char i=1; i<elems_of_dimension.size(); ++i)
00885     if (elems_of_dimension[i])
00886       max_dim_seen = i;
00887 
00888   // Do a global max to determine the max dimension seen by all processors.
00889   // It should match -- I don't think we even support calculations on meshes
00890   // with elements of different dimension...
00891   this->comm().max(max_dim_seen);
00892 
00893   if (_verbose)
00894     {
00895       // Print the max element dimension from all processors
00896       libMesh::out << "[" << this->processor_id() << "] "
00897                    << "max_dim_seen=" << +max_dim_seen << std::endl;
00898     }
00899 
00900   // Set the mesh dimension to the largest encountered for an element
00901   mesh.set_mesh_dimension(max_dim_seen);
00902 
00903 #if LIBMESH_DIM < 3
00904   if (mesh.mesh_dimension() > LIBMESH_DIM)
00905     libmesh_error_msg("Cannot open dimension "   \
00906                       << mesh.mesh_dimension()                          \
00907                       << " mesh file when configured without "          \
00908                       << mesh.mesh_dimension()                          \
00909                       << "D support." );
00910 #endif
00911 
00912 
00913   // Global sideset information, they are distributed as well, not sure if they will require communication...?
00914   nemhelper->get_ss_param_global();
00915 
00916   if (_verbose)
00917     {
00918       libMesh::out << "[" << this->processor_id() << "] "
00919                    << "Read global sideset parameter information." << std::endl;
00920 
00921       // These global values should be the same on all processors...
00922       libMesh::out << "[" << this->processor_id() << "] "
00923                    << "Number of global sideset IDs: " << nemhelper->global_sideset_ids.size() << std::endl;
00924     }
00925 
00926   // Read *local* sideset info the same way it is done in
00927   // exodusII_io_helper.  May be called any time after
00928   // nem_helper->read_header(); This sets num_side_sets and resizes
00929   // elem_list, side_list, and id_list to num_elem_all_sidesets.  Note
00930   // that there appears to be the same number of sidesets in each file
00931   // but they all have different numbers of entries (some are empty).
00932   // Note that the sum of "nemhelper->num_elem_all_sidesets" over all
00933   // processors should equal the sum of the entries in the "num_global_side_counts" array
00934   // filled up by nemhelper->get_ss_param_global()
00935   nemhelper->read_sideset_info();
00936 
00937   if (_verbose)
00938     {
00939       libMesh::out << "[" << this->processor_id() << "] "
00940                    << "nemhelper->num_side_sets = " << nemhelper->num_side_sets << std::endl;
00941 
00942       libMesh::out << "[" << this->processor_id() << "] "
00943                    << "nemhelper->num_elem_all_sidesets = " << nemhelper->num_elem_all_sidesets << std::endl;
00944     }
00945 
00946 #ifdef DEBUG
00947   {
00948     // In DEBUG mode, check that the global number of sidesets reported
00949     // in each nemesis file matches the sum of all local sideset counts
00950     // from each processor.  This requires a small communication, so only
00951     // do it in DEBUG mode.
00952     int sum_num_global_side_counts = std::accumulate(nemhelper->num_global_side_counts.begin(),
00953                                                      nemhelper->num_global_side_counts.end(),
00954                                                      0);
00955 
00956     // MPI sum up the local files contributions
00957     int sum_num_elem_all_sidesets = nemhelper->num_elem_all_sidesets;
00958     this->comm().sum(sum_num_elem_all_sidesets);
00959 
00960     if (sum_num_global_side_counts != sum_num_elem_all_sidesets)
00961       libmesh_error_msg("Error! global side count reported by Nemesis does not " \
00962                         << "match the side count reported by the individual files!");
00963   }
00964 #endif
00965 
00966   // Note that exodus stores sidesets in separate vectors but we want to pack
00967   // them all into a single vector.  So when we call read_sideset(), we pass an offset
00968   // into the single vector of all IDs
00969   for (int offset=0, i=0; i<nemhelper->num_side_sets; i++)
00970     {
00971       offset += (i > 0 ? nemhelper->num_sides_per_set[i-1] : 0); // Compute new offset
00972       nemhelper->read_sideset (i, offset);
00973     }
00974 
00975   // Now that we have the lists of elements, sides, and IDs, we are ready to set them
00976   // in the BoundaryInfo object of our Mesh object.  This is slightly different in parallel...
00977   // For example, I think the IDs in each of the split Exodus files are numbered locally,
00978   // and we have to know the appropriate ID for this processor to be able to set the
00979   // entry in BoundaryInfo.  This offset should be given by my_elem_offset determined in
00980   // this function...
00981 
00982   // Debugging:
00983   // Print entries of elem_list
00984   // libMesh::out << "[" << this->processor_id() << "] "
00985   //        << "elem_list = ";
00986   // for (unsigned int e=0; e<nemhelper->elem_list.size(); e++)
00987   //   {
00988   //     libMesh::out << nemhelper->elem_list[e] << ", ";
00989   //   }
00990   // libMesh::out << std::endl;
00991 
00992   // Print entries of side_list
00993   // libMesh::out << "[" << this->processor_id() << "] "
00994   //        << "side_list = ";
00995   // for (unsigned int e=0; e<nemhelper->side_list.size(); e++)
00996   //   {
00997   //     libMesh::out << nemhelper->side_list[e] << ", ";
00998   //   }
00999   // libMesh::out << std::endl;
01000 
01001 
01002   // Loop over the entries of the elem_list, get their pointers from the
01003   // Mesh data structure, and assign the appropriate side to the BoundaryInfo object.
01004   for (unsigned int e=0; e<nemhelper->elem_list.size(); e++)
01005     {
01006       // Calling mesh.elem() feels wrong, for example, in
01007       // ParallelMesh, Mesh::elem() can return NULL so we have to check for this...
01008       //
01009       // Perhaps we should iterate over elements and look them up in
01010       // the elem list instead?  Note that the IDs in elem_list are
01011       // not necessarily in order, so if we did instead loop over the
01012       // mesh, we would have to search the (unsorted) elem_list vector
01013       // for each entry!  We'll settle for doing some error checking instead.
01014       Elem* elem = mesh.elem(my_elem_offset + (nemhelper->elem_list[e]-1)/*Exodus numbering is 1-based!*/);
01015 
01016       if (elem == NULL)
01017         libmesh_error_msg("Mesh returned a NULL pointer when asked for element " \
01018                           << my_elem_offset                           \
01019                           << " + "                                    \
01020                           << nemhelper->elem_list[e]                  \
01021                           << " = "                                    \
01022                           << my_elem_offset+nemhelper->elem_list[e]);
01023 
01024       // The side numberings in libmesh and exodus are not 1:1, so we need to map
01025       // whatever side number is stored in Exodus into a libmesh side number using
01026       // a conv object...
01027       const ExodusII_IO_Helper::Conversion conv =
01028         em.assign_conversion(elem->type());
01029 
01030       // Finally, we are ready to add the element and its side to the BoundaryInfo object.
01031       // Call the version of add_side which takes a pointer, since we have already gone to
01032       // the trouble of getting said pointer...
01033       mesh.get_boundary_info().add_side(elem,
01034                                         cast_int<unsigned short>(conv.get_side_map(nemhelper->side_list[e]-1)), // Exodus numbering is 1-based
01035                                         cast_int<boundary_id_type>(nemhelper->id_list[e]));
01036     }
01037 
01038   // Debugging: make sure there are as many boundary conditions in the
01039   // boundary ID object as expected.  Note that, at this point, the
01040   // mesh still thinks it's serial, so n_boundary_conds() returns the
01041   // local number of boundary conditions (and is therefore cheap)
01042   // which should match nemhelper->elem_list.size().
01043   {
01044     std::size_t nbcs = mesh.get_boundary_info().n_boundary_conds();
01045     if (nbcs != nemhelper->elem_list.size())
01046       libmesh_error_msg("[" << this->processor_id() << "] "   \
01047                         << "BoundaryInfo contains "                     \
01048                         << nbcs                                         \
01049                         << " boundary conditions, while the Exodus file had " \
01050                         << nemhelper->elem_list.size());
01051   }
01052 
01053   // Read global nodeset parameters?  We might be able to use this to verify
01054   // something about the local files, but I haven't figured out what yet...
01055   nemhelper->get_ns_param_global();
01056 
01057   // Read local nodeset info
01058   nemhelper->read_nodeset_info();
01059 
01060   if (_verbose)
01061     {
01062       libMesh::out << "[" << this->processor_id() << "] ";
01063       libMesh::out << "nemhelper->num_node_sets=" << nemhelper->num_node_sets << std::endl;
01064     }
01065 
01066   //  // Debugging, what is currently in nemhelper->node_num_map anyway?
01067   //  libMesh::out << "[" << this->processor_id() << "] "
01068   //       << "nemhelper->node_num_map = ";
01069   //
01070   //  for (unsigned int i=0; i<nemhelper->node_num_map.size(); ++i)
01071   //    libMesh::out << nemhelper->node_num_map[i] << ", ";
01072   //  libMesh::out << std::endl;
01073 
01074   // For each nodeset,
01075   for (int nodeset=0; nodeset<nemhelper->num_node_sets; nodeset++)
01076     {
01077       // Get the user-defined ID associcated with the nodeset
01078       int nodeset_id = nemhelper->nodeset_ids[nodeset];
01079 
01080       if (_verbose)
01081         {
01082           libMesh::out << "[" << this->processor_id() << "] ";
01083           libMesh::out << "nemhelper->nodeset_ids[" << nodeset << "]=" << nodeset_id << std::endl;
01084         }
01085 
01086       // Read the nodeset from file, store them in a vector
01087       nemhelper->read_nodeset(nodeset);
01088 
01089       // Add nodes from the node_list to the BoundaryInfo object
01090       for (unsigned int node=0; node<nemhelper->node_list.size(); node++)
01091         {
01092           // Don't run past the end of our node map!
01093           if (to_uint(nemhelper->node_list[node]-1) >= nemhelper->node_num_map.size())
01094             libmesh_error_msg("Error, index is past the end of node_num_map array!");
01095 
01096           // We should be able to use the node_num_map data structure set up previously to determine
01097           // the proper global node index.
01098           unsigned global_node_id = nemhelper->node_num_map[ nemhelper->node_list[node]-1 /*Exodus is 1-based!*/ ];
01099 
01100           if (_verbose)
01101             {
01102               libMesh::out << "[" << this->processor_id() << "] "
01103                            << "nodeset " << nodeset
01104                            << ", local node number: " << nemhelper->node_list[node]-1
01105                            << ", global node id: " << global_node_id
01106                            << std::endl;
01107             }
01108 
01109           // Add the node to the BoundaryInfo object with the proper nodeset_id
01110           mesh.get_boundary_info().add_node
01111             (cast_int<dof_id_type>(global_node_id),
01112              cast_int<boundary_id_type>(nodeset_id));
01113         }
01114     }
01115 
01116   // See what the elem count is up to now.
01117   if (_verbose)
01118     {
01119       // Report the number of elements which have been added locally
01120       libMesh::out << "[" << this->processor_id() << "] ";
01121       libMesh::out << "mesh.n_elem()=" << mesh.n_elem() << std::endl;
01122 
01123       // Reports the number of elements that have been added in total.
01124       libMesh::out << "[" << this->processor_id() << "] ";
01125       libMesh::out << "mesh.parallel_n_elem()=" << mesh.parallel_n_elem() << std::endl;
01126     }
01127 
01128   STOP_LOG ("read()","Nemesis_IO");
01129 
01130   // For ParallelMesh, it seems that _is_serial is true by default.  A hack to
01131   // make the Mesh think it's parallel might be to call:
01132   mesh.update_post_partitioning();
01133   mesh.delete_remote_elements();
01134 
01135   // And if that didn't work, then we're actually reading into a
01136   // SerialMesh, so forget about gathering neighboring elements
01137   if (mesh.is_serial())
01138     return;
01139 
01140   // Gather neighboring elements so that the mesh has the proper "ghost" neighbor information.
01141   MeshCommunication().gather_neighboring_elements(cast_ref<ParallelMesh&>(mesh));
01142 }
01143 
01144 #else
01145 
01146 void Nemesis_IO::read (const std::string& )
01147 {
01148   libmesh_error_msg("ERROR, Nemesis API is not defined!");
01149 }
01150 
01151 #endif // #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
01152 
01153 
01154 
01155 
01156 
01157 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
01158 
01159 void Nemesis_IO::write (const std::string& base_filename)
01160 {
01161   // Get a constant reference to the mesh for writing
01162   const MeshBase & mesh = MeshOutput<MeshBase>::mesh();
01163 
01164   // Create the filename for this processor given the base_filename passed in.
01165   std::string nemesis_filename = nemhelper->construct_nemesis_filename(base_filename);
01166 
01167   // If the user has set the append flag here, it doesn't really make
01168   // sense: the intent of this function is to write a Mesh with no
01169   // data, while "appending" is really intended to add data to an
01170   // existing file.  If we're verbose, print a message to this effect.
01171   if (_append && _verbose)
01172     libMesh::out << "Warning: Appending in Nemesis_IO::write() does not make sense.\n"
01173                  << "Creating a new file instead!"
01174                  << std::endl;
01175 
01176   nemhelper->create(nemesis_filename);
01177 
01178   // Initialize data structures and write some global Nemesis-specifc data, such as
01179   // communication maps, to file.
01180   nemhelper->initialize(nemesis_filename,mesh);
01181 
01182   // Call the Nemesis-specialized version of write_nodal_coordinates() to write
01183   // the nodal coordinates.
01184   nemhelper->write_nodal_coordinates(mesh);
01185 
01186   // Call the Nemesis-specialized version of write_elements() to write
01187   // the elements.  Note: Must write a zero if a given global block ID has no
01188   // elements...
01189   nemhelper->write_elements(mesh);
01190 
01191   // Call our specialized function to write the nodesets
01192   nemhelper->write_nodesets(mesh);
01193 
01194   // Call our specialized write_sidesets() function to write the sidesets to file
01195   nemhelper->write_sidesets(mesh);
01196 
01197   // Not sure if this is really necessary, but go ahead and flush the file
01198   // once we have written all this stuff.
01199   nemhelper->ex_err = exII::ex_update(nemhelper->ex_id);
01200 
01201   if( (mesh.get_boundary_info().n_edge_conds() > 0) &&
01202       _verbose )
01203     {
01204       libMesh::out << "Warning: Mesh contains edge boundary IDs, but these "
01205                    << "are not supported by the Nemesis format."
01206                    << std::endl;
01207     }
01208 }
01209 
01210 #else
01211 
01212 void Nemesis_IO::write (const std::string& )
01213 {
01214   libmesh_error_msg("ERROR, Nemesis API is not defined!");
01215 }
01216 
01217 #endif // #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
01218 
01219 
01220 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
01221 
01222 void Nemesis_IO::write_timestep (const std::string& fname,
01223                                  const EquationSystems& es,
01224                                  const int timestep,
01225                                  const Real time)
01226 {
01227   _timestep=timestep;
01228   write_equation_systems(fname,es);
01229 
01230   nemhelper->write_timestep(timestep, time);
01231 }
01232 
01233 #else
01234 
01235 void Nemesis_IO::write_timestep (const std::string&,
01236                                  const EquationSystems&,
01237                                  const int,
01238                                  const Real)
01239 {
01240   libmesh_error_msg("ERROR, Nemesis API is not defined!");
01241 }
01242 
01243 #endif // #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
01244 
01245 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
01246 
01247 void Nemesis_IO::write_nodal_data (const std::string& base_filename,
01248                                    const std::vector<Number>& soln,
01249                                    const std::vector<std::string>& names)
01250 {
01251   START_LOG("write_nodal_data()", "Nemesis_IO");
01252 
01253   const MeshBase & mesh = MeshOutput<MeshBase>::mesh();
01254 
01255   std::string nemesis_filename = nemhelper->construct_nemesis_filename(base_filename);
01256 
01257   if (!nemhelper->opened_for_writing)
01258     {
01259       // If we're appending, open() the file with read_only=false,
01260       // otherwise create() it and write the contents of the mesh to
01261       // it.
01262       if (_append)
01263         {
01264           nemhelper->open(nemesis_filename.c_str(), /*read_only=*/false);
01265           // After opening the file, read the header so that certain
01266           // fields, such as the number of nodes and the number of
01267           // elements, are correctly initialized for the subsequent
01268           // call to write the nodal solution.
01269           nemhelper->read_header();
01270         }
01271       else
01272         {
01273           nemhelper->create(nemesis_filename);
01274           nemhelper->initialize(nemesis_filename,mesh);
01275           nemhelper->write_nodal_coordinates(mesh);
01276           nemhelper->write_elements(mesh);
01277           nemhelper->write_nodesets(mesh);
01278           nemhelper->write_sidesets(mesh);
01279 
01280           if( (mesh.get_boundary_info().n_edge_conds() > 0) &&
01281               _verbose )
01282             {
01283               libMesh::out << "Warning: Mesh contains edge boundary IDs, but these "
01284                            << "are not supported by the ExodusII format."
01285                            << std::endl;
01286             }
01287 
01288           // If we don't have any nodes written out on this processor,
01289           // Exodus seems to like us better if we don't try to write out any
01290           // variable names too...
01291 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
01292 
01293           std::vector<std::string> complex_names = nemhelper->get_complex_names(names);
01294 
01295           nemhelper->initialize_nodal_variables(complex_names);
01296 #else
01297           nemhelper->initialize_nodal_variables(names);
01298 #endif
01299         }
01300     }
01301 
01302   nemhelper->write_nodal_solution(soln, names, _timestep);
01303 
01304   STOP_LOG("write_nodal_data()", "Nemesis_IO");
01305 }
01306 
01307 #else
01308 
01309 void Nemesis_IO::write_nodal_data (const std::string& ,
01310                                    const std::vector<Number>& ,
01311                                    const std::vector<std::string>& )
01312 {
01313   libmesh_error_msg("ERROR, Nemesis API is not defined.");
01314 }
01315 
01316 
01317 #endif // #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
01318 
01319 
01320 
01321 
01322 
01323 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
01324 
01325 void Nemesis_IO::write_global_data (const std::vector<Number>& soln,
01326                                     const std::vector<std::string>& names)
01327 {
01328   if (!nemhelper->opened_for_writing)
01329     libmesh_error_msg("ERROR, Nemesis file must be initialized before outputting global variables.");
01330 
01331 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
01332 
01333   std::vector<std::string> complex_names = nemhelper->get_complex_names(names);
01334 
01335   nemhelper->initialize_global_variables(complex_names);
01336 
01337   unsigned int num_values = soln.size();
01338   unsigned int num_vars = names.size();
01339   unsigned int num_elems = num_values / num_vars;
01340 
01341   // This will contain the real and imaginary parts and the magnitude
01342   // of the values in soln
01343   std::vector<Real> complex_soln(3*num_values);
01344 
01345   for (unsigned i=0; i<num_vars; ++i)
01346     {
01347       for (unsigned int j=0; j<num_elems; ++j)
01348         {
01349           Number value = soln[i*num_vars + j];
01350           complex_soln[3*i*num_elems + j] = value.real();
01351         }
01352       for (unsigned int j=0; j<num_elems; ++j)
01353         {
01354           Number value = soln[i*num_vars + j];
01355           complex_soln[3*i*num_elems + num_elems +j] = value.imag();
01356         }
01357       for (unsigned int j=0; j<num_elems; ++j)
01358         {
01359           Number value = soln[i*num_vars + j];
01360           complex_soln[3*i*num_elems + 2*num_elems + j] = std::abs(value);
01361         }
01362     }
01363 
01364   nemhelper->write_global_values(complex_soln, _timestep);
01365 
01366 #else
01367 
01368   // Call the Exodus writer implementation
01369   nemhelper->initialize_global_variables( names );
01370   nemhelper->write_global_values( soln, _timestep);
01371 
01372 #endif
01373 
01374 }
01375 
01376 #else
01377 
01378 void Nemesis_IO::write_global_data (const std::vector<Number>&,
01379                                     const std::vector<std::string>&)
01380 {
01381   libmesh_error_msg("ERROR, Nemesis API is not defined.");
01382 }
01383 
01384 #endif // #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
01385 
01386 
01387 
01388 #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
01389 
01390 void Nemesis_IO::write_information_records (const std::vector<std::string>& records)
01391 {
01392   if (!nemhelper->opened_for_writing)
01393     libmesh_error_msg("ERROR, Nemesis file must be initialized before outputting information records.");
01394 
01395   // Call the Exodus writer implementation
01396   nemhelper->write_information_records( records );
01397 }
01398 
01399 
01400 #else
01401 
01402 void Nemesis_IO::write_information_records ( const std::vector<std::string>& )
01403 {
01404   libmesh_error_msg("ERROR, Nemesis API is not defined.");
01405 }
01406 
01407 #endif // #if defined(LIBMESH_HAVE_EXODUS_API) && defined(LIBMESH_HAVE_NEMESIS_API)
01408 
01409 } // namespace libMesh