/** \defgroup stk_io_module Sierra Toolkit IO
 *
 * \anchor stk_io_example
 * \section stk_io_example_code IO Example Code
 * The code samples below should closely match the code in the example
 * file stk_io/use_cases/io_example.cpp which is compilable and
 * executable. It can be used to experiment with the stk_classic::io and Ioss
 * functionality. If there is any discrepancy between the
 * documentation below and the code found in io_example.cpp; trust the
 * actual code.
 *
 * \subsection include_files Include Files
 * The following include files are required for this example. 
 * \code
 #include <stk_util/parallel/Parallel.hpp>
 #include <init/Ionit_Initializer.h>
 #include <Ioss_SubSystem.h>
 
 #include <stk_mesh/base/Field.hpp>
 #include <stk_mesh/base/FieldData.hpp>
 #include <stk_mesh/base/MetaData.hpp>
 #include <stk_mesh/base/BulkData.hpp>
 #include <stk_mesh/fem/TopologyHelpers.hpp>
 #include <stk_mesh/fem/TopologyDimensions.hpp>
 
 #include <stk_io/IossBridge.hpp>
 * \endcode
 * \subsection main_io_control Main IO Control
 * The io_example function provides all mesh input and results output
 * functionality for this example application. It would most likely be
 * split into multiple functions in a real application.  
 * The function
 * takes as arguments an MPI communicator; the name of the mesh file
 * to read from and the name of the results database to write to.
 *  \code
  void io_example( stk_classic::ParallelMachine comm,
                   const std::string& in_filename,
                   const std::string& out_filename)
 * \endcode

 * \subsection initialization Initialization
 * The IO system must be initialized via a call to
 * Ioss::Init::Initializer.  This sets up which database types are
 * supported and performs other behind the scenes initialization duties.
 * \code
    Ioss::Init::Initializer init_db;
 * \endcode
 *
 * \subsection open_mesh_database Open Mesh Database
 * The input mesh file must be associated with an Ioss::DatabaseIO
 * object. The IO system must be told the type of the database to be
 * opened; in this example, the type is "exodusII".  If the file does
 * not exist or could not be opened, the Ioss::IOFactory will return
 * NULL; if the file does exist and can be opened, but has other
 * problems, then the dbi->ok() function will return false.
 *
 * Once the datbase has been opened, it is then associated with an
 * Ioss::Region which is the main interface to the mesh description
 * stored in the mesh database.
 * \code
    std::string dbtype("exodusII");
    Ioss::DatabaseIO *dbi = Ioss::IOFactory::create(dbtype, in_filename, Ioss::READ_MODEL,
                                                    (MPI_Comm)comm);
    if (dbi == NULL || !dbi->ok()) {
      std::cerr  << "ERROR: Could not open database '" << in_filename
                 << "' of type '" << dbtype << "'\n";
      std::exit(EXIT_FAILURE);
    }

    // NOTE: 'in_region' owns 'dbi' pointer at this time...
    Ioss::Region in_region(dbi, "input_model");
 * \endcode
 *
 * \subsection optional_subsetting Optional Subsetting
 * The stk_classic::io functions provide a basic subsetting capability.  If an
 * Ioss entity (Ioss::ElementBlock, Ioss::NodeSet, Ioss::FaceSet,
 * Ioss::EdgeSet, ...) has the "omitted" property defined and the
 * value of the property is "1", then the associated entity will be
 * omitted from the stk_classic::mesh model.  At any time prior to defining
 * the stk_classic::mesh::MetaData, the application can set the property on
 * any entities that should be omitted from the model.
 *
 * The following code example shows how this subsetting capability
 * works by omitting the element blocks with names "cblock", "eblock",
 * "i1", and "i2". These are element blocks in a file that is used in
 * one of the stk_classic::io use cases.
 *\code    
    // Example command line in current code corresponding to behavior below:
    std::cout << "\nWhen processing file multi-block.g for use case 2, the blocks below will be omitted:\n";
    std::cout << "\tOMIT BLOCK Cblock Eblock I1 I2\n\n";
    Ioss::ElementBlock *eb = in_region.get_element_block("cblock");
    if (eb != NULL)
      eb->property_add(Ioss::Property(std::string("omitted"), 1));

    eb = in_region.get_element_block("eblock");
    if (eb != NULL)
      eb->property_add(Ioss::Property(std::string("omitted"), 1));

    eb = in_region.get_element_block("i1"); 
    if (eb != NULL)
      eb->property_add(Ioss::Property(std::string("omitted"), 1));

    eb = in_region.get_element_block("i2");
    if (eb != NULL)
      eb->property_add(Ioss::Property(std::string("omitted"), 1));
 * \endcode
 *
 * \subsection define_metadata Define MetaData
 * The following block of code shows how the Ioss metadata is
 * queried and used to define the stk_classic::mesh::MetaData for the analysis
 * model.  Each of the process_* functions is described in more
 * detail later on.
 * \code
    stk_classic::mesh::MetaData meta_data;
    process_elementblocks(in_region, meta_data);
    process_nodeblocks(in_region,    meta_data);
    process_facesets(in_region,      meta_data);
    process_edgesets(in_region,      meta_data);
    process_nodesets(in_region,      meta_data);
 * \endcode
 * \subsection define_other_info Define Other Information
 * At this point, the application would define other
 * stk_classic::mesh::Field's that exist on the mesh parts or any other data
 * that needs to be set before the meta data is comitted. Once this is
 * done, the meta data can be commited.
 * \code
    meta_data.commit();
 * \endcode
 * \subsection define_bulk_data Define Bulk Data
 * The following block of code defines a stk_classic::mesh::BulkData object
 * and populates it with the bulk data from the mesh database. Each of
 * the process_* function is described in more detail later on.
 * Following this, the analysis mesh is defined and ready for use.
 * \code
    stk_classic::mesh::BulkData bulk_data(meta_data, comm);
    process_elementblocks(in_region, bulk_data);
    process_nodeblocks(in_region,    bulk_data);
    process_facesets(in_region,      bulk_data);
    process_edgesets(in_region,      bulk_data);
    process_nodesets(in_region,      bulk_data);
 * \endcode
 *
 * \section Results Output
 * Once the analysis mesh is defined, the application will typically
 * want to define one or more output databases; for example, results,
 * heartbeat, history, and/or restart. In the example below, a results
 * database is defined and associated with an Ioss::Region.  The
 * define_output_db() function extracts the metadata from the
 * stk_classic::mesh MetaData and BulkData so that the output region
 * corresponds as much as possible to the input region. The
 * "in_region" argument to the function is optional and if present
 * will synchronize names and ids in the input mesh with the
 * corresponding entities in the output mesh.
 *
 * Once the output database metadata is defined, the write_output_db()
 * function is called to output the initial data to the file
 * corresponding to this database. Following this call, the file
 * should contain all of the non-transient data corresponding to the
 * analysis mesh.
 * \code
    Ioss::DatabaseIO *dbo = Ioss::IOFactory::create(dbtype, out_filename,
                                                    Ioss::WRITE_RESULTS,
                                                    (MPI_Comm)comm);
    if (dbo == NULL || !dbo->ok()) {
      std::cerr << "ERROR: Could not open results database '" << out_filename
                << "' of type '" << dbtype << "'\n";
      std::exit(EXIT_FAILURE);
    }

    // NOTE: 'out_region' owns 'dbo' pointer at this time...
    Ioss::Region out_region(dbo, "results_output");
      
    stk_classic::io::define_output_db(out_region, bulk_data, &in_region);
    stk_classic::io::write_output_db(out_region,  bulk_data);
 * \endcode
 * \subsection define_transient Define Transient Output Fields
 * At this time, the application would define what stk_classic::mesh::Field
 * fields should be output to the results database and what they would
 * be named.
 *
 * In this example, all fields existing on the input mesh database are
 * defined on the parts in the stk_classic::mesh.
 *
 * The real app would also only register a subset of the stk_classic::mesh 
 * fields as output fields and would probably have a mapping from the
 * internally used name to some name picked by the user. In this 
 * example, all Ioss::Field::TRANSIENT fields defined on the stk_classic::mesh
 * are output to the results database and the internal stk_classic::mesh
 * field name is used as the name on the database....
 *
 * See ioss_add_fields() for more details on how to add a field.
 * \code
    out_region.begin_mode(Ioss::STATE_DEFINE_TRANSIENT);

    // Special processing for nodeblock (all nodes in model)...
    stk_classic::io::ioss_add_fields(meta_data.universal_part(), stk_classic::mesh::Node,
                             out_region.get_node_blocks()[0],
                             Ioss::Field::TRANSIENT);
    
    const stk_classic::mesh::PartVector & all_parts = meta_data.get_parts();
    for ( stk_classic::mesh::PartVector::const_iterator
            ip = all_parts.begin(); ip != all_parts.end(); ++ip ) {

      stk_classic::mesh::Part * const part = *ip;

      // Check whether this part should be output to results database.
      if (stk_classic::io::is_part_io_part(*part)) {
        // Get Ioss::GroupingEntity corresponding to this part...
        Ioss::GroupingEntity *entity = out_region.get_entity(part->name());
        if (entity != NULL) {
          if (entity->type() == Ioss::FACESET || entity->type() == Ioss::EDGESET) {
            int block_count = entity->block_count();
            for (int i=0; i < block_count; i++) {
              Ioss::EntityBlock *fb = entity->get_block(i);
              stk_classic::io::ioss_add_fields(*part, part->primary_entity_type(),
                                       fb, Ioss::Field::TRANSIENT);
            }
          } else {
            stk_classic::io::ioss_add_fields(*part, part->primary_entity_type(),
                                     entity, Ioss::Field::TRANSIENT);
          }
        } else {
          ///  ...handle error...
        }
      }
    }
    out_region.end_mode(Ioss::STATE_DEFINE_TRANSIENT);
 * \endcode
 * \subsection read_write_transient Read and Write Transient Fields (Execute Loop)
 * At this time, the input and output databases are ready for reading
 * and/or writing transient field data. This is where an application
 * would typically have its execute loop which marches through time.
 *
 * In the example below, the code queries the input mesh region for
 * the number of timesteps it contains and then simply reads all data
 * on the input database for each timestep and writes the
 * corresponding data to the results database.
 * \code
    // Read and Write transient fields... 
    out_region.begin_mode(Ioss::STATE_TRANSIENT);
    int timestep_count = in_region.get_property("state_count").get_int();
    for (int step = 1; step <= timestep_count; step++) {
      double time = in_region.get_state_time(step);

      // Read data from the io input mesh database into stk_classic::mesh fields...
      process_input_request(in_region, bulk_data, step);

      // execute()

      // Write data from the stk_classic::mesh fields out to the output database.a
      int out_step = out_region.add_state(time);
      process_output_request(out_region, bulk_data, out_step);
    }
    out_region.end_mode(Ioss::STATE_TRANSIENT);
  }
  * \endcode
  * \subsection end_app End of Application
  * As the input and output Ioss::Region objects go out of scope, they
  * will close the files associated with them and do all cleanup.
  *
  * \section processing_details_metadata Entity Processing Routine Details -- MetaData.
  * \subsection process_nodeblocks
  * \code
  void process_nodeblocks(Ioss::Region &region, stk_classic::mesh::MetaData &meta)
  {
    const Ioss::NodeBlockContainer& node_blocks = region.get_node_blocks();
    assert(node_blocks.size() == 1);

    Ioss::NodeBlock *nb = node_blocks[0];

    assert(nb->field_exists("mesh_model_coordinates"));
    Ioss::Field coordinates = nb->get_field("mesh_model_coordinates");
    int spatial_dim = coordinates.transformed_storage()->component_count();
    
    stk_classic::mesh::Field<double,stk_classic::mesh::Cartesian> & coord_field =
      meta.declare_field<stk_classic::mesh::Field<double,stk_classic::mesh::Cartesian> >("coordinates");

    meta.put_field( coord_field, stk_classic::mesh::Node, meta.universal_part(),
                    spatial_dim);

   // For this case we are just defining a field for each
   // transient field that is present in the mesh...
    stk_classic::io::define_io_fields(nb, Ioss::Field::TRANSIENT, meta.universal_part(),stk_classic::mesh::Node);
  }
  * \endcode
  * \subsection process_elementblocks
  * \code
  void process_elementblocks(Ioss::Region &region, stk_classic::mesh::MetaData &meta)
  {
    const Ioss::ElementBlockContainer& elem_blocks = region.get_element_blocks();
    stk_classic::io::default_part_processing(elem_blocks, meta, stk_classic::mesh::Element);

    // Parts were created above, now handle element block specific
    // information (topology, attributes, ...);
    for(Ioss::ElementBlockContainer::const_iterator it = elem_blocks.begin();
        it != elem_blocks.end(); ++it) {
      Ioss::ElementBlock *entity = *it;
      
      if (stk_classic::io::include_entity(entity)) {
        stk_classic::mesh::Part* const part = meta.get_part(entity->name());
        assert(part != NULL);

        // Element Block attributes (if any)...  For this example 
        // we are just defining a field for each attribute field 
        // that is present in the mesh...
        stk_classic::io::define_io_fields(entity, Ioss::Field::ATTRIBUTE,
                                  *part, part->primary_entity_type());

        // For this case we are just defining a field for each
        // transient field that is present in the mesh...
        stk_classic::io::define_io_fields(entity, Ioss::Field::TRANSIENT,
                                  *part, part->primary_entity_type());

        std::cout << entity->type_string() << ": " << entity->name()
                  << " , celltop = " << stk_classic::mesh::get_cell_topology(*part)->name
                  << std::endl ;
      }
    }
  }
  * \endcode
  * \subsection process_nodesets
  * \code
  void process_nodesets(Ioss::Region &region, stk_classic::mesh::MetaData &meta)
  {
    const Ioss::NodeSetContainer& node_sets = region.get_nodesets();
    stk_classic::io::default_part_processing(node_sets, meta, stk_classic::mesh::Node);
    
    // In this example, "distribution_factor" is a default field that
    // is automatically declared on all objects that it exists on as
    // is done in current framework?
    stk_classic::mesh::Field<double> & distribution_factors_field =
      meta.declare_field<stk_classic::mesh::Field<double> >("distribution_factors");

    for(Ioss::NodeSetContainer::const_iterator it = node_sets.begin();
        it != node_sets.end(); ++it) {
      Ioss::NodeSet *entity = *it;

      if (stk_classic::io::include_entity(entity)) {
        stk_classic::mesh::Part* const part = meta.get_part(entity->name());
        assert(part != NULL);
        assert(entity->field_exists("distribution_factors"));

        meta.put_field(distribution_factors_field, stk_classic::mesh::Node, *part);

        // For this case we are just defining a field for each
        // transient field that is present in the mesh...
        stk_classic::io::define_io_fields(entity, Ioss::Field::TRANSIENT,
                                  *part, part->primary_entity_type());
      }
    }
  }

  * \endcode
  * \subsection process_surface_entity
  * \code
  void process_surface_entity(Ioss::GroupingEntity *entity, stk_classic::mesh::MetaData &meta,
                              stk_classic::mesh::EntityType entity_type)
  {
    assert(entity->type() == Ioss::FACESET || entity->type() == Ioss::EDGESET);
    if (entity->type() == Ioss::FACESET) {
      Ioss::FaceSet *fs = dynamic_cast<Ioss::FaceSet *>(entity);
      assert(fs != NULL);
      const Ioss::FaceBlockContainer& blocks = fs->get_face_blocks();
      stk_classic::io::default_part_processing(blocks, meta, entity_type);
    } else if (entity->type() == Ioss::EDGESET) {
      Ioss::EdgeSet *es = dynamic_cast<Ioss::EdgeSet *>(entity);
      assert(es != NULL);
      const Ioss::EdgeBlockContainer& blocks = es->get_edge_blocks();
      stk_classic::io::default_part_processing(blocks, meta, entity_type);
    }

    stk_classic::mesh::Part* const fs_part = meta.get_part(entity->name());
    assert(fs_part != NULL);
    
    stk_classic::mesh::Field<double, stk_classic::mesh::ElementNode> *distribution_factors_field = NULL;
    bool surface_df_defined = false; // Has the surface df field been defined yet?
      

    int block_count = entity->block_count();
    for (int i=0; i < block_count; i++) {
      Ioss::EntityBlock *fb = entity->get_block(i);
      if (stk_classic::io::include_entity(fb)) {
        std::cout << fb->type_string() << " " << fb->name() << "\n";
        stk_classic::mesh::Part * const fb_part = meta.get_part(fb->name());
        assert(fb_part != NULL);
        meta.declare_part_subset(*fs_part, *fb_part);
      
        if (fb->field_exists("distribution_factors")) {
          if (!surface_df_defined) {
            std::string field_name = entity->name() + "_distribution_factors";
            distribution_factors_field =
              &meta.declare_field<stk_classic::mesh::Field<double, stk_classic::mesh::ElementNode> >(field_name);
            stk_classic::io::set_distribution_factor_field(*fs_part, *distribution_factors_field);
            surface_df_defined = true;
          }
          stk_classic::io::set_distribution_factor_field(*fb_part, *distribution_factors_field);
          int face_node_count = fb->topology()->number_nodes();
          meta.put_field(*distribution_factors_field, fb_part->primary_entity_type(),
                         *fb_part, face_node_count);
        }

        // For this case we are just defining a field for each
        // transient field that is present in the mesh...
        stk_classic::io::define_io_fields(fb, Ioss::Field::TRANSIENT,
                                  *fb_part, fb_part->primary_entity_type());
      }
    }
  }

  * \endcode
  * \subsection process_facesets
  * \code
  void process_facesets(Ioss::Region &region, stk_classic::mesh::MetaData &meta)
  {
    const Ioss::FaceSetContainer& face_sets = region.get_facesets();
    stk_classic::io::default_part_processing(face_sets, meta, stk_classic::mesh::Face);
    
    for(Ioss::FaceSetContainer::const_iterator it = face_sets.begin();
        it != face_sets.end(); ++it) {
      Ioss::FaceSet *entity = *it;

      if (stk_classic::io::include_entity(entity)) {
        process_surface_entity(entity, meta, stk_classic::mesh::Face);
      }
    }
  }

  * \endcode
  * \subsection process_edgesets
  * \code
  void process_edgesets(Ioss::Region &region, stk_classic::mesh::MetaData &meta)
  {
    const Ioss::EdgeSetContainer& edge_sets = region.get_edgesets();
    stk_classic::io::default_part_processing(edge_sets, meta, stk_classic::mesh::Edge);

    for(Ioss::EdgeSetContainer::const_iterator it = edge_sets.begin();
        it != edge_sets.end(); ++it) {
      Ioss::EdgeSet *entity = *it;

      if (stk_classic::io::include_entity(entity)) {
        process_surface_entity(entity, meta, stk_classic::mesh::Edge);
      }
    }
  }
  * \endcode
  * \section processing_details_bulkdata Entity Processing Routine Details -- BulkData
  * \subsection process_nodeblocks
  * \code
  void process_nodeblocks(Ioss::Region &region, stk_classic::mesh::BulkData &bulk)
  {
    // This must be called after the "process_element_blocks" call
    // since there may be nodes that exist in the database that are
    // not part of the analysis mesh due to subsetting of the element
    // blocks. 

    const Ioss::NodeBlockContainer& node_blocks = region.get_node_blocks();
    assert(node_blocks.size() == 1);

    Ioss::NodeBlock *nb = node_blocks[0];

    std::vector<const stk_classic::mesh::Entity*> nodes;
    stk_classic::io::get_entity_list(nb, stk_classic::mesh::Node, bulk, nodes);
      
    const stk_classic::mesh::MetaData& meta = MetaData::get(bulk);

    // NOTE: Application would probably store this field (and others)
    // somewhere after the declaration instead of looking it up each
    // time it is needed.
    stk_classic::mesh::Field<double,stk_classic::mesh::Cartesian> *coord_field =
      meta.get_field<stk_classic::mesh::Field<double,stk_classic::mesh::Cartesian> >("coordinates");

    stk_classic::io::field_data_from_ioss(coord_field, nodes, nb, "mesh_model_coordinates");
  }

  * \endcode
  * \subsection process_elementblocks
  * \code
  void process_elementblocks(Ioss::Region &region, stk_classic::mesh::BulkData &bulk)
  {
    const Ioss::ElementBlockContainer& elem_blocks = region.get_element_blocks();

    for(Ioss::ElementBlockContainer::const_iterator it = elem_blocks.begin();
        it != elem_blocks.end(); ++it) {
      Ioss::ElementBlock *entity = *it;

      if (stk_classic::io::include_entity(entity)) {
        const std::string &name = entity->name();
        const stk_classic::mesh::MetaData& meta = MetaData::get(bulk);
        stk_classic::mesh::Part* const part = meta.get_part(name);
        assert(part != NULL);
        
        const CellTopologyData* cell_topo = stk_classic::mesh::get_cell_topology(*part);
        assert(cell_topo != NULL);

        std::vector<stk_classic::mesh::entity_id_type> elem_ids ;
        std::vector<stk_classic::mesh::entity_id_type> connectivity ;
        
        entity->get_field_data("ids", elem_ids);
        entity->get_field_data("connectivity", connectivity);

        int element_count = elem_ids.size();
        int nodes_per_elem = cell_topo->node_count ;

        std::vector<const stk_classic::mesh::Entity*> elements(element_count);
        for(int i=0; i<element_count; ++i) {
          stk_classic::mesh::entity_id_type *conn = &connectivity[i*nodes_per_elem];
          elements[i] = &stk_classic::mesh::declare_element(bulk, *part, elem_ids[i], conn);
        }

        // For this example, we are just taking all attribute fields
        // found on the io database and populating fields on the
        // corresponding mesh part.  In practice, would probably be
        // selective about which attributes to use...
        Ioss::NameList names;
        entity->field_describe(Ioss::Field::ATTRIBUTE, &names);
        for (Ioss::NameList::const_iterator I = names.begin(); I != names.end(); ++I) {
          if (*I == "attribute" && names.size() > 1)
            continue;
          stk_classic::mesh::FieldBase *field = meta.get_field<stk_classic::mesh::FieldBase>(*I);
          stk_classic::io::field_data_from_ioss(field, elements, entity, *I);
          
        }
      }
    }
  }

  * \endcode
  * \subsection process_nodesets
  * \code
  void process_nodesets(Ioss::Region &region, stk_classic::mesh::BulkData &bulk)
  {
    // Should only process nodes that have already been defined via the element
    // blocks connectivity lists.
    const Ioss::NodeSetContainer& node_sets = region.get_nodesets();

    for(Ioss::NodeSetContainer::const_iterator it = node_sets.begin();
        it != node_sets.end(); ++it) {
      Ioss::NodeSet *entity = *it;

      if (stk_classic::io::include_entity(entity)) {
        const std::string & name = entity->name();
        const stk_classic::mesh::MetaData& meta = MetaData::get(bulk);
        stk_classic::mesh::Part* const part = meta.get_part(name);
        assert(part != NULL);
        stk_classic::mesh::PartVector add_parts( 1 , part );

        std::vector<int> node_ids ;
        int node_count = entity->get_field_data("ids", node_ids);
        
        std::vector<const stk_classic::mesh::Entity*> nodes(node_count);
        for(int i=0; i<node_count; ++i) {
          const stk_classic::mesh::entity_key_type key =
            stk_classic::mesh::entity_key(stk_classic::mesh::Node, node_ids[i]);

          nodes[i] = bulk.get_entity( key );
          if (nodes[i] != NULL)
            bulk.declare_entity(key, add_parts );
        }

        // Application would probably store this field (and others)
        // somewhere after the declaration instead of looking it up
        // each time it is needed.
        stk_classic::mesh::Field<double> *df_field =
          meta.get_field<stk_classic::mesh::Field<double> >("distribution_factors");

        if (df_field != NULL) {
          stk_classic::io::field_data_from_ioss(df_field, nodes, entity, "distribution_factors");
        }
      }
    }
  }

  * \endcode
  * \subsection process_surface_entity
  * \code
  void process_surface_entity(const Ioss::GroupingEntity* io ,
                              stk_classic::mesh::BulkData & bulk)
  {
    assert(io->type() == Ioss::FACESET || io->type() == Ioss::EDGESET);
    const stk_classic::mesh::MetaData& meta = MetaData::get(bulk);

    int block_count = io->block_count();
    for (int i=0; i < block_count; i++) {
      Ioss::EntityBlock *block = io->get_block(i);
      if (stk_classic::io::include_entity(block)) {
        std::vector<int> side_ids ;
        std::vector<int> elem_side ;
        
        stk_classic::mesh::Part * const fb_part = meta.get_part(block->name());

        block->get_field_data("ids", side_ids);
        block->get_field_data("element_side", elem_side);
        
        assert(side_ids.size() * 2 == elem_side.size());
        stk_classic::mesh::PartVector add_parts( 1 , fb_part );
        
        int side_count = side_ids.size();
        std::vector<const stk_classic::mesh::Entity*> sides(side_count);
        for(int is=0; is<side_count; ++is) {
      
          const stk_classic::mesh::entity_key_type elem_key =
            stk_classic::mesh::entity_key(stk_classic::mesh::Element, elem_side[is*2]);
          
          // Ioss uses 1-based side ordinal, stk_classic::mesh uses 0-based.
          // Hence the '-1' in the following line.
          int side_ordinal = elem_side[is*2+1] - 1 ;
          
          stk_classic::mesh::Entity* const elem = bulk.get_entity(elem_key);
          // If NULL, then the element was probably assigned to an
          // element block that appears in the database, but was
          // subsetted out of the analysis mesh. Only process if
          // non-null.
          if (elem != NULL) { 
            stk_classic::mesh::Entity& side =
              stk_classic::mesh::declare_element_side(bulk, side_ids[is], *elem, side_ordinal);
            bulk.change_entity_parts( side, add_parts );
            sides[is] = &side;
          } else {
            sides[is] = NULL;
          }
        }

        const stk_classic::mesh::Field<double, stk_classic::mesh::ElementNode> *df_field =
          stk_classic::io::get_distribution_factor_field(*fb_part);
        if (df_field != NULL) {
          stk_classic::io::field_data_from_ioss(df_field, sides, block, "distribution_factors");
        }
      }
    }
  }

  * \endcode
  * \subsection process_facesets
  * \code
  void process_facesets(Ioss::Region &region, stk_classic::mesh::BulkData &bulk)
  {
    const Ioss::FaceSetContainer& face_sets = region.get_facesets();
    
    for(Ioss::FaceSetContainer::const_iterator it = face_sets.begin();
        it != face_sets.end(); ++it) {
      Ioss::FaceSet *entity = *it;
      
      if (stk_classic::io::include_entity(entity)) {
        process_surface_entity(entity, bulk);
      }
    }
  }

  * \endcode
  * \subsection process_edgesets
  * \code
  void process_edgesets(Ioss::Region &region, stk_classic::mesh::BulkData &bulk)
  {
    const Ioss::EdgeSetContainer& edge_sets = region.get_edgesets();
    
    for(Ioss::EdgeSetContainer::const_iterator it = edge_sets.begin();
        it != edge_sets.end(); ++it) {
      Ioss::EdgeSet *entity = *it;
      
      if (stk_classic::io::include_entity(entity)) {
        process_surface_entity(entity, bulk);
      }
    }
  } 

  * \endcode
  * \section process_field_data Entity Processing Routine Details -- Field Data to/from Ioss
  * \code
  void get_field_data(stk_classic::mesh::BulkData &bulk, stk_classic::mesh::Part &part,
                      stk_classic::mesh::EntityType part_type, 
                      Ioss::GroupingEntity *io_entity,
                      Ioss::Field::RoleType filter_role)
  {
    std::vector<const stk_classic::mesh::Entity*> entities;
    stk_classic::io::get_entity_list(io_entity, part_type, bulk, entities);

    stk_classic::mesh::MetaData & meta = MetaData::get(part);
    stk_classic::mesh::Part &universal = meta.universal_part();
    const std::vector<stk_classic::mesh::FieldBase*> &fields = meta.get_fields();

    std::vector<stk_classic::mesh::FieldBase *>::const_iterator I = fields.begin();
    while (I != fields.end()) {
      const stk_classic::mesh::FieldBase *f = *I; ++I;
      if (stk_classic::io::is_valid_part_field(f, part_type, part, universal, filter_role)) {
        stk_classic::io::field_data_from_ioss(f, entities, io_entity, f->name());
      }
    }
  }

  void put_field_data(stk_classic::mesh::BulkData &bulk, stk_classic::mesh::Part &part,
                      stk_classic::mesh::EntityType part_type, 
                      Ioss::GroupingEntity *io_entity,
                      Ioss::Field::RoleType filter_role)
  {
    std::vector<const stk_classic::mesh::Entity*> entities;
    stk_classic::io::get_entity_list(io_entity, part_type, bulk, entities);
      
    stk_classic::mesh::MetaData & meta = MetaData::get(part);
    stk_classic::mesh::Part &universal = meta.universal_part();
    const std::vector<stk_classic::mesh::FieldBase*> &fields = meta.get_fields();

    std::vector<stk_classic::mesh::FieldBase *>::const_iterator I = fields.begin();
    while (I != fields.end()) {
      const stk_classic::mesh::FieldBase *f = *I; ++I;
      if (stk_classic::io::is_valid_part_field(f, part_type, part, universal, filter_role)) {
        stk_classic::io::field_data_to_ioss(f, entities, io_entity, f->name());
      }
    }
  }

  * \endcode
  * \section input_request Entity Processing Routine Details -- Input Request
  * \code
  void process_input_request(Ioss::Region &region,
                             stk_classic::mesh::BulkData &bulk,
                             int step)
  {
    region.begin_state(step);

    // Special processing for nodeblock (all nodes in model)...
    const stk_classic::mesh::MetaData & meta = MetaData::get(bulk);

    // Get field data from nodeblock...
    get_field_data(bulk, meta.universal_part(), stk_classic::mesh::Node,
                   region.get_node_blocks()[0], Ioss::Field::TRANSIENT);
    
    const stk_classic::mesh::PartVector & all_parts = meta.get_parts();
    for ( stk_classic::mesh::PartVector::const_iterator
            ip = all_parts.begin(); ip != all_parts.end(); ++ip ) {

      stk_classic::mesh::Part * const part = *ip;

      // Check whether this part should be output to results database.
      if (stk_classic::io::is_part_io_part(*part)) {
        // Get Ioss::GroupingEntity corresponding to this part...
        Ioss::GroupingEntity *entity = region.get_entity(part->name());
        if (entity != NULL) {
          if (entity->type() == Ioss::FACESET || entity->type() == Ioss::EDGESET) {
            int block_count = entity->block_count();
            for (int i=0; i < block_count; i++) {
              Ioss::EntityBlock *fb = entity->get_block(i);
              // Real application would have different filtering mechanism
              get_field_data(bulk, *part, part->primary_entity_type(),
	                     fb, Ioss::Field::TRANSIENT);
            }
          } else {
            get_field_data(bulk, *part, part->primary_entity_type(),
                           entity, Ioss::Field::TRANSIENT);
          }
        }
      }
    }

    region.end_state(step);
  }

  * \endcode
  * \section output_request Entity Processing Routine Details -- Output Request
  * \code
  void process_output_request(Ioss::Region &region,
                              stk_classic::mesh::BulkData &bulk,
                              int step)
  {
    region.begin_state(step);
    // Special processing for nodeblock (all nodes in model)...
    const stk_classic::mesh::MetaData & meta = MetaData::get(bulk);

    put_field_data(bulk, meta.universal_part(), stk_classic::mesh::Node,
                   region.get_node_blocks()[0], Ioss::Field::TRANSIENT);
    
    const stk_classic::mesh::PartVector & all_parts = meta.get_parts();
    for ( stk_classic::mesh::PartVector::const_iterator
            ip = all_parts.begin(); ip != all_parts.end(); ++ip ) {

      stk_classic::mesh::Part * const part = *ip;

      // Check whether this part should be output to results database.
      if (stk_classic::io::is_part_io_part(*part)) {

        // Get Ioss::GroupingEntity corresponding to this part...
        Ioss::GroupingEntity *entity = region.get_entity(part->name());
        if (entity != NULL) {

          if (entity->type() == Ioss::FACESET || entity->type() == Ioss::EDGESET) {
            int block_count = entity->block_count();

            for (int i=0; i < block_count; i++) {
              Ioss::EntityBlock *fb = entity->get_block(i);
              // Real application would have different filtering mechanism
              put_field_data(bulk, *part, part->primary_entity_type(),
                             fb, Ioss::Field::TRANSIENT);
            }
          } else {
            put_field_data(bulk, *part, part->primary_entity_type(),
                           entity, Ioss::Field::TRANSIENT);
          }
        }
      }
    }
    region.end_state(step);
  }
}
\endcode
 */
