$extrastylesheet
nemesis_io_helper.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++ headers
00020 #include <iomanip>
00021 #include <set>
00022 #include <sstream>
00023 
00024 // Libmesh headers
00025 #include "libmesh/nemesis_io_helper.h"
00026 #include "libmesh/node.h"
00027 #include "libmesh/elem.h"
00028 #include "libmesh/boundary_info.h"
00029 #include "libmesh/parallel.h"
00030 
00031 #if defined(LIBMESH_HAVE_NEMESIS_API) && defined(LIBMESH_HAVE_EXODUS_API)
00032 
00033 namespace libMesh
00034 {
00035 
00036 
00037 // Initialize the various integer members to zero.  We can check
00038 // these later to see if they've been properly initialized...
00039 // The parent ExodusII_IO_Helper is created with the run_only_on_proc0
00040 // flag set to false, so that we can make use of its functionality
00041 // on multiple processors.
00042 Nemesis_IO_Helper::Nemesis_IO_Helper(const ParallelObject &parent,
00043                                      bool verbose_in, bool single_precision) :
00044   ExodusII_IO_Helper(parent, verbose_in, /*run_only_on_proc0=*/false, /*single_precision=*/single_precision),
00045   nemesis_err_flag(0),
00046   num_nodes_global(0),
00047   num_elems_global(0),
00048   num_elem_blks_global(0),
00049   num_node_sets_global(0),
00050   num_side_sets_global(0),
00051   num_proc(0),
00052   num_proc_in_file(0),
00053   ftype('\0'),
00054   num_internal_nodes(0),
00055   num_border_nodes(0),
00056   num_external_nodes(0),
00057   num_internal_elems(0),
00058   num_border_elems(0),
00059   num_node_cmaps(0),
00060   num_elem_cmaps(0)
00061 {
00062   // Warn about using untested code!
00063   libmesh_experimental();
00064 }
00065 
00066 
00067 Nemesis_IO_Helper::~Nemesis_IO_Helper()
00068 {
00069   // Our destructor is called from Nemesis_IO.  We close the Exodus file here since we have
00070   // responsibility for managing the file's lifetime.
00071   this->ex_err = exII::ex_update(this->ex_id);
00072   EX_EXCEPTIONLESS_CHECK_ERR(ex_err, "Error flushing buffers to file.");
00073   this->close();
00074 }
00075 
00076 
00077 
00078 void Nemesis_IO_Helper::get_init_global()
00079 {
00080   nemesis_err_flag =
00081     Nemesis::ne_get_init_global(ex_id,
00082                                 &num_nodes_global,
00083                                 &num_elems_global,
00084                                 &num_elem_blks_global,
00085                                 &num_node_sets_global,
00086                                 &num_side_sets_global);
00087   EX_CHECK_ERR(nemesis_err_flag, "Error reading initial global data!");
00088 
00089   if (verbose)
00090     {
00091       libMesh::out << "[" << this->processor_id() << "] " << "num_nodes_global=" << num_nodes_global << std::endl;
00092       libMesh::out << "[" << this->processor_id() << "] " << "num_elems_global=" << num_elems_global << std::endl;
00093       libMesh::out << "[" << this->processor_id() << "] " << "num_elem_blks_global=" << num_elem_blks_global << std::endl;
00094       libMesh::out << "[" << this->processor_id() << "] " << "num_node_sets_global=" << num_node_sets_global << std::endl;
00095       libMesh::out << "[" << this->processor_id() << "] " << "num_side_sets_global=" << num_side_sets_global << std::endl;
00096     }
00097 }
00098 
00099 
00100 
00101 void Nemesis_IO_Helper::get_ss_param_global()
00102 {
00103   if (num_side_sets_global > 0)
00104     {
00105       global_sideset_ids.resize(num_side_sets_global);
00106       num_global_side_counts.resize(num_side_sets_global);
00107 
00108       // df = "distribution factor", not really sure what that is.  I don't yet have a file
00109       // which has distribution factors so I guess we'll worry about it later...
00110       num_global_side_df_counts.resize(num_side_sets_global);
00111 
00112       nemesis_err_flag =
00113         Nemesis::ne_get_ss_param_global(ex_id,
00114                                         global_sideset_ids.empty()        ? NULL : &global_sideset_ids[0],
00115                                         num_global_side_counts.empty()    ? NULL : &num_global_side_counts[0],
00116                                         num_global_side_df_counts.empty() ? NULL : &num_global_side_df_counts[0]);
00117       EX_CHECK_ERR(nemesis_err_flag, "Error reading global sideset parameters!");
00118 
00119       if (verbose)
00120         {
00121           libMesh::out << "[" << this->processor_id() << "] " << "Global Sideset IDs, Side Counts, and DF counts:" << std::endl;
00122           for (unsigned int bn=0; bn<global_sideset_ids.size(); ++bn)
00123             {
00124               libMesh::out << "  [" << this->processor_id() << "] "
00125                            << "global_sideset_ids["<<bn<<"]=" << global_sideset_ids[bn]
00126                            << ", num_global_side_counts["<<bn<<"]=" << num_global_side_counts[bn]
00127                            << ", num_global_side_df_counts["<<bn<<"]=" << num_global_side_df_counts[bn]
00128                            << std::endl;
00129             }
00130         }
00131     }
00132 }
00133 
00134 
00135 
00136 
00137 void Nemesis_IO_Helper::get_ns_param_global()
00138 {
00139   if (num_node_sets_global > 0)
00140     {
00141       global_nodeset_ids.resize(num_node_sets_global);
00142       num_global_node_counts.resize(num_node_sets_global);
00143       num_global_node_df_counts.resize(num_node_sets_global);
00144 
00145       nemesis_err_flag =
00146         Nemesis::ne_get_ns_param_global(ex_id,
00147                                         global_nodeset_ids.empty()        ? NULL : &global_nodeset_ids[0],
00148                                         num_global_node_counts.empty()    ? NULL : &num_global_node_counts[0],
00149                                         num_global_node_df_counts.empty() ? NULL : &num_global_node_df_counts[0]);
00150       EX_CHECK_ERR(nemesis_err_flag, "Error reading global nodeset parameters!");
00151 
00152       if (verbose)
00153         {
00154           libMesh::out << "[" << this->processor_id() << "] " << "Global Nodeset IDs, Node Counts, and DF counts:" << std::endl;
00155           for (unsigned int bn=0; bn<global_nodeset_ids.size(); ++bn)
00156             {
00157               libMesh::out << "  [" << this->processor_id() << "] "
00158                            << "global_nodeset_ids["<<bn<<"]=" << global_nodeset_ids[bn]
00159                            << ", num_global_node_counts["<<bn<<"]=" << num_global_node_counts[bn]
00160                            << ", num_global_node_df_counts["<<bn<<"]=" << num_global_node_df_counts[bn]
00161                            << std::endl;
00162             }
00163         }
00164     }
00165 }
00166 
00167 
00168 
00169 void Nemesis_IO_Helper::get_eb_info_global()
00170 {
00171   global_elem_blk_ids.resize(num_elem_blks_global);
00172   global_elem_blk_cnts.resize(num_elem_blks_global);
00173 
00174   nemesis_err_flag =
00175     Nemesis::ne_get_eb_info_global(ex_id,
00176                                    global_elem_blk_ids.empty()  ? NULL : &global_elem_blk_ids[0],
00177                                    global_elem_blk_cnts.empty() ? NULL : &global_elem_blk_cnts[0]);
00178   EX_CHECK_ERR(nemesis_err_flag, "Error reading global element block info!");
00179 
00180   if (verbose)
00181     {
00182       libMesh::out << "[" << this->processor_id() << "] " << "Global Element Block IDs and Counts:" << std::endl;
00183       for (unsigned int bn=0; bn<global_elem_blk_ids.size(); ++bn)
00184         {
00185           libMesh::out << "  [" << this->processor_id() << "] "
00186                        << "global_elem_blk_ids["<<bn<<"]=" << global_elem_blk_ids[bn]
00187                        << ", global_elem_blk_cnts["<<bn<<"]=" << global_elem_blk_cnts[bn]
00188                        << std::endl;
00189         }
00190     }
00191 }
00192 
00193 
00194 
00195 void Nemesis_IO_Helper::get_init_info()
00196 {
00197   nemesis_err_flag =
00198     Nemesis::ne_get_init_info(ex_id,
00199                               &num_proc,
00200                               &num_proc_in_file,
00201                               &ftype);
00202   EX_CHECK_ERR(nemesis_err_flag, "Error reading initial info!");
00203 
00204   if (verbose)
00205     {
00206       libMesh::out << "[" << this->processor_id() << "] " << "num_proc=" << num_proc << std::endl;
00207       libMesh::out << "[" << this->processor_id() << "] " << "num_proc_in_file=" << num_proc_in_file << std::endl;
00208       libMesh::out << "[" << this->processor_id() << "] " << "ftype=" << ftype << std::endl;
00209     }
00210 }
00211 
00212 
00213 
00214 void Nemesis_IO_Helper::get_loadbal_param()
00215 {
00216   nemesis_err_flag =
00217     Nemesis::ne_get_loadbal_param(ex_id,
00218                                   &num_internal_nodes,
00219                                   &num_border_nodes,
00220                                   &num_external_nodes,
00221                                   &num_internal_elems,
00222                                   &num_border_elems,
00223                                   &num_node_cmaps,
00224                                   &num_elem_cmaps,
00225                                   this->processor_id() // The ID of the processor for which info is to be read
00226                                   );
00227   EX_CHECK_ERR(nemesis_err_flag, "Error reading load balance parameters!");
00228 
00229 
00230   if (verbose)
00231     {
00232       libMesh::out << "[" << this->processor_id() << "] " << "num_internal_nodes=" << num_internal_nodes << std::endl;
00233       libMesh::out << "[" << this->processor_id() << "] " << "num_border_nodes=" << num_border_nodes << std::endl;
00234       libMesh::out << "[" << this->processor_id() << "] " << "num_external_nodes=" << num_external_nodes << std::endl;
00235       libMesh::out << "[" << this->processor_id() << "] " << "num_internal_elems=" << num_internal_elems << std::endl;
00236       libMesh::out << "[" << this->processor_id() << "] " << "num_border_elems=" << num_border_elems << std::endl;
00237       libMesh::out << "[" << this->processor_id() << "] " << "num_node_cmaps=" << num_node_cmaps << std::endl;
00238       libMesh::out << "[" << this->processor_id() << "] " << "num_elem_cmaps=" << num_elem_cmaps << std::endl;
00239     }
00240 }
00241 
00242 
00243 
00244 void Nemesis_IO_Helper::get_elem_map()
00245 {
00246   elem_mapi.resize(num_internal_elems);
00247   elem_mapb.resize(num_border_elems);
00248 
00249   nemesis_err_flag =
00250     Nemesis::ne_get_elem_map(ex_id,
00251                              elem_mapi.empty() ? NULL : &elem_mapi[0],
00252                              elem_mapb.empty() ? NULL : &elem_mapb[0],
00253                              this->processor_id()
00254                              );
00255   EX_CHECK_ERR(nemesis_err_flag, "Error reading element maps!");
00256 
00257 
00258   if (verbose)
00259     {
00260       // These are not contiguous ranges....
00261       //libMesh::out << "[" << this->processor_id() << "] " << "first interior elem id=" << elem_mapi[0] << std::endl;
00262       //libMesh::out << "[" << this->processor_id() << "] " << "last interior elem id=" << elem_mapi.back() << std::endl;
00263       //libMesh::out << "[" << this->processor_id() << "] " << "first boundary elem id=" << elem_mapb[0] << std::endl;
00264       //libMesh::out << "[" << this->processor_id() << "] " << "last boundary elem id=" << elem_mapb.back() << std::endl;
00265       libMesh::out << "[" << this->processor_id() << "] elem_mapi[i] = ";
00266       for (unsigned int i=0; i< static_cast<unsigned int>(num_internal_elems-1); ++i)
00267         libMesh::out << elem_mapi[i] << ", ";
00268       libMesh::out << "... " << elem_mapi.back() << std::endl;
00269 
00270       libMesh::out << "[" << this->processor_id() << "] elem_mapb[i] = ";
00271       for (unsigned int i=0; i< static_cast<unsigned int>(std::min(10, num_border_elems-1)); ++i)
00272         libMesh::out << elem_mapb[i] << ", ";
00273       libMesh::out << "... " << elem_mapb.back() << std::endl;
00274     }
00275 }
00276 
00277 
00278 
00279 
00280 void Nemesis_IO_Helper::get_node_map()
00281 {
00282   node_mapi.resize(num_internal_nodes);
00283   node_mapb.resize(num_border_nodes);
00284   node_mape.resize(num_external_nodes);
00285 
00286   nemesis_err_flag =
00287     Nemesis::ne_get_node_map(ex_id,
00288                              node_mapi.empty() ? NULL : &node_mapi[0],
00289                              node_mapb.empty() ? NULL : &node_mapb[0],
00290                              node_mape.empty() ? NULL : &node_mape[0],
00291                              this->processor_id()
00292                              );
00293   EX_CHECK_ERR(nemesis_err_flag, "Error reading node maps!");
00294 
00295   if (verbose)
00296     {
00297       // Remark: The Exodus/Nemesis node numbring is always (?) 1-based!  This means the first interior node id will
00298       // always be == 1.
00299       libMesh::out << "[" << this->processor_id() << "] " << "first interior node id=" << node_mapi[0] << std::endl;
00300       libMesh::out << "[" << this->processor_id() << "] " << "last interior node id=" << node_mapi.back() << std::endl;
00301 
00302       libMesh::out << "[" << this->processor_id() << "] " << "first boundary node id=" << node_mapb[0] << std::endl;
00303       libMesh::out << "[" << this->processor_id() << "] " << "last boundary node id=" << node_mapb.back() << std::endl;
00304 
00305       // The number of external nodes is sometimes zero, don't try to access
00306       // node_mape.back() in this case!
00307       if (num_external_nodes > 0)
00308         {
00309           libMesh::out << "[" << this->processor_id() << "] " << "first external node id=" << node_mape[0] << std::endl;
00310           libMesh::out << "[" << this->processor_id() << "] " << "last external node id=" << node_mape.back() << std::endl;
00311         }
00312     }
00313 }
00314 
00315 
00316 
00317 void Nemesis_IO_Helper::get_cmap_params()
00318 {
00319   node_cmap_ids.resize(num_node_cmaps);
00320   node_cmap_node_cnts.resize(num_node_cmaps);
00321   elem_cmap_ids.resize(num_elem_cmaps);
00322   elem_cmap_elem_cnts.resize(num_elem_cmaps);
00323 
00324   nemesis_err_flag =
00325     Nemesis::ne_get_cmap_params(ex_id,
00326                                 node_cmap_ids.empty()       ? NULL : &node_cmap_ids[0],
00327                                 node_cmap_node_cnts.empty() ? NULL : &node_cmap_node_cnts[0],
00328                                 elem_cmap_ids.empty()       ? NULL : &elem_cmap_ids[0],
00329                                 elem_cmap_elem_cnts.empty() ? NULL : &elem_cmap_elem_cnts[0],
00330                                 this->processor_id());
00331   EX_CHECK_ERR(nemesis_err_flag, "Error reading cmap parameters!");
00332 
00333 
00334   if (verbose)
00335     {
00336       libMesh::out << "[" << this->processor_id() << "] ";
00337       for (unsigned int i=0; i<node_cmap_ids.size(); ++i)
00338         libMesh::out << "node_cmap_ids["<<i<<"]=" << node_cmap_ids[i] << " ";
00339       libMesh::out << std::endl;
00340 
00341       libMesh::out << "[" << this->processor_id() << "] ";
00342       for (unsigned int i=0; i<node_cmap_node_cnts.size(); ++i)
00343         libMesh::out << "node_cmap_node_cnts["<<i<<"]=" << node_cmap_node_cnts[i] << " ";
00344       libMesh::out << std::endl;
00345 
00346       libMesh::out << "[" << this->processor_id() << "] ";
00347       for (unsigned int i=0; i<elem_cmap_ids.size(); ++i)
00348         libMesh::out << "elem_cmap_ids["<<i<<"]=" << elem_cmap_ids[i] << " ";
00349       libMesh::out << std::endl;
00350 
00351       libMesh::out << "[" << this->processor_id() << "] ";
00352       for (unsigned int i=0; i<elem_cmap_elem_cnts.size(); ++i)
00353         libMesh::out << "elem_cmap_elem_cnts["<<i<<"]=" << elem_cmap_elem_cnts[i] << " ";
00354       libMesh::out << std::endl;
00355     }
00356 }
00357 
00358 
00359 
00360 void Nemesis_IO_Helper::get_node_cmap()
00361 {
00362   node_cmap_node_ids.resize(num_node_cmaps);
00363   node_cmap_proc_ids.resize(num_node_cmaps);
00364 
00365   for (unsigned int i=0; i<node_cmap_node_ids.size(); ++i)
00366     {
00367       node_cmap_node_ids[i].resize(node_cmap_node_cnts[i]);
00368       node_cmap_proc_ids[i].resize(node_cmap_node_cnts[i]);
00369 
00370       nemesis_err_flag =
00371         Nemesis::ne_get_node_cmap(ex_id,
00372                                   node_cmap_ids.empty()         ? 0    : node_cmap_ids[i],
00373                                   node_cmap_node_ids[i].empty() ? NULL : &node_cmap_node_ids[i][0],
00374                                   node_cmap_proc_ids[i].empty() ? NULL : &node_cmap_proc_ids[i][0],
00375                                   this->processor_id());
00376       EX_CHECK_ERR(nemesis_err_flag, "Error reading node cmap node and processor ids!");
00377 
00378       if (verbose)
00379         {
00380           libMesh::out << "[" << this->processor_id() << "] node_cmap_node_ids["<<i<<"]=";
00381           for (unsigned int j=0; j<node_cmap_node_ids[i].size(); ++j)
00382             libMesh::out << node_cmap_node_ids[i][j] << " ";
00383           libMesh::out << std::endl;
00384 
00385           // This is basically a vector, all entries of which are = node_cmap_ids[i]
00386           // Not sure if it's always guaranteed to be that or what...
00387           libMesh::out << "[" << this->processor_id() << "] node_cmap_proc_ids["<<i<<"]=";
00388           for (unsigned int j=0; j<node_cmap_proc_ids[i].size(); ++j)
00389             libMesh::out << node_cmap_proc_ids[i][j] << " ";
00390           libMesh::out << std::endl;
00391         }
00392     }
00393 }
00394 
00395 
00396 
00397 void Nemesis_IO_Helper::get_elem_cmap()
00398 {
00399   elem_cmap_elem_ids.resize(num_elem_cmaps);
00400   elem_cmap_side_ids.resize(num_elem_cmaps);
00401   elem_cmap_proc_ids.resize(num_elem_cmaps);
00402 
00403   for (unsigned int i=0; i<elem_cmap_elem_ids.size(); ++i)
00404     {
00405       elem_cmap_elem_ids[i].resize(elem_cmap_elem_cnts[i]);
00406       elem_cmap_side_ids[i].resize(elem_cmap_elem_cnts[i]);
00407       elem_cmap_proc_ids[i].resize(elem_cmap_elem_cnts[i]);
00408 
00409       nemesis_err_flag =
00410         Nemesis::ne_get_elem_cmap(ex_id,
00411                                   elem_cmap_ids.empty()         ? 0    : elem_cmap_ids[i],
00412                                   elem_cmap_elem_ids[i].empty() ? NULL : &elem_cmap_elem_ids[i][0],
00413                                   elem_cmap_side_ids[i].empty() ? NULL : &elem_cmap_side_ids[i][0],
00414                                   elem_cmap_proc_ids[i].empty() ? NULL : &elem_cmap_proc_ids[i][0],
00415                                   this->processor_id());
00416       EX_CHECK_ERR(nemesis_err_flag, "Error reading elem cmap elem, side, and processor ids!");
00417 
00418 
00419       if (verbose)
00420         {
00421           libMesh::out << "[" << this->processor_id() << "] elem_cmap_elem_ids["<<i<<"]=";
00422           for (unsigned int j=0; j<elem_cmap_elem_ids[i].size(); ++j)
00423             libMesh::out << elem_cmap_elem_ids[i][j] << " ";
00424           libMesh::out << std::endl;
00425 
00426           // These must be the (local) side IDs (in the ExodusII face numbering scheme)
00427           // of the sides shared across processors.
00428           libMesh::out << "[" << this->processor_id() << "] elem_cmap_side_ids["<<i<<"]=";
00429           for (unsigned int j=0; j<elem_cmap_side_ids[i].size(); ++j)
00430             libMesh::out << elem_cmap_side_ids[i][j] << " ";
00431           libMesh::out << std::endl;
00432 
00433           // This is basically a vector, all entries of which are = elem_cmap_ids[i]
00434           // Not sure if it's always guaranteed to be that or what...
00435           libMesh::out << "[" << this->processor_id() << "] elem_cmap_proc_ids["<<i<<"]=";
00436           for (unsigned int j=0; j<elem_cmap_proc_ids[i].size(); ++j)
00437             libMesh::out << elem_cmap_proc_ids[i][j] << " ";
00438           libMesh::out << std::endl;
00439         }
00440     }
00441 }
00442 
00443 
00444 
00445 
00446 void Nemesis_IO_Helper::put_init_info(unsigned num_proc_in,
00447                                       unsigned num_proc_in_file_in,
00448                                       const char* ftype_in)
00449 {
00450   nemesis_err_flag =
00451     Nemesis::ne_put_init_info(ex_id,
00452                               num_proc_in,
00453                               num_proc_in_file_in,
00454                               const_cast<char*>(ftype_in));
00455 
00456   EX_CHECK_ERR(nemesis_err_flag, "Error writing initial information!");
00457 }
00458 
00459 
00460 
00461 
00462 void Nemesis_IO_Helper::put_init_global(dof_id_type num_nodes_global_in,
00463                                         dof_id_type num_elems_global_in,
00464                                         unsigned num_elem_blks_global_in,
00465                                         unsigned num_node_sets_global_in,
00466                                         unsigned num_side_sets_global_in)
00467 {
00468   nemesis_err_flag =
00469     Nemesis::ne_put_init_global(ex_id,
00470                                 num_nodes_global_in,
00471                                 num_elems_global_in,
00472                                 num_elem_blks_global_in,
00473                                 num_node_sets_global_in,
00474                                 num_side_sets_global_in);
00475 
00476   EX_CHECK_ERR(nemesis_err_flag, "Error writing initial global data!");
00477 }
00478 
00479 
00480 
00481 void Nemesis_IO_Helper::put_eb_info_global(std::vector<int>& global_elem_blk_ids_in,
00482                                            std::vector<int>& global_elem_blk_cnts_in)
00483 {
00484   nemesis_err_flag =
00485     Nemesis::ne_put_eb_info_global(ex_id,
00486                                    &global_elem_blk_ids_in[0],
00487                                    &global_elem_blk_cnts_in[0]);
00488 
00489   EX_CHECK_ERR(nemesis_err_flag, "Error writing global element block information!");
00490 }
00491 
00492 
00493 
00494 
00495 void Nemesis_IO_Helper::put_ns_param_global(std::vector<int>& global_nodeset_ids_in,
00496                                             std::vector<int>& num_global_node_counts_in,
00497                                             std::vector<int>& num_global_node_df_counts_in)
00498 {
00499   // Only add nodesets if there are some
00500   if(global_nodeset_ids.size())
00501     {
00502       nemesis_err_flag =
00503         Nemesis::ne_put_ns_param_global(ex_id,
00504                                         &global_nodeset_ids_in[0],
00505                                         &num_global_node_counts_in[0],
00506                                         &num_global_node_df_counts_in[0]);
00507     }
00508 
00509   EX_CHECK_ERR(nemesis_err_flag, "Error writing global nodeset parameters!");
00510 }
00511 
00512 
00513 
00514 
00515 void Nemesis_IO_Helper::put_ss_param_global(std::vector<int>& global_sideset_ids_in,
00516                                             std::vector<int>& num_global_side_counts_in,
00517                                             std::vector<int>& num_global_side_df_counts_in)
00518 {
00519   // Only add sidesets if there are some
00520   if(global_sideset_ids.size())
00521     {
00522       nemesis_err_flag =
00523         Nemesis::ne_put_ss_param_global(ex_id,
00524                                         &global_sideset_ids_in[0],
00525                                         &num_global_side_counts_in[0],
00526                                         &num_global_side_df_counts_in[0]);
00527     }
00528 
00529   EX_CHECK_ERR(nemesis_err_flag, "Error writing global sideset parameters!");
00530 }
00531 
00532 
00533 
00534 
00535 void Nemesis_IO_Helper::put_loadbal_param(unsigned num_internal_nodes_in,
00536                                           unsigned num_border_nodes_in,
00537                                           unsigned num_external_nodes_in,
00538                                           unsigned num_internal_elems_in,
00539                                           unsigned num_border_elems_in,
00540                                           unsigned num_node_cmaps_in,
00541                                           unsigned num_elem_cmaps_in)
00542 {
00543   nemesis_err_flag =
00544     Nemesis::ne_put_loadbal_param(ex_id,
00545                                   num_internal_nodes_in,
00546                                   num_border_nodes_in,
00547                                   num_external_nodes_in,
00548                                   num_internal_elems_in,
00549                                   num_border_elems_in,
00550                                   num_node_cmaps_in,
00551                                   num_elem_cmaps_in,
00552                                   this->processor_id());
00553 
00554   EX_CHECK_ERR(nemesis_err_flag, "Error writing loadbal parameters!");
00555 }
00556 
00557 
00558 
00559 
00560 
00561 void Nemesis_IO_Helper::put_cmap_params(std::vector<int>& node_cmap_ids_in,
00562                                         std::vector<int>& node_cmap_node_cnts_in,
00563                                         std::vector<int>& elem_cmap_ids_in,
00564                                         std::vector<int>& elem_cmap_elem_cnts_in)
00565 {
00566   // We might not have cmaps on every processor in some corner
00567   // cases
00568   if(node_cmap_ids.size())
00569     {
00570       nemesis_err_flag =
00571         Nemesis::ne_put_cmap_params(ex_id,
00572                                     &node_cmap_ids_in[0],
00573                                     &node_cmap_node_cnts_in[0],
00574                                     &elem_cmap_ids_in[0],
00575                                     &elem_cmap_elem_cnts_in[0],
00576                                     this->processor_id());
00577     }
00578 
00579   EX_CHECK_ERR(nemesis_err_flag, "Error writing cmap parameters!");
00580 }
00581 
00582 
00583 
00584 
00585 void Nemesis_IO_Helper::put_node_cmap(std::vector<std::vector<int> >& node_cmap_node_ids_in,
00586                                       std::vector<std::vector<int> >& node_cmap_proc_ids_in)
00587 {
00588 
00589   // Print to screen what we are about to print to Nemesis file
00590   if (verbose)
00591     {
00592       for (unsigned i=0; i<node_cmap_node_ids_in.size(); ++i)
00593         {
00594           libMesh::out << "[" << this->processor_id() << "] put_node_cmap() : nodes communicated to proc "
00595                        << this->node_cmap_ids[i]
00596                        << " = ";
00597           for (unsigned j=0; j<node_cmap_node_ids_in[i].size(); ++j)
00598             libMesh::out << node_cmap_node_ids_in[i][j] << " ";
00599           libMesh::out << std::endl;
00600         }
00601 
00602       for (unsigned i=0; i<node_cmap_node_ids_in.size(); ++i)
00603         {
00604           libMesh::out << "[" << this->processor_id() << "] put_node_cmap() : processor IDs = ";
00605           for (unsigned j=0; j<node_cmap_proc_ids_in[i].size(); ++j)
00606             libMesh::out << node_cmap_proc_ids_in[i][j] << " ";
00607           libMesh::out << std::endl;
00608         }
00609     }
00610 
00611   for (unsigned int i=0; i<node_cmap_node_ids_in.size(); ++i)
00612     {
00613       nemesis_err_flag =
00614         Nemesis::ne_put_node_cmap(ex_id,
00615                                   this->node_cmap_ids[i],
00616                                   &node_cmap_node_ids_in[i][0],
00617                                   &node_cmap_proc_ids_in[i][0],
00618                                   this->processor_id());
00619 
00620       EX_CHECK_ERR(nemesis_err_flag, "Error writing node communication map to file!");
00621     }
00622 }
00623 
00624 
00625 
00626 
00627 void Nemesis_IO_Helper::put_node_map(std::vector<int>& node_mapi_in,
00628                                      std::vector<int>& node_mapb_in,
00629                                      std::vector<int>& node_mape_in)
00630 {
00631   nemesis_err_flag =
00632     Nemesis::ne_put_node_map(ex_id,
00633                              node_mapi_in.empty() ? NULL : &node_mapi_in[0],
00634                              node_mapb_in.empty() ? NULL : &node_mapb_in[0],
00635                              node_mape_in.empty() ? NULL : &node_mape_in[0], // Don't take address of empty vector...
00636                              this->processor_id());
00637 
00638   EX_CHECK_ERR(nemesis_err_flag, "Error writing Nemesis internal and border node maps to file!");
00639 }
00640 
00641 
00642 
00643 
00644 void Nemesis_IO_Helper::put_elem_cmap(std::vector<std::vector<int> >& elem_cmap_elem_ids_in,
00645                                       std::vector<std::vector<int> >& elem_cmap_side_ids_in,
00646                                       std::vector<std::vector<int> >& elem_cmap_proc_ids_in)
00647 {
00648   for (unsigned int i=0; i<elem_cmap_ids.size(); ++i)
00649     {
00650       nemesis_err_flag =
00651         Nemesis::ne_put_elem_cmap(ex_id,
00652                                   this->elem_cmap_ids[i],
00653                                   &elem_cmap_elem_ids_in[i][0],
00654                                   &elem_cmap_side_ids_in[i][0],
00655                                   &elem_cmap_proc_ids_in[i][0],
00656                                   this->processor_id());
00657 
00658       EX_CHECK_ERR(nemesis_err_flag, "Error writing elem communication map to file!");
00659     }
00660 }
00661 
00662 
00663 
00664 
00665 void Nemesis_IO_Helper::put_elem_map(std::vector<int>& elem_mapi_in,
00666                                      std::vector<int>& elem_mapb_in)
00667 {
00668   nemesis_err_flag =
00669     Nemesis::ne_put_elem_map(ex_id,
00670                              elem_mapi_in.empty() ? NULL : &elem_mapi_in[0],
00671                              elem_mapb_in.empty() ? NULL : &elem_mapb_in[0],
00672                              this->processor_id());
00673 
00674   EX_CHECK_ERR(nemesis_err_flag, "Error writing Nemesis internal and border element maps to file!");
00675 }
00676 
00677 
00678 
00679 
00680 
00681 
00682 void Nemesis_IO_Helper::put_n_coord(unsigned start_node_num,
00683                                     unsigned num_nodes_in,
00684                                     std::vector<Real>& x_coor,
00685                                     std::vector<Real>& y_coor,
00686                                     std::vector<Real>& z_coor)
00687 {
00688   nemesis_err_flag =
00689     Nemesis::ne_put_n_coord(ex_id,
00690                             start_node_num,
00691                             num_nodes_in,
00692                             &x_coor[0],
00693                             &y_coor[0],
00694                             &z_coor[0]);
00695 
00696   EX_CHECK_ERR(nemesis_err_flag, "Error writing coords to file!");
00697 }
00698 
00699 
00700 
00701 
00702 
00703 
00704 
00705 
00706 // Note: we can't reuse the ExodusII_IO_Helper code directly, since it only runs
00707 // on processor 0.  TODO: We could have the body of this function as a separate
00708 // function and then ExodusII_IO_Helper would only call it if on processor 0...
00709 void Nemesis_IO_Helper::create(std::string filename)
00710 {
00711   // Fall back on double precision when necessary since ExodusII
00712   // doesn't seem to support long double
00713   int
00714     comp_ws = 0,
00715     io_ws = 0;
00716 
00717   if(_single_precision)
00718     {
00719       comp_ws = sizeof(float);
00720       io_ws = sizeof(float);
00721     }
00722   else
00723     {
00724       comp_ws = cast_int<int>(std::min(sizeof(Real), sizeof(double)));
00725       io_ws = cast_int<int>(std::min(sizeof(Real), sizeof(double)));
00726     }
00727 
00728   this->ex_id = exII::ex_create(filename.c_str(), EX_CLOBBER, &comp_ws, &io_ws);
00729 
00730   EX_CHECK_ERR(ex_id, "Error creating Nemesis mesh file.");
00731 
00732   if (verbose)
00733     libMesh::out << "File created successfully." << std::endl;
00734 
00735   this->opened_for_writing = true;
00736 }
00737 
00738 
00739 
00740 
00741 
00742 
00743 
00744 
00745 void Nemesis_IO_Helper::initialize(std::string title_in, const MeshBase & mesh, bool /*use_discontinuous*/)
00746 {
00747   // Make sure that the reference passed in is really a ParallelMesh
00748   // const ParallelMesh& pmesh = cast_ref<const ParallelMesh&>(mesh);
00749   const MeshBase& pmesh = mesh;
00750 
00751   // According to Nemesis documentation, first call when writing should be to
00752   // ne_put_init_info().  Our reader doesn't actually call this, but we should
00753   // strive to be as close to a normal nemesis file as possible...
00754   this->put_init_info(this->n_processors(), 1, "p");
00755 
00756 
00757   // Gather global "initial" information for Nemesis.  This consists of
00758   // three parts labelled I, II, and III below...
00759 
00760   //
00761   // I.) Need to compute the number of global element blocks.  To be consistent with
00762   // Exodus, we also incorrectly associate the number of element blocks with the
00763   // number of libmesh subdomains...
00764   //
00765   this->compute_num_global_elem_blocks(pmesh);
00766 
00767   //
00768   // II.) Determine the global number of nodesets by communication.
00769   // This code relies on BoundaryInfo storing side and node
00770   // boundary IDs separately at the time they are added to the
00771   // BoundaryInfo object.
00772   //
00773   this->compute_num_global_nodesets(pmesh);
00774 
00775   //
00776   // III.) Need to compute the global number of sidesets by communication:
00777   // This code relies on BoundaryInfo storing side and node
00778   // boundary IDs separately at the time they are added to the
00779   // BoundaryInfo object.
00780   //
00781   this->compute_num_global_sidesets(pmesh);
00782 
00783   // Now write the global data obtained in steps I, II, and III to the Nemesis file
00784   this->put_init_global(pmesh.parallel_n_nodes(),
00785                         pmesh.parallel_n_elem(),
00786                         this->num_elem_blks_global, /* I.   */
00787                         this->num_node_sets_global, /* II.  */
00788                         this->num_side_sets_global  /* III. */
00789                         );
00790 
00791   // Next, we'll write global element block information to the file.  This was already
00792   // gathered in step I. above
00793   this->put_eb_info_global(this->global_elem_blk_ids,
00794                            this->global_elem_blk_cnts);
00795 
00796 
00797   // Next, write global nodeset information to the file.  This was already gathered in
00798   // step II. above.
00799   this->num_global_node_df_counts.clear();
00800   this->num_global_node_df_counts.resize(this->global_nodeset_ids.size()); // distribution factors all zero...
00801   this->put_ns_param_global(this->global_nodeset_ids,
00802                             this->num_global_node_counts,
00803                             this->num_global_node_df_counts);
00804 
00805 
00806   // Next, write global sideset information to the file.  This was already gathered in
00807   // step III. above.
00808   this->num_global_side_df_counts.clear();
00809   this->num_global_side_df_counts.resize(this->global_sideset_ids.size()); // distribution factors all zero...
00810   this->put_ss_param_global(this->global_sideset_ids,
00811                             this->num_global_side_counts,
00812                             this->num_global_side_df_counts);
00813 
00814 
00815   // Before we go any further we need to derive consistent node and
00816   // element numbering schemes for all local elems and nodes connected
00817   // to local elements.
00818   //
00819   // Must be called *after* the local_subdomain_counts map has been constructed
00820   // by the compute_num_global_elem_blocks() function!
00821   this->build_element_and_node_maps(pmesh);
00822 
00823   // Next step is to write "load balance" parameters.  Several things need to
00824   // be computed first though...
00825 
00826   // First we'll collect IDs of border nodes.
00827   this->compute_border_node_ids(pmesh);
00828 
00829   // Next we'll collect numbers of internal and border elements, and internal nodes.
00830   // Note: "A border node does not a border element make...", that is, just because one
00831   // of an element's nodes has been identified as a border node, the element is not
00832   // necessarily a border element.  It must have a side on the boundary between processors,
00833   // i.e. have a face neighbor with a different processor id...
00834   this->compute_internal_and_border_elems_and_internal_nodes(pmesh);
00835 
00836   // Finally we are ready to write the loadbal information to the file
00837   this->put_loadbal_param(this->num_internal_nodes,
00838                           this->num_border_nodes,
00839                           this->num_external_nodes,
00840                           this->num_internal_elems,
00841                           this->num_border_elems,
00842                           this->num_node_cmaps,
00843                           this->num_elem_cmaps);
00844 
00845 
00846   // Now we need to compute the "communication map" parameters.  These are basically
00847   // lists of nodes and elements which need to be communicated between different processors
00848   // when the mesh file is read back in.
00849   this->compute_communication_map_parameters();
00850 
00851   // Write communication map parameters to file.
00852   this->put_cmap_params(this->node_cmap_ids,
00853                         this->node_cmap_node_cnts,
00854                         this->elem_cmap_ids,
00855                         this->elem_cmap_elem_cnts);
00856 
00857 
00858   // Ready the node communication maps.  The node IDs which
00859   // are communicated are the ones currently stored in
00860   // proc_nodes_touched_intersections.
00861   this->compute_node_communication_maps();
00862 
00863   // Write the packed node communication vectors to file.
00864   this->put_node_cmap(this->node_cmap_node_ids,
00865                       this->node_cmap_proc_ids);
00866 
00867 
00868   // Ready the node maps.  These have nothing to do with communiction, they map
00869   // the nodes to internal, border, and external nodes in the file.
00870   this->compute_node_maps();
00871 
00872   // Call the Nemesis API to write the node maps to file.
00873   this->put_node_map(this->node_mapi,
00874                      this->node_mapb,
00875                      this->node_mape);
00876 
00877 
00878 
00879   // Ready the element communication maps.  This includes border
00880   // element IDs, sides which are on the border, and the processors to which
00881   // they are to be communicated...
00882   this->compute_elem_communication_maps();
00883 
00884 
00885 
00886   // Call the Nemesis API to write the packed element communication maps vectors to file
00887   this->put_elem_cmap(this->elem_cmap_elem_ids,
00888                       this->elem_cmap_side_ids,
00889                       this->elem_cmap_proc_ids);
00890 
00891 
00892 
00893 
00894 
00895 
00896   // Ready the Nemesis element maps (internal and border) for writing to file.
00897   this->compute_element_maps();
00898 
00899   // Call the Nemesis API to write the internal and border element IDs.
00900   this->put_elem_map(this->elem_mapi,
00901                      this->elem_mapb);
00902 
00903 
00904   // Now write Exodus-specific initialization information, some of which is
00905   // different when you are using Nemesis.
00906   this->write_exodus_initialization_info(pmesh, title_in);
00907 } // end initialize()
00908 
00909 
00910 
00911 
00912 
00913 
00914 void Nemesis_IO_Helper::write_exodus_initialization_info(const MeshBase& pmesh,
00915                                                          const std::string& title_in)
00916 {
00917   // This follows the convention of Exodus: we always write out the mesh as LIBMESH_DIM-dimensional,
00918   // even if it is 2D...
00919   this->num_dim = pmesh.spatial_dimension();
00920 
00921   this->num_elem = static_cast<unsigned int>(std::distance (pmesh.active_local_elements_begin(),
00922                                                             pmesh.active_local_elements_end()));
00923 
00924   // Exodus will also use *global* number of side and node sets,
00925   // though it will not write out entries for all of them...
00926   this->num_side_sets =
00927     cast_int<int>(this->global_sideset_ids.size());
00928   this->num_node_sets =
00929     cast_int<int>(this->global_nodeset_ids.size());
00930 
00931   // We need to write the global number of blocks, even though this processor might not have
00932   // elements in some of them!
00933   this->num_elem_blk = this->num_elem_blks_global;
00934 
00935   ex_err = exII::ex_put_init(ex_id,
00936                              title_in.c_str(),
00937                              this->num_dim,
00938                              this->num_nodes,
00939                              this->num_elem,
00940                              this->num_elem_blk,
00941                              this->num_node_sets,
00942                              this->num_side_sets);
00943 
00944   EX_CHECK_ERR(ex_err, "Error initializing new Nemesis file.");
00945 }
00946 
00947 
00948 
00949 
00950 
00951 void Nemesis_IO_Helper::compute_element_maps()
00952 {
00953   // Make sure we don't have any leftover info
00954   this->elem_mapi.clear();
00955   this->elem_mapb.clear();
00956 
00957   // Copy set contents into vectors
00958   this->elem_mapi.resize(this->internal_elem_ids.size());
00959   this->elem_mapb.resize(this->border_elem_ids.size());
00960 
00961   {
00962     unsigned cnt = 0;
00963     for (std::set<unsigned>::iterator it=this->internal_elem_ids.begin();
00964          it != this->internal_elem_ids.end();
00965          ++it, ++cnt)
00966       this->elem_mapi[cnt] = libmesh_elem_num_to_exodus[(*it)]; // + 1; // Exodus is 1-based!
00967   }
00968 
00969   {
00970     unsigned cnt = 0;
00971     for (std::set<unsigned>::iterator it=this->border_elem_ids.begin();
00972          it != this->border_elem_ids.end();
00973          ++it, ++cnt)
00974       this->elem_mapb[cnt] = libmesh_elem_num_to_exodus[(*it)]; // + 1; // Exodus is 1-based!
00975   }
00976 }
00977 
00978 
00979 
00980 void Nemesis_IO_Helper::compute_elem_communication_maps()
00981 {
00982   // Make sure there is no leftover information
00983   this->elem_cmap_elem_ids.clear();
00984   this->elem_cmap_side_ids.clear();
00985   this->elem_cmap_proc_ids.clear();
00986 
00987   // Allocate enough space for all our element maps
00988   this->elem_cmap_elem_ids.resize(this->num_elem_cmaps);
00989   this->elem_cmap_side_ids.resize(this->num_elem_cmaps);
00990   this->elem_cmap_proc_ids.resize(this->num_elem_cmaps);
00991   {
00992     unsigned cnt=0; // Index into vectors
00993     for (proc_border_elem_sets_iterator it=this->proc_border_elem_sets.begin();
00994          it != this->proc_border_elem_sets.end();
00995          ++it)
00996       {
00997         // Make sure the current elem_cmap_id matches the index in our map of node intersections
00998         libmesh_assert_equal_to ( static_cast<unsigned>(this->elem_cmap_ids[cnt]), (*it).first );
00999 
01000         // Get reference to the set of IDs to be packed into the vector
01001         std::set<std::pair<unsigned,unsigned> >& elem_set = (*it).second;
01002 
01003         // Resize the vectors to receive their payload
01004         this->elem_cmap_elem_ids[cnt].resize(elem_set.size());
01005         this->elem_cmap_side_ids[cnt].resize(elem_set.size());
01006         this->elem_cmap_proc_ids[cnt].resize(elem_set.size());
01007 
01008         std::set<std::pair<unsigned,unsigned> >::iterator elem_set_iter = elem_set.begin();
01009 
01010         // Pack the vectors with elem IDs, side IDs, and processor IDs.
01011         for (unsigned j=0; j<this->elem_cmap_elem_ids[cnt].size(); ++j, ++elem_set_iter)
01012           {
01013             this->elem_cmap_elem_ids[cnt][j] = libmesh_elem_num_to_exodus[(*elem_set_iter).first];//  + 1; // Elem ID, Exodus is 1-based
01014             this->elem_cmap_side_ids[cnt][j] = (*elem_set_iter).second;     // Side ID, this has already been converted above
01015             this->elem_cmap_proc_ids[cnt][j] = (*it).first; // All have the same processor ID
01016           }
01017 
01018         cnt++;// increment vector index to go to next processor
01019       }
01020   } // end scope for packing
01021 }
01022 
01023 
01024 
01025 
01026 
01027 void Nemesis_IO_Helper::compute_node_maps()
01028 {
01029   // Make sure we don't have any leftover information
01030   this->node_mapi.clear();
01031   this->node_mapb.clear();
01032   this->node_mape.clear();
01033 
01034   // Make sure there's enough space to hold all our node IDs
01035   this->node_mapi.resize(this->internal_node_ids.size());
01036   this->node_mapb.resize(this->border_node_ids.size());
01037 
01038   // Copy set contents into vectors
01039   //
01040   // Can't use insert, since we are copying unsigned's into vector<int>...
01041   // this->node_mapi.insert(internal_node_ids.begin(), internal_node_ids.end());
01042   // this->node_mapb.insert(boundary_node_ids.begin(), boundary_node_ids.end());
01043   {
01044     unsigned cnt = 0;
01045     for (std::set<unsigned>::iterator it=this->internal_node_ids.begin();
01046          it != this->internal_node_ids.end();
01047          ++it, ++cnt)
01048       this->node_mapi[cnt] = this->libmesh_node_num_to_exodus[*it];// + 1; // Exodus is 1-based!
01049   }
01050 
01051   {
01052     unsigned cnt=0;
01053     for (std::set<unsigned>::iterator it=this->border_node_ids.begin();
01054          it != this->border_node_ids.end();
01055          ++it, ++cnt)
01056       this->node_mapb[cnt] = this->libmesh_node_num_to_exodus[*it];// + 1; // Exodus is 1-based!
01057   }
01058 }
01059 
01060 
01061 
01062 
01063 
01064 void Nemesis_IO_Helper::compute_node_communication_maps()
01065 {
01066   // Make sure there's no left-over information
01067   this->node_cmap_node_ids.clear();
01068   this->node_cmap_proc_ids.clear();
01069 
01070   // Allocate enough space for all our node maps
01071   this->node_cmap_node_ids.resize(this->num_node_cmaps);
01072   this->node_cmap_proc_ids.resize(this->num_node_cmaps);
01073   {
01074     unsigned cnt=0; // Index into vectors
01075     for (proc_nodes_touched_iterator it = this->proc_nodes_touched_intersections.begin();
01076          it != this->proc_nodes_touched_intersections.end();
01077          ++it)
01078       {
01079         // Make sure the current node_cmap_id matches the index in our map of node intersections
01080         libmesh_assert_equal_to ( static_cast<unsigned>(this->node_cmap_ids[cnt]), (*it).first );
01081 
01082         // Get reference to the set of IDs to be packed into the vector.
01083         std::set<unsigned>& node_set = (*it).second;
01084 
01085         //libMesh::out << "[" << this->processor_id() << "] node_set.size()=" << node_set.size() << std::endl;
01086 
01087         // Resize the vectors to receive their payload
01088         this->node_cmap_node_ids[cnt].resize(node_set.size());
01089         this->node_cmap_proc_ids[cnt].resize(node_set.size());
01090 
01091         std::set<unsigned>::iterator node_set_iter = node_set.begin();
01092 
01093         // Pack the vectors with node IDs and processor IDs.
01094         for (unsigned j=0; j<this->node_cmap_node_ids[cnt].size(); ++j, ++node_set_iter)
01095           {
01096             this->node_cmap_node_ids[cnt][j] = this->libmesh_node_num_to_exodus[*node_set_iter];//(*node_set_iter) + 1; // Exodus is 1-based
01097             this->node_cmap_proc_ids[cnt][j] = (*it).first;
01098           }
01099 
01100         cnt++;// increment vector index to go to next processor
01101       }
01102   } // end scope for packing
01103 
01104   // if (verbose)
01105   //   libMesh::out << "Done packing." << std::endl;
01106 
01107   // Print out the vectors we just packed
01108   if (verbose)
01109     {
01110       for (unsigned i=0; i<this->node_cmap_node_ids.size(); ++i)
01111         {
01112           libMesh::out << "[" << this->processor_id() << "] nodes communicated to proc "
01113                        << this->node_cmap_ids[i]
01114                        << " = ";
01115           for (unsigned j=0; j<this->node_cmap_node_ids[i].size(); ++j)
01116             libMesh::out << this->node_cmap_node_ids[i][j] << " ";
01117           libMesh::out << std::endl;
01118         }
01119 
01120       for (unsigned i=0; i<this->node_cmap_node_ids.size(); ++i)
01121         {
01122           libMesh::out << "[" << this->processor_id() << "] processor ID node communicated to = ";
01123           for (unsigned j=0; j<this->node_cmap_proc_ids[i].size(); ++j)
01124             libMesh::out << this->node_cmap_proc_ids[i][j] << " ";
01125           libMesh::out << std::endl;
01126         }
01127     }
01128 }
01129 
01130 
01131 
01132 
01133 void Nemesis_IO_Helper::compute_communication_map_parameters()
01134 {
01135   // For the nodes, these are the number of entries in the sets in proc_nodes_touched_intersections
01136   // map computed above.  Note: this map does not contain self-intersections so we can loop over it
01137   // directly.
01138   this->node_cmap_node_cnts.clear(); // Make sure we don't have any leftover information...
01139   this->node_cmap_ids.clear();       // Make sure we don't have any leftover information...
01140   this->node_cmap_node_cnts.resize(this->num_node_cmaps);
01141   this->node_cmap_ids.resize(this->num_node_cmaps);
01142 
01143   {
01144     unsigned cnt=0; // Index into the vector
01145     for (proc_nodes_touched_iterator it = this->proc_nodes_touched_intersections.begin();
01146          it != this->proc_nodes_touched_intersections.end();
01147          ++it)
01148       {
01149         this->node_cmap_ids[cnt] = (*it).first; // The ID of the proc we communicate with
01150         this->node_cmap_node_cnts[cnt] =
01151           cast_int<int>((*it).second.size());   // The number of nodes we communicate
01152         cnt++; // increment vector index!
01153       }
01154   }
01155 
01156   // Print the packed vectors we just filled
01157   if (verbose)
01158     {
01159       libMesh::out << "[" << this->processor_id() << "] node_cmap_node_cnts = ";
01160       for (unsigned i=0; i<node_cmap_node_cnts.size(); ++i)
01161         libMesh::out << node_cmap_node_cnts[i] << ", ";
01162       libMesh::out << std::endl;
01163 
01164       libMesh::out << "[" << this->processor_id() << "] node_cmap_ids = ";
01165       for (unsigned i=0; i<node_cmap_ids.size(); ++i)
01166         libMesh::out << node_cmap_ids[i] << ", ";
01167       libMesh::out << std::endl;
01168     }
01169 
01170   // For the elements, we have not yet computed all this information..
01171   this->elem_cmap_elem_cnts.clear(); // Make sure we don't have any leftover information...
01172   this->elem_cmap_ids.clear();       // Make sure we don't have any leftover information...
01173   this->elem_cmap_elem_cnts.resize(this->num_elem_cmaps);
01174   this->elem_cmap_ids.resize(this->num_elem_cmaps);
01175 
01176   // Pack the elem_cmap_ids and elem_cmap_elem_cnts vectors
01177   {
01178     unsigned cnt=0; // Index into the vectors we're filling
01179     for (proc_border_elem_sets_iterator it = this->proc_border_elem_sets.begin();
01180          it != this->proc_border_elem_sets.end();
01181          ++it)
01182       {
01183         this->elem_cmap_ids[cnt] = (*it).first; // The ID of the proc we communicate with
01184         this->elem_cmap_elem_cnts[cnt] =
01185           cast_int<int>((*it).second.size()); // The number of elems we communicate to/from that proc
01186         cnt++; // increment vector index!
01187       }
01188   }
01189 
01190   // Print the packed vectors we just filled
01191   if (verbose)
01192     {
01193       libMesh::out << "[" << this->processor_id() << "] elem_cmap_elem_cnts = ";
01194       for (unsigned i=0; i<elem_cmap_elem_cnts.size(); ++i)
01195         libMesh::out << elem_cmap_elem_cnts[i] << ", ";
01196       libMesh::out << std::endl;
01197 
01198       libMesh::out << "[" << this->processor_id() << "] elem_cmap_ids = ";
01199       for (unsigned i=0; i<elem_cmap_ids.size(); ++i)
01200         libMesh::out << elem_cmap_ids[i] << ", ";
01201       libMesh::out << std::endl;
01202     }
01203 }
01204 
01205 
01206 
01207 
01208 void
01209 Nemesis_IO_Helper::compute_internal_and_border_elems_and_internal_nodes(const MeshBase& pmesh)
01210 {
01211   // Set of all local, active element IDs.  After we have identified border element
01212   // IDs, the set_difference between this set and the border_elem_ids set will give us
01213   // the set of internal_elem_ids.
01214   std::set<unsigned> all_elem_ids;
01215 
01216   // A set of processor IDs which elements on this processor have as
01217   // neighbors.  The size of this set will determine the number of
01218   // element communication maps in Exodus.
01219   std::set<unsigned> neighboring_processor_ids;
01220 
01221   // Will be used to create conversion objects capable of mapping libmesh
01222   // element numberings into Nemesis numberings.
01223   ExodusII_IO_Helper::ElementMaps element_mapper;
01224 
01225   MeshBase::const_element_iterator elem_it = pmesh.active_local_elements_begin();
01226   MeshBase::const_element_iterator elem_end = pmesh.active_local_elements_end();
01227 
01228   for (; elem_it != elem_end; ++elem_it)
01229     {
01230       const Elem* elem = *elem_it;
01231 
01232       // Add this Elem's ID to all_elem_ids, later we will take the difference
01233       // between this set and the set of border_elem_ids, to get the set of
01234       // internal_elem_ids.
01235       all_elem_ids.insert(elem->id());
01236 
01237       // Will be set to true if element is determined to be a border element
01238       bool is_border_elem = false;
01239 
01240       // Construct a conversion object for this Element.  This will help us map
01241       // Libmesh numberings into Nemesis numberings for sides.
01242       ExodusII_IO_Helper::Conversion conv = element_mapper.assign_conversion(elem->type());
01243 
01244       // Add all this element's node IDs to the set of all node IDs.
01245       // The set of internal_node_ids will be the set difference between
01246       // the set of all nodes and the set of border nodes.
01247       //
01248       // In addition, if any node of a local node is listed in the
01249       // border nodes list, then this element goes into the proc_border_elem_sets.
01250       // Note that there is not a 1:1 correspondence between
01251       // border_elem_ids and the entries which go into proc_border_elem_sets.
01252       // The latter is for communication purposes, ie determining which elements
01253       // should be shared between processors.
01254       for (unsigned int node=0; node<elem->n_nodes(); ++node)
01255         {
01256           this->nodes_attached_to_local_elems.insert(elem->node(node));
01257         } // end loop over element's nodes
01258 
01259       // Loop over element's neighbors, see if it has a neighbor which is off-processor
01260       for (unsigned int n=0; n<elem->n_neighbors(); ++n)
01261         {
01262           if (elem->neighbor(n) != NULL)
01263             {
01264               unsigned neighbor_proc_id = elem->neighbor(n)->processor_id();
01265 
01266               // If my neighbor has a different processor ID, I must be a border element.
01267               // Also track the neighboring processor ID if it is are different from our processor ID
01268               if (neighbor_proc_id != this->processor_id())
01269                 {
01270                   is_border_elem = true;
01271                   neighboring_processor_ids.insert(neighbor_proc_id);
01272 
01273                   // Convert libmesh side(n) of this element into a side ID for Nemesis
01274                   unsigned nemesis_side_id = conv.get_inverse_side_map(n);
01275 
01276                   if (verbose)
01277                     libMesh::out << "[" << this->processor_id() << "] LibMesh side "
01278                                  << n
01279                                  << " mapped to (1-based) Exodus side "
01280                                  << nemesis_side_id
01281                                  << std::endl;
01282 
01283                   // Add this element's ID and the ID of the side which is on the boundary
01284                   // to the set of border elements for this processor.
01285                   // Note: if the set does not already exist, this creates it.
01286                   this->proc_border_elem_sets[ neighbor_proc_id ].insert( std::make_pair(elem->id(), nemesis_side_id) );
01287                 }
01288             }
01289         } // end for loop over neighbors
01290 
01291       // If we're on a border element, add it to the set
01292       if (is_border_elem)
01293         this->border_elem_ids.insert( elem->id() );
01294 
01295     } // end for loop over active local elements
01296 
01297   // Take the set_difference between all elements and border elements to get internal
01298   // element IDs
01299   std::set_difference(all_elem_ids.begin(), all_elem_ids.end(),
01300                       this->border_elem_ids.begin(), this->border_elem_ids.end(),
01301                       std::inserter(this->internal_elem_ids, this->internal_elem_ids.end()));
01302 
01303   // Take the set_difference between all nodes and border nodes to get internal nodes
01304   std::set_difference(this->nodes_attached_to_local_elems.begin(), this->nodes_attached_to_local_elems.end(),
01305                       this->border_node_ids.begin(), this->border_node_ids.end(),
01306                       std::inserter(this->internal_node_ids, this->internal_node_ids.end()));
01307 
01308   if (verbose)
01309     {
01310       libMesh::out << "[" << this->processor_id() << "] neighboring_processor_ids = ";
01311       for (std::set<unsigned>::iterator it = neighboring_processor_ids.begin();
01312            it != neighboring_processor_ids.end();
01313            ++it)
01314         {
01315           libMesh::out << *it << " ";
01316         }
01317       libMesh::out << std::endl;
01318     }
01319 
01320   // The size of the neighboring_processor_ids set should be the number of element communication maps
01321   this->num_elem_cmaps =
01322     cast_int<int>(neighboring_processor_ids.size());
01323 
01324   if (verbose)
01325     libMesh::out << "[" << this->processor_id() << "] "
01326                  << "Number of neighboring processor IDs="
01327                  << this->num_elem_cmaps
01328                  << std::endl;
01329 
01330   if (verbose)
01331     {
01332       // Print out counts of border elements for each processor
01333       for (proc_border_elem_sets_iterator it=this->proc_border_elem_sets.begin();
01334            it != this->proc_border_elem_sets.end(); ++it)
01335         {
01336           libMesh::out << "[" << this->processor_id() << "] "
01337                        << "Proc "
01338                        << (*it).first << " communicates "
01339                        << (*it).second.size() << " elements." << std::endl;
01340         }
01341     }
01342 
01343   // Store the number of internal and border elements, and the number of internal nodes,
01344   // to be written to the Nemesis file.
01345   this->num_internal_elems =
01346     cast_int<int>(this->internal_elem_ids.size());
01347   this->num_border_elems   =
01348     cast_int<int>(this->border_elem_ids.size());
01349   this->num_internal_nodes =
01350     cast_int<int>(this->internal_node_ids.size());
01351 
01352   if (verbose)
01353     {
01354       libMesh::out << "[" << this->processor_id() << "] num_internal_nodes=" << this->num_internal_nodes << std::endl;
01355       libMesh::out << "[" << this->processor_id() << "] num_border_nodes=" << this->num_border_nodes << std::endl;
01356       libMesh::out << "[" << this->processor_id() << "] num_border_elems=" << this->num_border_elems << std::endl;
01357       libMesh::out << "[" << this->processor_id() << "] num_internal_elems=" << this->num_internal_elems << std::endl;
01358     }
01359 }
01360 
01361 
01362 
01363 void Nemesis_IO_Helper::compute_num_global_sidesets(const MeshBase& pmesh)
01364 {
01365   // 1.) Get reference to the set of side boundary IDs
01366   std::set<boundary_id_type> global_side_boundary_ids
01367     (pmesh.get_boundary_info().get_side_boundary_ids().begin(),
01368      pmesh.get_boundary_info().get_side_boundary_ids().end());
01369 
01370   // 2.) Gather boundary side IDs from other processors
01371   this->comm().set_union(global_side_boundary_ids);
01372 
01373   // 3.) Now global_side_boundary_ids actually contains a global list of all side boundary IDs
01374   this->num_side_sets_global =
01375     cast_int<int>(global_side_boundary_ids.size());
01376 
01377   // 4.) Pack these sidesets into a vector so they can be written by Nemesis
01378   this->global_sideset_ids.clear(); // Make sure there is no leftover information
01379   this->global_sideset_ids.insert(this->global_sideset_ids.end(),
01380                                   global_side_boundary_ids.begin(),
01381                                   global_side_boundary_ids.end());
01382 
01383   if (verbose)
01384     {
01385       libMesh::out << "[" << this->processor_id() << "] global_sideset_ids = ";
01386       for (unsigned i=0; i<this->global_sideset_ids.size(); ++i)
01387         libMesh::out << this->global_sideset_ids[i] << ", ";
01388       libMesh::out << std::endl;
01389     }
01390 
01391   // We also need global counts of sides in each of the sidesets.  Again, there may be a
01392   // better way to do this...
01393   std::vector<dof_id_type> bndry_elem_list;
01394   std::vector<unsigned short int> bndry_side_list;
01395   std::vector<boundary_id_type> bndry_id_list;
01396   pmesh.get_boundary_info().build_side_list(bndry_elem_list, bndry_side_list, bndry_id_list);
01397 
01398   // Similarly to the nodes, we can't count any sides for elements which aren't local
01399   std::vector<dof_id_type>::iterator it_elem=bndry_elem_list.begin();
01400   std::vector<unsigned short>::iterator it_side=bndry_side_list.begin();
01401   std::vector<boundary_id_type>::iterator it_id=bndry_id_list.begin();
01402 
01403   // New end iterators, to be updated as we find non-local IDs
01404   std::vector<dof_id_type>::iterator new_bndry_elem_list_end = bndry_elem_list.end();
01405   std::vector<unsigned short>::iterator new_bndry_side_list_end = bndry_side_list.end();
01406   std::vector<boundary_id_type>::iterator new_bndry_id_list_end = bndry_id_list.end();
01407 
01408   for ( ; it_elem != new_bndry_elem_list_end; )
01409     {
01410       if (pmesh.elem( *it_elem )->processor_id() != this->processor_id())
01411         {
01412           // Back up the new end iterators to prepare for swap
01413           --new_bndry_elem_list_end;
01414           --new_bndry_side_list_end;
01415           --new_bndry_id_list_end;
01416 
01417           // Swap places, the non-local elem will now be "past-the-end"
01418           std::swap (*it_elem, *new_bndry_elem_list_end);
01419           std::swap (*it_side, *new_bndry_side_list_end);
01420           std::swap (*it_id, *new_bndry_id_list_end);
01421         }
01422       else // elem is local, go to next
01423         {
01424           ++it_elem;
01425           ++it_side;
01426           ++it_id;
01427         }
01428     }
01429 
01430   // Erase from "new" end to old end on each vector.
01431   bndry_elem_list.erase(new_bndry_elem_list_end, bndry_elem_list.end());
01432   bndry_side_list.erase(new_bndry_side_list_end, bndry_side_list.end());
01433   bndry_id_list.erase(new_bndry_id_list_end, bndry_id_list.end());
01434 
01435   this->num_global_side_counts.clear(); // Make sure we don't have any leftover information
01436   this->num_global_side_counts.resize(this->global_sideset_ids.size());
01437 
01438   // Get the count for each global sideset ID
01439   for (unsigned i=0; i<global_sideset_ids.size(); ++i)
01440     {
01441       this->num_global_side_counts[i] = cast_int<int>
01442         (std::count(bndry_id_list.begin(),
01443                     bndry_id_list.end(),
01444                     cast_int<boundary_id_type>(this->global_sideset_ids[i])));
01445     }
01446 
01447   if (verbose)
01448     {
01449       libMesh::out << "[" << this->processor_id() << "] num_global_side_counts = ";
01450       for (unsigned i=0; i<this->num_global_side_counts.size(); ++i)
01451         libMesh::out << this->num_global_side_counts[i] << ", ";
01452       libMesh::out << std::endl;
01453     }
01454 
01455   // Finally sum up the result
01456   this->comm().sum(this->num_global_side_counts);
01457 
01458   if (verbose)
01459     {
01460       libMesh::out << "[" << this->processor_id() << "] num_global_side_counts = ";
01461       for (unsigned i=0; i<this->num_global_side_counts.size(); ++i)
01462         libMesh::out << this->num_global_side_counts[i] << ", ";
01463       libMesh::out << std::endl;
01464     }
01465 }
01466 
01467 
01468 
01469 
01470 
01471 
01472 void Nemesis_IO_Helper::compute_num_global_nodesets(const MeshBase& pmesh)
01473 {
01474   std::set<boundary_id_type> local_node_boundary_ids;
01475 
01476   // 1.) Get reference to the set of node boundary IDs *for this processor*
01477   std::set<boundary_id_type> global_node_boundary_ids
01478     (pmesh.get_boundary_info().get_node_boundary_ids().begin(),
01479      pmesh.get_boundary_info().get_node_boundary_ids().end());
01480 
01481   // Save a copy of the local_node_boundary_ids...
01482   local_node_boundary_ids = global_node_boundary_ids;
01483 
01484   // 2.) Gather boundary node IDs from other processors
01485   this->comm().set_union(global_node_boundary_ids);
01486 
01487   // 3.) Now global_node_boundary_ids actually contains a global list of all node boundary IDs
01488   this->num_node_sets_global =
01489     cast_int<int>(global_node_boundary_ids.size());
01490 
01491   // 4.) Create a vector<int> from the global_node_boundary_ids set
01492   this->global_nodeset_ids.clear();
01493   this->global_nodeset_ids.insert(this->global_nodeset_ids.end(),
01494                                   global_node_boundary_ids.begin(),
01495                                   global_node_boundary_ids.end());
01496 
01497   if (verbose)
01498     {
01499       libMesh::out << "[" << this->processor_id() << "] global_nodeset_ids = ";
01500       for (unsigned i=0; i<global_nodeset_ids.size(); ++i)
01501         libMesh::out << global_nodeset_ids[i] << ", ";
01502       libMesh::out << std::endl;
01503 
01504       libMesh::out << "[" << this->processor_id() << "] local_node_boundary_ids = ";
01505       for (std::set<boundary_id_type>::iterator it = local_node_boundary_ids.begin();
01506            it != local_node_boundary_ids.end();
01507            ++it)
01508         libMesh::out << *it << ", ";
01509       libMesh::out << std::endl;
01510     }
01511 
01512   // 7.) We also need to know the number of nodes which is in each of the nodesets, globally.
01513   // There is probably a better way to do this...
01514   std::vector<dof_id_type> boundary_node_list;
01515   std::vector<boundary_id_type> boundary_node_boundary_id_list;
01516   pmesh.get_boundary_info().build_node_list
01517     (boundary_node_list, boundary_node_boundary_id_list);
01518 
01519   if (verbose)
01520     {
01521       libMesh::out << "[" << this->processor_id() << "] boundary_node_list.size()="
01522                    << boundary_node_list.size() << std::endl;
01523       libMesh::out << "[" << this->processor_id() << "] (boundary_node_id, boundary_id) = ";
01524       for (unsigned i=0; i<boundary_node_list.size(); ++i)
01525         {
01526           libMesh::out << "(" << boundary_node_list[i] << ", " << boundary_node_boundary_id_list[i] << ") ";
01527         }
01528       libMesh::out << std::endl;
01529     }
01530 
01531   // Now get the global information.  In this case, we only want to count boundary
01532   // information for nodes *owned* by this processor, so there are no duplicates.
01533 
01534   // Make sure we don't have any left over information
01535   this->num_global_node_counts.clear();
01536   this->num_global_node_counts.resize(this->global_nodeset_ids.size());
01537 
01538   // Unfortunately, we can't just count up all occurrences of a given id,
01539   // that would give us duplicate entries when we do the parallel summation.
01540   // So instead, only count entries for nodes owned by this processor.
01541   // Start by getting rid of all non-local node entries from the vectors.
01542   std::vector<dof_id_type>::iterator it_node=boundary_node_list.begin();
01543   std::vector<boundary_id_type>::iterator it_id=boundary_node_boundary_id_list.begin();
01544 
01545   // New end iterators, to be updated as we find non-local IDs
01546   std::vector<dof_id_type>::iterator new_node_list_end = boundary_node_list.end();
01547   std::vector<boundary_id_type>::iterator new_boundary_id_list_end = boundary_node_boundary_id_list.end();
01548   for ( ; it_node != new_node_list_end; )
01549     {
01550       if (pmesh.node_ptr( *it_node )->processor_id() != this->processor_id())
01551         {
01552           // Back up the new end iterators to prepare for swap
01553           --new_node_list_end;
01554           --new_boundary_id_list_end;
01555 
01556           // Swap places, the non-local node will now be "past-the-end"
01557           std::swap (*it_node, *new_node_list_end);
01558           std::swap (*it_id, *new_boundary_id_list_end);
01559         }
01560       else // node is local, go to next
01561         {
01562           ++it_node;
01563           ++it_id;
01564         }
01565     }
01566 
01567   // Erase from "new" end to old end on each vector.
01568   boundary_node_list.erase(new_node_list_end, boundary_node_list.end());
01569   boundary_node_boundary_id_list.erase(new_boundary_id_list_end, boundary_node_boundary_id_list.end());
01570 
01571   // Now we can do the local count for each ID...
01572   for (unsigned i=0; i<global_nodeset_ids.size(); ++i)
01573     {
01574       this->num_global_node_counts[i] = cast_int<int>
01575         (std::count(boundary_node_boundary_id_list.begin(),
01576                     boundary_node_boundary_id_list.end(),
01577                     cast_int<boundary_id_type>(this->global_nodeset_ids[i])));
01578     }
01579 
01580   // And finally we can sum them up
01581   this->comm().sum(this->num_global_node_counts);
01582 
01583   if (verbose)
01584     {
01585       libMesh::out << "[" << this->processor_id() << "] num_global_node_counts = ";
01586       for (unsigned i=0; i<num_global_node_counts.size(); ++i)
01587         libMesh::out << num_global_node_counts[i] << ", ";
01588       libMesh::out << std::endl;
01589     }
01590 }
01591 
01592 
01593 
01594 
01595 void Nemesis_IO_Helper::compute_num_global_elem_blocks(const MeshBase& pmesh)
01596 {
01597   // 1.) Loop over active local elements, build up set of subdomain IDs.
01598   std::set<subdomain_id_type> global_subdomain_ids;
01599 
01600   // This map keeps track of the number of elements in each subdomain over all processors
01601   std::map<subdomain_id_type, unsigned> global_subdomain_counts;
01602 
01603   MeshBase::const_element_iterator elem_it = pmesh.active_local_elements_begin();
01604   MeshBase::const_element_iterator elem_end = pmesh.active_local_elements_end();
01605 
01606   for (; elem_it != elem_end; ++elem_it)
01607     {
01608       const Elem* elem = *elem_it;
01609 
01610       subdomain_id_type cur_subdomain = elem->subdomain_id();
01611 
01612       /*
01613       // We can't have a zero subdomain ID in Exodus (for some reason?)
01614       // so map zero subdomains to a max value...
01615       if (cur_subdomain == 0)
01616       cur_subdomain = std::numeric_limits<subdomain_id_type>::max();
01617       */
01618 
01619       global_subdomain_ids.insert(cur_subdomain);
01620 
01621       // Increment the count of elements in this subdomain
01622       global_subdomain_counts[cur_subdomain]++;
01623     }
01624 
01625   // We're next going to this->comm().sum the subdomain counts, so save the local counts
01626   this->local_subdomain_counts = global_subdomain_counts;
01627 
01628   {
01629     // 2.) Copy local subdomain IDs into a vector for communication
01630     std::vector<subdomain_id_type> global_subdomain_ids_vector(global_subdomain_ids.begin(),
01631                                                                global_subdomain_ids.end());
01632 
01633     // 3.) Gather them into an enlarged vector
01634     this->comm().allgather(global_subdomain_ids_vector);
01635 
01636     // 4.) Insert any new IDs into the set (any duplicates will be dropped)
01637     global_subdomain_ids.insert(global_subdomain_ids_vector.begin(),
01638                                 global_subdomain_ids_vector.end());
01639   }
01640 
01641   // 5.) Now global_subdomain_ids actually contains a global list of all subdomain IDs
01642   this->num_elem_blks_global =
01643     cast_int<int>(global_subdomain_ids.size());
01644 
01645   // Print the number of elements found locally in each subdomain
01646   if (verbose)
01647     {
01648       libMesh::out << "[" << this->processor_id() << "] ";
01649       for (std::map<subdomain_id_type, unsigned>::iterator it=global_subdomain_counts.begin();
01650            it != global_subdomain_counts.end();
01651            ++it)
01652         {
01653           libMesh::out << "ID: "
01654                        << static_cast<unsigned>((*it).first)
01655                        << ", Count: " << (*it).second << ", ";
01656         }
01657       libMesh::out << std::endl;
01658     }
01659 
01660   // 6.) this->comm().sum up the number of elements in each block.  We know the global
01661   // subdomain IDs, so pack them into a vector one by one.  Use a vector of int since
01662   // that is what Nemesis wants
01663   this->global_elem_blk_cnts.resize(global_subdomain_ids.size());
01664 
01665   unsigned cnt=0;
01666   for (std::set<subdomain_id_type>::iterator it=global_subdomain_ids.begin();
01667        it != global_subdomain_ids.end(); ++it)
01668     {
01669       // Find the entry in the local map, note: if not found, will be created with 0 default value, which is OK...
01670       this->global_elem_blk_cnts[cnt++] = global_subdomain_counts[*it];
01671     }
01672 
01673   // Sum up subdomain counts from all processors
01674   this->comm().sum(this->global_elem_blk_cnts);
01675 
01676   if (verbose)
01677     {
01678       libMesh::out << "[" << this->processor_id() << "] global_elem_blk_cnts = ";
01679       for (unsigned i=0; i<this->global_elem_blk_cnts.size(); ++i)
01680         libMesh::out << this->global_elem_blk_cnts[i] << ", ";
01681       libMesh::out << std::endl;
01682     }
01683 
01684   // 7.) Create a vector<int> from the global_subdomain_ids set, for passing to Nemesis
01685   this->global_elem_blk_ids.clear();
01686   this->global_elem_blk_ids.insert(this->global_elem_blk_ids.end(), // pos
01687                                    global_subdomain_ids.begin(),
01688                                    global_subdomain_ids.end());
01689 
01690   if (verbose)
01691     {
01692       libMesh::out << "[" << this->processor_id() << "] global_elem_blk_ids = ";
01693       for (unsigned i=0; i<this->global_elem_blk_ids.size(); ++i)
01694         libMesh::out << this->global_elem_blk_ids[i] << ", ";
01695       libMesh::out << std::endl;
01696     }
01697 
01698 
01699   // 8.) We will call put_eb_info_global later, it must be called after this->put_init_global().
01700 }
01701 
01702 
01703 
01704 
01705 void Nemesis_IO_Helper::build_element_and_node_maps(const MeshBase& pmesh)
01706 {
01707   // If we don't have any local subdomains, it had better be because
01708   // we don't have any local elements
01709 #ifdef DEBUG
01710   if (local_subdomain_counts.empty())
01711     {
01712       libmesh_assert(pmesh.active_local_elements_begin() ==
01713                      pmesh.active_local_elements_end());
01714       libmesh_assert(this->nodes_attached_to_local_elems.empty());
01715     }
01716 #endif
01717 
01718   // Elements have to be numbered contiguously based on what block
01719   // number they are in.  Therefore we have to do a bit of work to get
01720   // the block (ie subdomain) numbers first and store them off as
01721   // block_ids.
01722 
01723   // Make sure there is no leftover information in the subdomain_map, and reserve
01724   // enough space to store the elements we need.
01725   this->subdomain_map.clear();
01726   for (std::map<subdomain_id_type, unsigned>::iterator it=this->local_subdomain_counts.begin();
01727        it != this->local_subdomain_counts.end();
01728        ++it)
01729     {
01730       subdomain_id_type cur_subdomain = (*it).first;
01731 
01732       /*
01733       // We can't have a zero subdomain ID in Exodus (for some reason?)
01734       // so map zero subdomains to a max value...
01735       if (cur_subdomain == 0)
01736       cur_subdomain = std::numeric_limits<subdomain_id_type>::max();
01737       */
01738 
01739       if (verbose)
01740         {
01741           libMesh::out << "[" << this->processor_id() << "] "
01742                        << "local_subdomain_counts [" << static_cast<unsigned>(cur_subdomain) << "]= "
01743                        << (*it).second
01744                        << std::endl;
01745         }
01746 
01747       // *it.first is the subodmain ID, *it.second is the number of elements it contains
01748       this->subdomain_map[ cur_subdomain ].reserve( (*it).second );
01749     }
01750 
01751 
01752   // First loop over the elements to figure out which elements are in which subdomain
01753   MeshBase::const_element_iterator elem_it = pmesh.active_local_elements_begin();
01754   MeshBase::const_element_iterator elem_end = pmesh.active_local_elements_end();
01755 
01756   for (; elem_it != elem_end; ++elem_it)
01757     {
01758       const Elem * elem = *elem_it;
01759 
01760       // Grab the nodes while we're here.
01761       for (unsigned int n=0; n<elem->n_nodes(); ++n)
01762         this->nodes_attached_to_local_elems.insert( elem->node(n) );
01763 
01764       subdomain_id_type cur_subdomain = elem->subdomain_id();
01765 
01766       /*
01767       // We can't have a zero subdomain ID in Exodus (for some reason?)
01768       // so map zero subdomains to a max value...
01769       if(cur_subdomain == 0)
01770       cur_subdomain = std::numeric_limits<subdomain_id_type>::max();
01771       */
01772 
01773       this->subdomain_map[cur_subdomain].push_back
01774         (cast_int<unsigned>(elem->id()));
01775     }
01776 
01777   // Set num_nodes which is used by exodusII_io_helper
01778   this->num_nodes =
01779     cast_int<int>(this->nodes_attached_to_local_elems.size());
01780 
01781   // Now come up with a 1-based numbering for these nodes
01782   this->exodus_node_num_to_libmesh.clear(); // Make sure it's empty
01783   this->exodus_node_num_to_libmesh.reserve(this->nodes_attached_to_local_elems.size());
01784 
01785   // Also make sure there's no leftover information in the map which goes the
01786   // other direction.
01787   this->libmesh_node_num_to_exodus.clear();
01788 
01789   // Set the map for nodes
01790   for (std::set<int>::iterator it = this->nodes_attached_to_local_elems.begin();
01791        it != this->nodes_attached_to_local_elems.end();
01792        ++it)
01793     {
01794       // I.e. given exodus_node_id,
01795       // exodus_node_num_to_libmesh[ exodus_node_id ] returns the libmesh ID for that node.
01796       // Note that even though most of Exodus is 1-based, this code will map an Exodus ID of
01797       // zero to some libmesh node ID.  Is that a problem?
01798       this->exodus_node_num_to_libmesh.push_back(*it);
01799 
01800       // Likewise, given libmesh_node_id,
01801       // libmesh_node_num_to_exodus[ libmesh_node_id ] returns the *Exodus* ID for that node.
01802       // Unlike the exodus_node_num_to_libmesh vector above, this one is a std::map
01803       this->libmesh_node_num_to_exodus[*it] =
01804         cast_int<int>(this->exodus_node_num_to_libmesh.size()); // should never be zero...
01805     }
01806 
01807   // Now we're going to loop over the subdomain map and build a few things right
01808   // now that we'll use later.
01809 
01810   // First make sure our data structures don't have any leftover data...
01811   this->exodus_elem_num_to_libmesh.clear();
01812   this->block_ids.clear();
01813   this->libmesh_elem_num_to_exodus.clear();
01814 
01815   // Now loop over each subdomain and get a unique numbering for the elements
01816   for (std::map<subdomain_id_type, std::vector<unsigned int> >::iterator it = this->subdomain_map.begin();
01817        it != this->subdomain_map.end();
01818        ++it)
01819     {
01820       block_ids.push_back((*it).first);
01821 
01822       // Vector of element IDs for this subdomain
01823       std::vector<unsigned int>& elem_ids_this_subdomain = (*it).second;
01824 
01825       // The code below assumes this subdomain block is not empty, make sure that's the case!
01826       if (elem_ids_this_subdomain.size() == 0)
01827         libmesh_error_msg("Error, no element IDs found in subdomain " << (*it).first);
01828 
01829       ExodusII_IO_Helper::ElementMaps em;
01830 
01831       // Use the first element in this block to get representative information.
01832       // Note that Exodus assumes all elements in a block are of the same type!
01833       // We are using that same assumption here!
01834       const ExodusII_IO_Helper::Conversion conv = em.assign_conversion(pmesh.elem(elem_ids_this_subdomain[0])->type());
01835       this->num_nodes_per_elem = pmesh.elem(elem_ids_this_subdomain[0])->n_nodes();
01836 
01837       // Get a reference to the connectivity vector for this subdomain.  This vector
01838       // is most likely empty, we are going to fill it up now.
01839       std::vector<int>& current_block_connectivity = this->block_id_to_elem_connectivity[(*it).first];
01840 
01841       // Just in case it's not already empty...
01842       current_block_connectivity.clear();
01843       current_block_connectivity.resize(elem_ids_this_subdomain.size() * this->num_nodes_per_elem);
01844 
01845       for (unsigned int i=0; i<elem_ids_this_subdomain.size(); i++)
01846         {
01847           unsigned int elem_id = elem_ids_this_subdomain[i];
01848 
01849           // Set the number map for elements
01850           this->exodus_elem_num_to_libmesh.push_back(elem_id);
01851           this->libmesh_elem_num_to_exodus[elem_id] =
01852             cast_int<int>(this->exodus_elem_num_to_libmesh.size());
01853 
01854           const Elem * elem = pmesh.elem(elem_id);
01855 
01856           // Exodus/Nemesis want every block to have the same element type
01857           // libmesh_assert_equal_to (elem->type(), conv.get_canonical_type());
01858 
01859           // But we can get away with writing e.g. HEX8 and INFHEX8 in
01860           // the same block...
01861           libmesh_assert_equal_to (elem->n_nodes(), Elem::build(conv.get_canonical_type(), NULL)->n_nodes());
01862 
01863           for (unsigned int j=0; j < static_cast<unsigned int>(this->num_nodes_per_elem); j++)
01864             {
01865               const unsigned int connect_index   = (i*this->num_nodes_per_elem)+j;
01866               const unsigned int elem_node_index = conv.get_node_map(j);
01867               current_block_connectivity[connect_index] = this->libmesh_node_num_to_exodus[elem->node(elem_node_index)];
01868             }
01869         } // End loop over elems in this subdomain
01870     } // end loop over subdomain_map
01871 }
01872 
01873 
01874 
01875 
01876 
01877 void Nemesis_IO_Helper::compute_border_node_ids(const MeshBase& pmesh)
01878 {
01879   // The set which will eventually contain the IDs of "border nodes".  These are nodes
01880   // that lie on the boundary between one or more processors.
01881   //std::set<unsigned> border_node_ids;
01882 
01883   // map from processor ID to set of nodes which elements from this processor "touch",
01884   // that is,
01885   // proc_nodes_touched[p] = (set all node IDs found in elements owned by processor p)
01886   std::map<unsigned, std::set<unsigned> > proc_nodes_touched;
01887 
01888 
01889   // We are going to create a lot of intermediate data structures here, so make sure
01890   // as many as possible all cleaned up by creating scope!
01891   {
01892     // Loop over active (not just active local) elements, make sets of node IDs for each
01893     // processor which has an element that "touches" a node.
01894     {
01895       MeshBase::const_element_iterator elem_it = pmesh.active_elements_begin();
01896       MeshBase::const_element_iterator elem_end = pmesh.active_elements_end();
01897 
01898       for (; elem_it != elem_end; ++elem_it)
01899         {
01900           const Elem* elem = *elem_it;
01901 
01902           // Get reference to the set for this processor.  If it does not exist
01903           // it will be created.
01904           std::set<unsigned>& set_p = proc_nodes_touched[ elem->processor_id() ];
01905 
01906           // Insert all nodes touched by this element into the set
01907           for (unsigned int node=0; node<elem->n_nodes(); ++node)
01908             set_p.insert(elem->node(node));
01909         }
01910     }
01911 
01912     // The number of node communication maps is the number of other processors
01913     // with which we share nodes. (I think.) This is just the size of the map we just
01914     // created, minus 1.
01915     this->num_node_cmaps =
01916       cast_int<int>(proc_nodes_touched.size() - 1);
01917 
01918     // If we've got no elements on this processor and haven't touched
01919     // any nodes, however, then that's 0 other processors with which
01920     // we share nodes, not -1.
01921     if (this->num_node_cmaps == -1)
01922       {
01923         libmesh_assert (pmesh.active_elements_begin() == pmesh.active_elements_end());
01924         this->num_node_cmaps = 0;
01925       }
01926 
01927     // We can't be connecting to more processors than exist outside
01928     // ourselves
01929     libmesh_assert_less (static_cast<unsigned>(this->num_node_cmaps), this->n_processors());
01930 
01931     if (verbose)
01932       {
01933         libMesh::out << "[" << this->processor_id()
01934                      << "] proc_nodes_touched contains "
01935                      << proc_nodes_touched.size()
01936                      << " sets of nodes."
01937                      << std::endl;
01938 
01939         for (proc_nodes_touched_iterator it = proc_nodes_touched.begin();
01940              it != proc_nodes_touched.end();
01941              ++it)
01942           {
01943             libMesh::out << "[" << this->processor_id()
01944                          << "] proc_nodes_touched[" << (*it).first << "] has "
01945                          << (*it).second.size()
01946                          << " entries."
01947                          << std::endl;
01948           }
01949       }
01950 
01951 
01952     // Loop over all the sets we just created and compute intersections with the
01953     // this processor's set.  Obviously, don't intersect with ourself.
01954     for (proc_nodes_touched_iterator it = proc_nodes_touched.begin();
01955          it != proc_nodes_touched.end();
01956          ++it)
01957       {
01958         // Don't compute intersections with ourself
01959         if ((*it).first == this->processor_id())
01960           continue;
01961 
01962         // Otherwise, compute intersection with other processor and ourself
01963         std::set<unsigned>& my_set = proc_nodes_touched[this->processor_id()];
01964         std::set<unsigned>& other_set = (*it).second;
01965         std::set<unsigned>& result_set = this->proc_nodes_touched_intersections[ (*it).first ]; // created if does not exist
01966 
01967         std::set_intersection(my_set.begin(), my_set.end(),
01968                               other_set.begin(), other_set.end(),
01969                               std::inserter(result_set, result_set.end()));
01970       }
01971 
01972     if (verbose)
01973       {
01974         for (proc_nodes_touched_iterator it = this->proc_nodes_touched_intersections.begin();
01975              it != this->proc_nodes_touched_intersections.end();
01976              ++it)
01977           {
01978             libMesh::out << "[" << this->processor_id()
01979                          << "] this->proc_nodes_touched_intersections[" << (*it).first << "] has "
01980                          << (*it).second.size()
01981                          << " entries."
01982                          << std::endl;
01983           }
01984       }
01985 
01986     // Compute the set_union of all the preceding intersections.  This will be the set of
01987     // border node IDs for this processor.
01988     for (proc_nodes_touched_iterator it = this->proc_nodes_touched_intersections.begin();
01989          it != this->proc_nodes_touched_intersections.end();
01990          ++it)
01991       {
01992         std::set<unsigned>& other_set = (*it).second;
01993         std::set<unsigned> intermediate_result; // Don't think we can insert into one of the sets we're unioning...
01994 
01995         std::set_union(this->border_node_ids.begin(), this->border_node_ids.end(),
01996                        other_set.begin(), other_set.end(),
01997                        std::inserter(intermediate_result, intermediate_result.end()));
01998 
01999         // Swap our intermediate result into the final set
02000         this->border_node_ids.swap(intermediate_result);
02001       }
02002 
02003     if (verbose)
02004       {
02005         libMesh::out << "[" << this->processor_id()
02006                      << "] border_node_ids.size()=" << this->border_node_ids.size()
02007                      << std::endl;
02008       }
02009   } // end scope for border node ID creation
02010 
02011   // Store the number of border node IDs to be written to Nemesis file
02012   this->num_border_nodes = cast_int<int>(this->border_node_ids.size());
02013 }
02014 
02015 
02016 
02017 
02018 
02019 void Nemesis_IO_Helper::write_nodesets(const MeshBase & mesh)
02020 {
02021   // Write the nodesets.  In Nemesis, the idea is to "create space" for the global
02022   // set of boundary nodesets, but to only write node IDs which are local to the current
02023   // processor.  This is what is done in Nemesis files created by the "loadbal" script.
02024 
02025   // Store a map of vectors for boundary node IDs on this processor.
02026   // Use a vector of int here so it can be passed directly to Exodus.
02027   std::map<boundary_id_type, std::vector<int> > local_node_boundary_id_lists;
02028   typedef std::map<boundary_id_type, std::vector<int> >::iterator local_node_boundary_id_lists_iterator;
02029 
02030   // FIXME: We should build this list only one time!!  We already built it above, but we
02031   // did not have the libmesh to exodus node mapping at that time... for now we'll just
02032   // build it here again, hopefully it's small relative to the size of the entire mesh.
02033   std::vector<dof_id_type> boundary_node_list;
02034   std::vector<boundary_id_type> boundary_node_boundary_id_list;
02035   mesh.get_boundary_info().build_node_list
02036     (boundary_node_list, boundary_node_boundary_id_list);
02037 
02038   if (verbose)
02039     {
02040       libMesh::out << "[" << this->processor_id() << "] boundary_node_list.size()="
02041                    << boundary_node_list.size() << std::endl;
02042       libMesh::out << "[" << this->processor_id() << "] (boundary_node_id, boundary_id) = ";
02043       for (unsigned i=0; i<boundary_node_list.size(); ++i)
02044         {
02045           libMesh::out << "(" << boundary_node_list[i] << ", " << boundary_node_boundary_id_list[i] << ") ";
02046         }
02047       libMesh::out << std::endl;
02048     }
02049 
02050   // For each node in the node list, add it to the vector of node IDs for that
02051   // set for the local processor.  This will be used later when writing Exodus
02052   // nodesets.
02053   for (unsigned i=0; i<boundary_node_list.size(); ++i)
02054     {
02055       // Don't try to grab a reference to the vector unless the current node is attached
02056       // to a local element.  Otherwise, another processor will be responsible for writing it in its nodeset.
02057       std::map<int, int>::iterator it = this->libmesh_node_num_to_exodus.find( boundary_node_list[i] );
02058 
02059       if ( it != this->libmesh_node_num_to_exodus.end() )
02060         {
02061           // Get reference to the vector where this node ID will be inserted.  If it
02062           // doesn't yet exist, this will create it.
02063           std::vector<int>& current_id_set = local_node_boundary_id_lists[ boundary_node_boundary_id_list[i] ];
02064 
02065           // Push back Exodus-mapped node ID for this set
02066           // TODO: reserve space in these vectors somehow.
02067           current_id_set.push_back( (*it).second );
02068         }
02069     }
02070 
02071   // See what we got
02072   if (verbose)
02073     {
02074       for (std::map<boundary_id_type, std::vector<int> >::iterator it = local_node_boundary_id_lists.begin();
02075            it != local_node_boundary_id_lists.end();
02076            ++it)
02077         {
02078           libMesh::out << "[" << this->processor_id() << "] ID: " << (*it).first << ", ";
02079 
02080           std::vector<int>& current_id_set = (*it).second;
02081 
02082           // Libmesh node ID (Exodus Node ID)
02083           for (unsigned j=0; j<current_id_set.size(); ++j)
02084             libMesh::out << current_id_set[j]
02085                          << ", ";
02086 
02087           libMesh::out << std::endl;
02088         }
02089     }
02090 
02091   // Loop over *global* nodeset IDs, call the Exodus API.  Note that some nodesets may be empty
02092   // for a given processor.
02093   for (unsigned i=0; i<this->global_nodeset_ids.size(); ++i)
02094     {
02095       if (verbose)
02096         {
02097           libMesh::out << "[" << this->processor_id()
02098                        << "] Writing out Exodus nodeset info for ID: " << global_nodeset_ids[i] << std::endl;
02099         }
02100 
02101       // Convert current global_nodeset_id into an exodus ID, which can't be zero...
02102       int exodus_id = global_nodeset_ids[i];
02103 
02104       /*
02105       // Exodus can't handle zero nodeset IDs (?)  Use max short here since
02106       // when libmesh reads it back in, it will want to store it as a short...
02107       if (exodus_id==0)
02108       exodus_id = std::numeric_limits<short>::max();
02109       */
02110 
02111       // Try to find this boundary ID in the local list we created
02112       local_node_boundary_id_lists_iterator it =
02113         local_node_boundary_id_lists.find (cast_int<boundary_id_type>(this->global_nodeset_ids[i]));
02114 
02115       // No nodes found for this boundary ID on this processor
02116       if (it == local_node_boundary_id_lists.end())
02117         {
02118           if (verbose)
02119             libMesh::out << "[" << this->processor_id()
02120                          << "] No nodeset data for ID: " << global_nodeset_ids[i]
02121                          << " on this processor." << std::endl;
02122 
02123           // Call the Exodus interface to write the parameters of this node set
02124           this->ex_err = exII::ex_put_node_set_param(this->ex_id,
02125                                                      exodus_id,
02126                                                      0, /* No nodes for this ID */
02127                                                      0  /* No distribution factors */);
02128           EX_CHECK_ERR(this->ex_err, "Error writing nodeset parameters in Nemesis");
02129 
02130         }
02131       else // Boundary ID *was* found in list
02132         {
02133           // Get reference to the vector of node IDs
02134           std::vector<int>& current_nodeset_ids = (*it).second;
02135 
02136           // Call the Exodus interface to write the parameters of this node set
02137           this->ex_err = exII::ex_put_node_set_param(this->ex_id,
02138                                                      exodus_id,
02139                                                      current_nodeset_ids.size(),
02140                                                      0  /* No distribution factors */);
02141 
02142           EX_CHECK_ERR(this->ex_err, "Error writing nodeset parameters in Nemesis");
02143 
02144           // Call Exodus interface to write the actual node IDs for this boundary ID
02145           this->ex_err = exII::ex_put_node_set(this->ex_id,
02146                                                exodus_id,
02147                                                &current_nodeset_ids[0]);
02148 
02149           EX_CHECK_ERR(this->ex_err, "Error writing nodesets in Nemesis");
02150 
02151         }
02152     } // end loop over global nodeset IDs
02153 }
02154 
02155 
02156 
02157 
02158 void Nemesis_IO_Helper::write_sidesets(const MeshBase & mesh)
02159 {
02160   // Write the sidesets.  In Nemesis, the idea is to "create space" for the global
02161   // set of boundary sidesets, but to only write sideset IDs which are local to the current
02162   // processor.  This is what is done in Nemesis files created by the "loadbal" script.
02163   // See also: ExodusII_IO_Helper::write_sidesets()...
02164 
02165 
02166   // Store a map of vectors for boundary side IDs on this processor.
02167   // Use a vector of int here so it can be passed directly to Exodus.
02168   std::map<boundary_id_type, std::vector<int> > local_elem_boundary_id_lists;
02169   std::map<boundary_id_type, std::vector<int> > local_elem_boundary_id_side_lists;
02170   typedef std::map<boundary_id_type, std::vector<int> >::iterator local_elem_boundary_id_lists_iterator;
02171 
02172   ExodusII_IO_Helper::ElementMaps em;
02173 
02174   // FIXME: We already built this list once, we should reuse that information!
02175   std::vector< dof_id_type > bndry_elem_list;
02176   std::vector< unsigned short int > bndry_side_list;
02177   std::vector< boundary_id_type > bndry_id_list;
02178 
02179   mesh.get_boundary_info().build_side_list
02180     (bndry_elem_list, bndry_side_list, bndry_id_list);
02181 
02182   // Integer looping, skipping non-local elements
02183   for (unsigned i=0; i<bndry_elem_list.size(); ++i)
02184     {
02185       // Get pointer to current Elem
02186       const Elem* elem = mesh.elem(bndry_elem_list[i]);
02187 
02188       // If element is local, process it
02189       if (elem->processor_id() == this->processor_id())
02190         {
02191           std::vector<const Elem*> family;
02192 #ifdef LIBMESH_ENABLE_AMR
02193           // We need to build up active elements if AMR is enabled and add
02194           // them to the exodus sidesets instead of the potentially inactive "parent" elements
02195           // Technically we don't need to "reset" the tree since the vector was just created.
02196           elem->active_family_tree_by_side(family, bndry_side_list[i], /*reset tree=*/false);
02197 #else
02198           // If AMR is not even enabled, just push back the element itself
02199           family.push_back( elem );
02200 #endif
02201 
02202           // Loop over all the elements in the family tree, store their converted IDs
02203           // and side IDs to the map's vectors.  TODO: Somehow reserve enough space for these
02204           // push_back's...
02205           for (unsigned int j=0; j<family.size(); ++j)
02206             {
02207               const ExodusII_IO_Helper::Conversion conv = em.assign_conversion(mesh.elem(family[j]->id())->type());
02208 
02209               // Use the libmesh to exodus datastructure map to get the proper sideset IDs
02210               // The datastructure contains the "collapsed" contiguous ids.
02211               //
02212               // We know the parent element is local, but let's be absolutely sure that all the children have been
02213               // actually mapped to Exodus IDs before we blindly try to add them...
02214               std::map<int,int>::iterator it = this->libmesh_elem_num_to_exodus.find( family[j]->id() );
02215               if (it != this->libmesh_elem_num_to_exodus.end())
02216                 {
02217                   local_elem_boundary_id_lists[ bndry_id_list[i] ].push_back( (*it).second );
02218                   local_elem_boundary_id_side_lists[ bndry_id_list[i] ].push_back(conv.get_inverse_side_map( bndry_side_list[i] ));
02219                 }
02220               else
02221                 libmesh_error_msg("Error, no Exodus mapping for Elem " \
02222                                   << family[j]->id()                  \
02223                                   << " on processor "                 \
02224                                   << this->processor_id());
02225             }
02226         }
02227     }
02228 
02229 
02230   // Loop over *global* sideset IDs, call the Exodus API.  Note that some sidesets may be empty
02231   // for a given processor.
02232   for (unsigned i=0; i<this->global_sideset_ids.size(); ++i)
02233     {
02234       if (verbose)
02235         {
02236           libMesh::out << "[" << this->processor_id()
02237                        << "] Writing out Exodus sideset info for ID: " << global_sideset_ids[i] << std::endl;
02238         }
02239 
02240       // Convert current global_sideset_id into an exodus ID, which can't be zero...
02241       int exodus_id = global_sideset_ids[i];
02242 
02243       /*
02244       // Exodus can't handle zero sideset IDs (?)  Use max short here since
02245       // when libmesh reads it back in, it will want to store it as a short...
02246       if (exodus_id==0)
02247       exodus_id = std::numeric_limits<short>::max();
02248       */
02249 
02250       // Try to find this boundary ID in the local list we created
02251       local_elem_boundary_id_lists_iterator it =
02252         local_elem_boundary_id_lists.find (cast_int<boundary_id_type>(this->global_sideset_ids[i]));
02253 
02254       // No sides found for this boundary ID on this processor
02255       if (it == local_elem_boundary_id_lists.end())
02256         {
02257           if (verbose)
02258             libMesh::out << "[" << this->processor_id()
02259                          << "] No sideset data for ID: " << global_sideset_ids[i]
02260                          << " on this processor." << std::endl;
02261 
02262           // Call the Exodus interface to write the parameters of this side set
02263           this->ex_err = exII::ex_put_side_set_param(this->ex_id,
02264                                                      exodus_id,
02265                                                      0, /* No sides for this ID */
02266                                                      0  /* No distribution factors */);
02267           EX_CHECK_ERR(this->ex_err, "Error writing sideset parameters in Nemesis");
02268 
02269         }
02270       else // Boundary ID *was* found in list
02271         {
02272           // Get iterator to sides vector as well
02273           local_elem_boundary_id_lists_iterator it_sides =
02274             local_elem_boundary_id_side_lists.find (cast_int<boundary_id_type>(this->global_sideset_ids[i]));
02275 
02276           libmesh_assert (it_sides != local_elem_boundary_id_side_lists.end());
02277 
02278           // Get reference to the vector of elem IDs
02279           std::vector<int>& current_sideset_elem_ids = (*it).second;
02280 
02281           // Get reference to the vector of side IDs
02282           std::vector<int>& current_sideset_side_ids = (*it_sides).second;
02283 
02284           // Call the Exodus interface to write the parameters of this side set
02285           this->ex_err = exII::ex_put_side_set_param(this->ex_id,
02286                                                      exodus_id,
02287                                                      current_sideset_elem_ids.size(),
02288                                                      0  /* No distribution factors */);
02289 
02290           EX_CHECK_ERR(this->ex_err, "Error writing sideset parameters in Nemesis");
02291 
02292           // Call Exodus interface to write the actual side IDs for this boundary ID
02293           this->ex_err = exII::ex_put_side_set(this->ex_id,
02294                                                exodus_id,
02295                                                &current_sideset_elem_ids[0],
02296                                                &current_sideset_side_ids[0]);
02297 
02298           EX_CHECK_ERR(this->ex_err, "Error writing sidesets in Nemesis");
02299         }
02300     } // end for loop over global sideset IDs
02301 }
02302 
02303 
02304 
02305 void Nemesis_IO_Helper::write_nodal_coordinates(const MeshBase & mesh, bool /*use_discontinuous*/)
02306 {
02307   // Make sure that the reference passed in is really a ParallelMesh
02308   // const ParallelMesh& pmesh = cast_ref<const ParallelMesh&>(mesh);
02309 
02310   unsigned local_num_nodes =
02311     cast_int<unsigned int>(this->exodus_node_num_to_libmesh.size());
02312 
02313   x.resize(local_num_nodes);
02314   y.resize(local_num_nodes);
02315   z.resize(local_num_nodes);
02316 
02317   // Just loop over our list outputing the nodes the way we built the map
02318   for (unsigned int i=0; i<local_num_nodes; ++i)
02319     {
02320       const Node & node = *mesh.node_ptr(this->exodus_node_num_to_libmesh[i]);
02321       x[i]=node(0);
02322       y[i]=node(1);
02323       z[i]=node(2);
02324     }
02325 
02326   if (local_num_nodes)
02327     {
02328       if (_single_precision)
02329         {
02330           std::vector<float>
02331             x_single(x.begin(), x.end()),
02332             y_single(y.begin(), y.end()),
02333             z_single(z.begin(), z.end());
02334 
02335           ex_err = exII::ex_put_coord(ex_id, &x_single[0], &y_single[0], &z_single[0]);
02336         }
02337       else
02338         {
02339           // Call Exodus API to write nodal coordinates...
02340           ex_err = exII::ex_put_coord(ex_id, &x[0], &y[0], &z[0]);
02341         }
02342       EX_CHECK_ERR(ex_err, "Error writing node coordinates");
02343 
02344       // And write the nodal map we created for them
02345       ex_err = exII::ex_put_node_num_map(ex_id, &(this->exodus_node_num_to_libmesh[0]));
02346       EX_CHECK_ERR(ex_err, "Error writing node num map");
02347     }
02348   else // Does the Exodus API want us to write empty nodal coordinates?
02349     {
02350       ex_err = exII::ex_put_coord(ex_id, NULL, NULL, NULL);
02351       EX_CHECK_ERR(ex_err, "Error writing empty node coordinates");
02352 
02353       ex_err = exII::ex_put_node_num_map(ex_id, NULL);
02354       EX_CHECK_ERR(ex_err, "Error writing empty node num map");
02355     }
02356 }
02357 
02358 
02359 
02360 
02361 
02362 void Nemesis_IO_Helper::write_elements(const MeshBase & mesh, bool /*use_discontinuous*/)
02363 {
02364 
02365   // Loop over all blocks, even if we don't have elements in each block.
02366   // If we don't have elements we need to write out a 0 for that block...
02367   for (unsigned int i=0; i<static_cast<unsigned>(this->num_elem_blks_global); ++i)
02368     {
02369       // Search for the current global block ID in the map
02370       std::map<int, std::vector<int> >::iterator it =
02371         this->block_id_to_elem_connectivity.find( this->global_elem_blk_ids[i] );
02372 
02373       // If not found, write a zero to file....
02374       if (it == this->block_id_to_elem_connectivity.end())
02375         {
02376           this->ex_err = exII::ex_put_elem_block(this->ex_id,
02377                                                  this->global_elem_blk_ids[i],
02378                                                  "Empty",
02379                                                  0, /* n. elements in this block */
02380                                                  0, /* n. nodes per element */
02381                                                  0);  /* number of attributes per element */
02382 
02383           EX_CHECK_ERR(this->ex_err, "Error writing element block from Nemesis.");
02384         }
02385 
02386       // Otherwise, write the actual block information and connectivity to file
02387       else
02388         {
02389           subdomain_id_type block =
02390             cast_int<subdomain_id_type>((*it).first);
02391           std::vector<int> & this_block_connectivity = (*it).second;
02392           std::vector<unsigned int> & elements_in_this_block = subdomain_map[block];
02393 
02394           ExodusII_IO_Helper::ElementMaps em;
02395 
02396           //Use the first element in this block to get representative information.
02397           //Note that Exodus assumes all elements in a block are of the same type!
02398           //We are using that same assumption here!
02399           const ExodusII_IO_Helper::Conversion conv =
02400             em.assign_conversion(mesh.elem(elements_in_this_block[0])->type());
02401 
02402           this->num_nodes_per_elem = mesh.elem(elements_in_this_block[0])->n_nodes();
02403 
02404           ex_err = exII::ex_put_elem_block(ex_id,
02405                                            block,
02406                                            conv.exodus_elem_type().c_str(),
02407                                            elements_in_this_block.size(),
02408                                            num_nodes_per_elem,
02409                                            0);
02410           EX_CHECK_ERR(ex_err, "Error writing element block from Nemesis.");
02411 
02412           ex_err = exII::ex_put_elem_conn(ex_id,
02413                                           block,
02414                                           &this_block_connectivity[0]);
02415           EX_CHECK_ERR(ex_err, "Error writing element connectivities from Nemesis.");
02416         }
02417     } // end loop over global block IDs
02418 
02419   // Only call this once, not in the loop above!
02420   ex_err = exII::ex_put_elem_num_map(ex_id,
02421                                      exodus_elem_num_to_libmesh.empty() ? NULL : &exodus_elem_num_to_libmesh[0]);
02422   EX_CHECK_ERR(ex_err, "Error writing element map");
02423 }
02424 
02425 
02426 
02427 
02428 
02429 void Nemesis_IO_Helper::write_nodal_solution
02430 (const std::vector<Number>& values,
02431  const std::vector<std::string>& names,
02432  int timestep)
02433 {
02434   int num_vars = cast_int<int>(names.size());
02435   //int num_values = values.size(); // Not used?
02436 
02437   for (int c=0; c<num_vars; c++)
02438     {
02439 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
02440       std::vector<Real> real_parts(num_nodes);
02441       std::vector<Real> imag_parts(num_nodes);
02442       std::vector<Real> magnitudes(num_nodes);
02443 
02444       for (int i=0; i<num_nodes; ++i)
02445         {
02446           Number value = values[this->exodus_node_num_to_libmesh[i]*num_vars + c];
02447           real_parts[i] = value.real();
02448           imag_parts[i] = value.imag();
02449           magnitudes[i] = std::abs(value);
02450         }
02451       write_nodal_values(3*c+1,real_parts,timestep);
02452       write_nodal_values(3*c+2,imag_parts,timestep);
02453       write_nodal_values(3*c+3,magnitudes,timestep);
02454 #else
02455       std::vector<Number> cur_soln(num_nodes);
02456 
02457       // Copy out this variable's solution
02458       for (int i=0; i<num_nodes; i++)
02459         cur_soln[i] = values[this->exodus_node_num_to_libmesh[i]*num_vars + c];
02460 
02461       write_nodal_values(c+1,cur_soln,timestep);
02462 #endif
02463     }
02464 }
02465 
02466 
02467 
02468 
02469 std::string Nemesis_IO_Helper::construct_nemesis_filename(const std::string& base_filename)
02470 {
02471   // Build a filename for this processor.  This code is cut-n-pasted from the read function
02472   // and should probably be put into a separate function...
02473   std::ostringstream file_oss;
02474 
02475   // We have to be a little careful here: Nemesis left pads its file
02476   // numbers based on the number of processors, so for example on 10
02477   // processors, we'd have:
02478   // mesh.e.10.00
02479   // mesh.e.10.01
02480   // mesh.e.10.02
02481   // ...
02482   // mesh.e.10.09
02483 
02484   // And on 100 you'd have:
02485   // mesh.e.100.000
02486   // mesh.e.100.001
02487   // ...
02488   // mesh.e.128.099
02489 
02490   // Find the length of the highest processor ID
02491   file_oss << (this->n_processors());
02492   unsigned int field_width = cast_int<unsigned int>(file_oss.str().size());
02493 
02494   if (verbose)
02495     libMesh::out << "field_width=" << field_width << std::endl;
02496 
02497   file_oss.str(""); // reset the string stream
02498   file_oss << base_filename
02499            << '.' << this->n_processors()
02500            << '.' << std::setfill('0') << std::setw(field_width) << this->processor_id();
02501 
02502   // Return the resulting string
02503   return file_oss.str();
02504 }
02505 
02506 } // namespace libMesh
02507 
02508 #endif // #if defined(LIBMESH_HAVE_NEMESIS_API) && defined(LIBMESH_HAVE_EXODUS_API)