4.5. API 3.0 Headers

Three example API 3.0 readers are found in the following directories within your EnSight install. The first contains an example of structured and unstructured data together, the second is structured data alone, and the third contains unstructured data. This third one is the most common form of reader and likely is the one you will use as a template for developing your own reader.

$CEI/ensight242/src/readers/test3

$CEI/ensight242/src/readers/test3s

$CEI/ensight242/src/readers/test3u

Look at these readers, compile them and use them as prototypes for your new reader. The following contains the most useful headers in API 3.0, as extracted from the test3 readers.

4.5.1. User Defined test3 Reader

User Defined test3 Reader
/*----------------------------------------------------------------------------------------------
This reader does a simple (hard-coded) model:

It has both Unstructured and Structured geometry and variables.

  

                                                          * 300
                                                       .     .
                                                     .         .
                                                   .             .
                                                 .       123       .
                                               .                     . 
                                        100  *-------------------------* 200
                   
                  * 5000                     *-------------------------*
               .  |  .                       | 5001                 .  | 6001
             .    |    .                     |                 .       |
           .      |      .                   |   150      .            |
         .   20   |   30   .                 |       .          175    |
       .          |          .               |  .                      |
     *------------*------------*             *-------------------------* 
     | 4000        6000        | 3000        | 4004                    | 3001
     |                         |             |                         |
     |                         |             |                         |
     |                         |             |                         |
     |                         |             |                         |
     |                         |             |                         |
     |            10           |             |           250           |
     |                         |             |                         |
     |                         |             |                         |
     |                         |             |                         |
     |                         |             |                         |
     *-------------------------*             *-------------------------*
     1000                      2000           1001                      2001

               Part 2                                   Part 3



 Part 0:  part_descriptions: "left"           Part 1:  part_description: "right"
          part_index: 0                                part_index: 1
          part_id: 2                                   part_id: 3
          number_of_geoms: 2                           number_of_geoms: 2
            geom_index[0] = 0                            geom_index[0] = 1
            geom_index[1] = 2                            geom_index[1] = 3


------------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------
              


                  * 5000
               .  |  .
             .    |    .
           .      |      .
         .   20   |   30   .
       .          |          .
     *------------*------------*
     | 4000        6000        | 3000
     |                         |
     |                         |
     |                         |
     |                         |
     |                         |
     |            10           |
     |                         |
     |                         |
     |                         |
     |                         |
     *-------------------------*
     1000                      2000
          

 Geom 0:  geom_type = Z_UNSTRUCTURED        (Composed of a set of nodes used by
          nodeset_index = 0                  a set of 1 quad element, and
          number_of_elemsets = 2             a set of 2 triangle elements)
            elemset_index[0] = 0
            elemset_index[1] = 1

 Nodeset 0:  number_of_nodes = 6           Elemset 0: number_of_elements = 1
             interleave_flag = FALSE;                 etype = Z_QUA04
             coords_changing_flag = FALSE             contents_index_mode = BY_INDEX_1
             transient_var_flag = FALSE               conn_changing_flag = FALSE
             num_node_variables = 2                   transient_var_flag = FALSE
                                                      num_elem_variables = 2
             coord_array_compx[0] = 0.0;
             coord_array_compx[1] = 2.0;              conn_array[0] = 1;
             coord_array_compx[2] = 2.0;              conn_array[1] = 2;   
             coord_array_compx[3] = 0.0;              conn_array[2] = 3;
             coord_array_compx[4] = 1.0;              conn_array[3] = 4;
             coord_array_compx[5] = 1.0;
                                                      elem_id_array[0] = 10;
             coord_array_compy[0] = 0.0;
             coord_array_compy[1] = 0.0;
             coord_array_compy[2] = 2.0;   Elemset 1: number_of_elements = 2
             coord_array_compy[3] = 2.0;              etype = Z_TRI03
             coord_array_compy[4] = 3.0;              contents_index_mode = BY_INDEX_1
             coord_array_compy[5] = 2.0;              conn_changing_flag = FALSE
                                                      transient_var_flag = FALSE
             coord_array_compz[0] = 0.0;              num_elem_variables = 2
             coord_array_compz[1] = 0.0;
             coord_array_compz[2] = 0.0;              conn_array[0] = 4;
             coord_array_compz[3] = 0.0;              conn_array[1] = 6;
             coord_array_compz[4] = 0.0;              conn_array[2] = 5;
             coord_array_compz[5] = 0.0;
                                                      conn_array[3] = 3;
             node_id_array[0] = 1000;                 conn_array[4] = 5;
             node_id_array[1] = 2000;                 conn_array[5] = 6;
             node_id_array[2] = 3000;
             node_id_array[3] = 4000;                 elem_id_array[0] = 20;
             node_id_array[4] = 5000;                 elem_id_array[1] = 30;
             node_id_array[5] = 6000;

 Geom 2:  geom_type = Z_UNSTRUCTURED        (Composed of a set of 5 bar elements
          nodeset_index = 0                  which use the same set of nodes as geom 0)
          number_of_elemsets = 1
            elemset_index[0] = 4

                                           Elemset 4: number_of_elements = 5
                                                      etype = Z_BAR02
                                                      contents_index_mode = BY_INDEX_0
                                                      conn_changing_flag = FALSE
                                                      transient_var_flag = FALSE
                                                      num_elem_variables = 2

                                                      conn_array[0] = 0;
                                                      conn_array[1] = 1;

                                                      conn_array[2] = 1;
                                                      conn_array[3] = 2;

                                                      conn_array[4] = 2;
                                                      conn_array[5] = 4;

                                                      conn_array[6] = 4;
                                                      conn_array[7] = 3;

                                                      conn_array[8] = 3;
                                                      conn_array[9] = 0;

                                                      elem_id_array[0] = 10;
                                                      elem_id_array[1] = 10;
                                                      elem_id_array[2] = 30;
                                                      elem_id_array[3] = 20;
                                                      elem_id_array[4] = 10;

-------------------------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------------------

                                                          * 300
                                                       .     .
                                                     .         .
                                                   .             .
                                                 .       123       .
                                               .                     . 
                                        100  *-------------------------* 200

                                             *-------------------------*
                                             | 5001                 .  | 6001
                                             |                 .       |
                                             |   150      .            |
                                             |       .          175    |
                                             |  .                      |
                                             *-------------------------* 
                                             | 4004                    | 3001
                                             |                         |
                                             |                         |
                                             |                         |
                                             |                         |
                                             |                         |
                                             |           250           |
                                             |                         |
                                             |                         |
                                             |                         |
                                             |                         |
                                             *-------------------------*
                                              1001                      2001


 Geom 1:  geom_type = Z_UNSTRUCTURED        (Composed of a another set of nodes used
          nodeset_index = 1                  by a set of 1 quad element,
          number_of_elemsets = 2             and a set of 2 tria3 elements)
            elemset_index[0] = 2
            elemset_index[1] = 3

 Nodeset 1:  number_of_nodes = 6               Elemset 2: number_of_elements = 1
             interleave_flag = TRUE                       etype = Z_QUA04
             coords_changing_flag = FALSE                 contents_index_mode = BY_ID
             transient_var_flag = FALSE                   conn_changing_flag = FALSE
             num_node_variables = 2                       transient_var_flag = FALSE
                                                          num_elem_variables = 2
             coord_array_compx[0] = 3.0;
             coord_array_compx[1] = 0.0;                  conn_array[0] = 1001;
             coord_array_compx[2] = 0.0;                  conn_array[1] = 2001;   
                                                          conn_array[2] = 3001;
             coord_array_compx[3] = 5.0;                  conn_array[3] = 4001;
             coord_array_compx[4] = 0.0;
             coord_array_compx[5] = 0.0                   elem_id_array[0] = 250;
             
             coord_array_compx[6] = 5.0;
             coord_array_compx[7] = 2.0;       Elemset 3: number_of_elements = 2
             coord_array_compx[8] = 0.0;                  etype = Z_TRI03
                                                          contents_index_mode = BY_ID
             coord_array_compx[9]  = 3.0;                 conn_changing_flag = FALSE
             coord_array_compx[10] = 2.0                  transient_var_flag = FALSE
             coord_array_compx[11] = 0.0;                 num_elem_variables = 2

             coord_array_compx[12] = 3.0;                  conn_array[0] = 4001;
             coord_array_compx[13] = 3.0;                  conn_array[1] = 6001;
             coord_array_compx[14] = 0.0;                  conn_array[2] = 5001;
          
             coord_array_compx[15] = 5.0;                  conn_array[3] = 3001;
             coord_array_compx[16] = 3.0;                  conn_array[4] = 6001;
             coord_array_compx[17] = 0.0;                  conn_array[5] = 4001;

             node_id_array[0] = 1001;                      elem_id_array[0] = 150;
             node_id_array[1] = 2001;                      elem_id_array[1] = 175;
             node_id_array[2] = 3001;
             node_id_array[3] = 4001;
             node_id_array[4] = 5001;
             node_id_array[5] = 6001;

 Geom 3:  geom_type = Z_UNSTRUCTURED        (Composed of another set of nodes used by
          nodeset_index = 2                  a single set of 1 tri element.)
          number_of_elemsets = 1
            elemset_index[0] = 5

 Nodeset 2:  number_of_nodes = 3 
             interleave_flag = TRUE           Elemset 5: number_of_elements = 1
             coords_changing_flag = FALSE                etype = Z_TRI03
             transient_var_flag = FALSE                  contents_index_mode = BY_ID
             num_node_variables = 2                      conn_changing_flag = FALSE
                                                         transient_var_flag = FALSE
             coord_array_compx[0] = 3.0;                 num_elem_variables = 2
             coord_array_compx[1] = 3.25;
             coord_array_compx[2] = 0.0;                 conn_array[0] = 100;
                                                         conn_array[1] = 200;
             coord_array_compx[3] = 5.0;                 conn_array[2] = 300;
             coord_array_compx[4] = 3.25;
             coord_array_compx[5] = 0.0;                 elem_id_array[0] = 123;
             coord_array_compx[6] = 4.0;
             coord_array_compx[7] = 4.25;
             coord_array_compx[8] = 0.0;

             node_id_array[0] = 100;
             node_id_array[1] = 200;
             node_id_array[2] = 300;


 Note that:
  => all three contents_index_modes were used above.
  => Muti-geom was used once with the same node set (pretty easy)
     But, also was used once with different node sets (had to combine and modify 
     conns)
-----------------------------------------------------------------------*/

/*----------------------------------------------------------------------
Now some parts using the same "Node", so we can test the efficiency of loading vbuf only
when needed.


        *------------*------------* 
        |            |            | 
        |            |            |
        |           TLR           |
        |            |            |
        |            |            |
        *------------*------------*
        |            |            |
        |            |            |
        |    BL      |     BR     |
        |            |            |
        |            |            |
        *------------*------------*


 Part 2:  part_descriptions: "BL"           Part 3:  part_description: "BR"
          part_index: 2                                part_index: 3
          part_id: 10                                  part_id: 11
          number_of_geoms: 1                           number_of_geoms: 1
            geom_index[0] = 4                            geom_index[0] = 5

 Part 4:  part_descriptions: "TLR"
          part_index: 4            
          part_id: 12               
          number_of_geoms: 2       
            geom_index[0] = 6      
            geom_index[1] = 7      

 Geom 4:  geom_type = Z_UNSTRUCTURED
          nodeset_index = 3
          number_of_elemsets = 1
            elemset_index[0] = 6

 Geom 5:  geom_type = Z_UNSTRUCTURED
          nodeset_index = 3
          number_of_elemsets = 1
            elemset_index[0] = 7

 Geom 6:  geom_type = Z_UNSTRUCTURED
          nodeset_index = 3
          number_of_elemsets = 1
            elemset_index[0] = 8

 Geom 7:  geom_type = Z_UNSTRUCTURED
          nodeset_index = 3
          number_of_elemsets = 1
            elemset_index[0] = 9

 Nodeset 3:  number_of_nodes = 9
             interleave_flag = TRUE
             coords_changing_flag = FALSE
             transient_var_flag = FALSE
             num_node_variables = 2

             coord_array_compx[0] = 0.0;
             coord_array_compx[1] = 4.0;
             coord_array_compx[2] = 0.0;

             coord_array_compx[3] = 1.0;
             coord_array_compx[4] = 4.0;
             coord_array_compx[5] = 0.0; 
          
             coord_array_compx[6] = 2.0;
             coord_array_compx[7] = 4.0;
             coord_array_compx[8] = 0.0;

             coord_array_compx[9]  = 0.0;
             coord_array_compx[10] = 5.0;
             coord_array_compx[11] = 0.0;

             coord_array_compx[12] = 1.0;
             coord_array_compx[13] = 5.0;
             coord_array_compx[14] = 0.0;
          
             coord_array_compx[15] = 2.0;
             coord_array_compx[16] = 5.0;
             coord_array_compx[17] = 0.0;

             coord_array_compx[18] = 0.0;
             coord_array_compx[19] = 6.0;
             coord_array_compx[20] = 0.0;

             coord_array_compx[21] = 1.0;
             coord_array_compx[22] = 6.0;
             coord_array_compx[23] = 0.0;

             coord_array_compx[24] = 2.0;
             coord_array_compx[25] = 6.0;
             coord_array_compx[26] = 0.0;

             node_id_array[0] = 33;
             node_id_array[1] = 34;
             node_id_array[2] = 35;
             node_id_array[3] = 36;
             node_id_array[4] = 37;
             node_id_array[5] = 38;
             node_id_array[6] = 39;
             node_id_array[7] = 40;
             node_id_array[8] = 41;


   Elemset 6: number_of_elements = 1
              etype = Z_QUA04
              contents_index_mode = BY_INDEX_0
              conn_changing_flag = FALSE
              transient_var_flag = FALSE
              num_elem_variables = 2

              conn_array[0] = 0;
              conn_array[1] = 1;
              conn_array[2] = 4;
              conn_array[3] = 3;

              elem_id_array[0] = 330;

   Elemset 7: number_of_elements = 1
              etype = Z_QUA04
              contents_index_mode = BY_INDEX_0
              conn_changing_flag = FALSE
              transient_var_flag = FALSE
              num_elem_variables = 2

              conn_array[0] = 1;
              conn_array[1] = 2;
              conn_array[2] = 5;
              conn_array[3] = 4;

              elem_id_array[0] = 331;

   Elemset 8: number_of_elements = 1
              etype = Z_QUA04
              contents_index_mode = BY_INDEX_0
              conn_changing_flag = FALSE
              transient_var_flag = FALSE
              num_elem_variables = 2

              conn_array[0] = 3;
              conn_array[1] = 4;
              conn_array[2] = 7;
              conn_array[3] = 6;

              elem_id_array[0] = 332;

   Elemset 9: number_of_elements = 1
              etype = Z_QUA04
              contents_index_mode = BY_INDEX_0
              conn_changing_flag = FALSE
              transient_var_flag = FALSE
              num_elem_variables = 2

              conn_array[0] = 4;
              conn_array[1] = 5;
              conn_array[2] = 8;
              conn_array[3] = 7;

              elem_id_array[0] = 333;
-----------------------------------------------------------------------*/

/*----------------------------------------------------------------------
  Now a part using the same "Node" set, but with nsided and nfaced elements

                       * 5
                    . / \                        nfaced is the whole "house"
                 .   /   \                       
          10  *     /     \                      nsided elements used are the
             / \   /       \                     front and bottom
            /   \ /         \
           /     \3          * 4
          /       \       .  |
         /         \  .      |
        * 8         * 9      |
        |           |        |
        |  front    |        * 2
        |           |     .
        |           | .    \
        *-----------*       - - bottom
        6            7

 Part 5:  part_descriptions: "House"
          part_index: 5
          part_id: 15
          number_of_geoms: 2
          geom_index[0] = 8
          geom_index[1] = 9

 Geom 8:  geom_type = Z_UNSTRUCTURED
          nodeset_index = 4
          number_of_elemsets = 2
          elemset_index[0] = 10
          elemset_index[1] = 11

 Geom 9:  geom_type = Z_UNSTRUCTURED
          nodeset_index = 5
          number_of_elemsets = 2
          elemset_index[0] = 12
          elemset_index[1] = 13

 Nodeset 4:  number_of_nodes = 10
             interleave_flag = FALSE
             coords_changing_flag = FALSE
             transient_var_flag = FALSE
             num_node_variables = 2

             coord_array_compx[0] = 10.0;
             coord_array_compx[1] = 12.0;
             coord_array_compx[2] = 10.0;
             coord_array_compx[3] = 12.0;
             coord_array_compx[4] = 11.0;
             coord_array_compx[5] = 10.0; 
             coord_array_compx[6] = 12.0;
             coord_array_compx[7] = 10.0;
             coord_array_compx[8] = 12.0;
             coord_array_compx[9] = 11.0;

             coord_array_compy[0] = 0.0;
             coord_array_compy[1] = 0.0;
             coord_array_compy[2] = 2.0;
             coord_array_compy[3] = 2.0;
             coord_array_compy[4] = 3.0;
             coord_array_compy[5] = 0.0; 
             coord_array_compy[6] = 0.0;
             coord_array_compy[7] = 2.0;
             coord_array_compy[8] = 2.0;
             coord_array_compy[9] = 3.0;

             coord_array_compz[0] = 0.0;
             coord_array_compz[1] = 0.0;
             coord_array_compz[2] = 0.0;
             coord_array_compz[3] = 0.0;
             coord_array_compz[4] = 0.0;
             coord_array_compz[5] = 2.0; 
             coord_array_compz[6] = 2.0;
             coord_array_compz[7] = 2.0;
             coord_array_compz[8] = 2.0;
             coord_array_compz[9] = 2.0;

             node_id_array[0] = 301;
             node_id_array[1] = 302;
             node_id_array[2] = 303;
             node_id_array[3] = 304;
             node_id_array[4] = 305;
             node_id_array[5] = 306;
             node_id_array[6] = 307;
             node_id_array[7] = 308;
             node_id_array[8] = 309;
             node_id_array[9] = 310;


 Nodeset 5:  number_of_nodes = 10
             interleave_flag = FALSE
             coords_changing_flag = FALSE
             transient_var_flag = FALSE
             num_node_variables = 2

             coord_array_compx[0] = 10.0;
             coord_array_compx[1] = 12.0;
             coord_array_compx[2] = 10.0;
             coord_array_compx[3] = 12.0;
             coord_array_compx[4] = 11.0;
             coord_array_compx[5] = 10.0; 
             coord_array_compx[6] = 12.0;
             coord_array_compx[7] = 10.0;
             coord_array_compx[8] = 12.0;
             coord_array_compx[9] = 11.0;

             coord_array_compy[0] = 0.0;
             coord_array_compy[1] = 0.0;
             coord_array_compy[2] = 2.0;
             coord_array_compy[3] = 2.0;
             coord_array_compy[4] = 3.0;
             coord_array_compy[5] = 0.0; 
             coord_array_compy[6] = 0.0;
             coord_array_compy[7] = 2.0;
             coord_array_compy[8] = 2.0;
             coord_array_compy[9] = 3.0;

             coord_array_compz[0] = 2.5;
             coord_array_compz[1] = 2.5;
             coord_array_compz[2] = 2.5;
             coord_array_compz[3] = 2.5;
             coord_array_compz[4] = 2.5;
             coord_array_compz[5] = 4.5; 
             coord_array_compz[6] = 4.5;
             coord_array_compz[7] = 4.5;
             coord_array_compz[8] = 4.5;
             coord_array_compz[9] = 4.5;

             node_id_array[0] = 401;
             node_id_array[1] = 402;
             node_id_array[2] = 403;
             node_id_array[3] = 404;
             node_id_array[4] = 405;
             node_id_array[5] = 406;
             node_id_array[6] = 407;
             node_id_array[7] = 408;
             node_id_array[8] = 409;
             node_id_array[9] = 410;


  Elemset 10: number_of_elements = 2
              etype = Z_NSIDED
              contents_index_mode = BY_INDEX_0
              conn_changing_flag = FALSE
              transient_var_flag = FALSE
              num_elem_variables = 2

              fpe[0] = 1;

              npf[0] = 5;
              npf[1] = 4;

              conn_array[0] = 5;
              conn_array[1] = 6;
              conn_array[2] = 8;
              conn_array[3] = 9;
              conn_array[4] = 7;

              conn_array[5] = 0;
              conn_array[6] = 1;
              conn_array[7] = 6;
              conn_array[8] = 5;

              elem_id_array[0] = 338;
              elem_id_array[1] = 339;


  Elemset 11: number_of_elements = 1
              etype = Z_NFACED
              contents_index_mode = BY_INDEX_1
              conn_changing_flag = FALSE
              transient_var_flag = FALSE
              num_elem_variables = 2

              fpe[0] = 7;

              npf[0] = 5;
              npf[1] = 5;
              npf[2] = 4;
              npf[3] = 4;
              npf[4] = 4;
              npf[5] = 4;
              npf[6] = 4;

              back
              conn_array[0] = 1;
              conn_array[1] = 3;
              conn_array[2] = 5;
              conn_array[3] = 4;
              conn_array[4] = 2;

              front
              conn_array[0] = 7;
              conn_array[1] = 9;
              conn_array[2] = 10;
              conn_array[3] = 8;
              conn_array[4] = 6;

              bottom
              conn_array[0] = 1;
              conn_array[1] = 2;
              conn_array[2] = 7;
              conn_array[3] = 6;

              left
              conn_array[0] = 1;
              conn_array[1] = 6;
              conn_array[2] = 8;
              conn_array[3] = 3;

              right
              conn_array[0] = 2;
              conn_array[1] = 4;
              conn_array[2] = 9;
              conn_array[3] = 7;

              top left
              conn_array[0] = 3;
              conn_array[1] = 8;
              conn_array[2] = 10;
              conn_array[3] = 5;

              top right
              conn_array[0] = 4;
              conn_array[1] = 5;
              conn_array[2] = 10;
              conn_array[3] = 9;

              elem_id_array[0] = 183;

  Elemset 12: number_of_elements = 2
              etype = Z_NSIDED
              contents_index_mode = BY_INDEX_0
              conn_changing_flag = FALSE
              transient_var_flag = FALSE
              num_elem_variables = 2

              fpe[0] = 1;

              npf[0] = 5;
              npf[1] = 4;

              conn_array[0] = 5;
              conn_array[1] = 6;
              conn_array[2] = 8;
              conn_array[3] = 9;
              conn_array[4] = 7;

              conn_array[5] = 0;
              conn_array[6] = 1;
              conn_array[7] = 6;
              conn_array[8] = 5;

              elem_id_array[0] = 340;
              elem_id_array[1] = 341;


  Elemset 13: number_of_elements = 1
              etype = Z_NFACED
              contents_index_mode = BY_INDEX_1
              conn_changing_flag = FALSE
              transient_var_flag = FALSE
              num_elem_variables = 2

              fpe[0] = 7;

              npf[0] = 5;
              npf[1] = 5;
              npf[2] = 4;
              npf[3] = 4;
              npf[4] = 4;
              npf[5] = 4;
              npf[6] = 4;

              back
              conn_array[0] = 1;
              conn_array[1] = 3;
              conn_array[2] = 5;
              conn_array[3] = 4;
              conn_array[4] = 2;

              front
              conn_array[0] = 7;
              conn_array[1] = 9;
              conn_array[2] = 10;
              conn_array[3] = 8;
              conn_array[4] = 6;

              bottom
              conn_array[0] = 1;
              conn_array[1] = 2;
              conn_array[2] = 7;
              conn_array[3] = 6;

              left
              conn_array[0] = 1;
              conn_array[1] = 6;
              conn_array[2] = 8;
              conn_array[3] = 3;

              right
              conn_array[0] = 2;
              conn_array[1] = 4;
              conn_array[2] = 9;
              conn_array[3] = 7;

              top left
              conn_array[0] = 3;
              conn_array[1] = 8;
              conn_array[2] = 10;
              conn_array[3] = 5;

              top right
              conn_array[0] = 4;
              conn_array[1] = 5;
              conn_array[2] = 10;
              conn_array[3] = 9;

              elem_id_array[0] = 184;
-------------------------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------------------
  curvilinear structured block
    - no iblanking
    - assigning node and element ids
    - no ghosts

           j
           |
           |
           *------------*------------*
          /            /            /|
         *------------*------------* |
        /            /            /| |
       *------------*------------* | |
      /            /            /| | |
     *------------*------------* | | * ----- i
     |            |            | | |/
     |            |            | | *
     |            |            | |/
     |            |            | *
     |            |            |/
     *------------*------------*
    /
   /
  k


 Part 6:  part_descriptions: "block 1"
          part_index: 6
          part_id: 7
          number_of_geoms: 1
           geom_index[0] = 10

  Geom 14: geom_type = Z_STRUCTURED
           nodeset_index = 6
           number_of_elemsets = 1
             elemset_index[0] = 14

  Nodeset 6: ijk_dimension[0] = 3
             ijk_dimension[1] = 2
             ijk_dimension[2] = 4
             ijk_dimension[3] = 1
             ijk_dimension[4] = 3
             ijk_dimension[5] = 1
             ijk_dimension[6] = 2
             ijk_dimension[7] = 1
             ijk_dimension[8] = 4

             stype = Z_CURVILINEAR
             iblanking_options[Z_EXT]    = FALSE
             iblanking_options[Z_INT]    = FALSE
             iblanking_options[Z_BND]    = FALSE
             iblanking_options[Z_INTBND] = FALSE
             iblanking_options[Z_SYM]    = FALSE

             interleave_flag = FALSE
             coords_changing_flag = FALSE
             transient_var_flag = FALSE
             num_node_variables = 2

             coord_array_compx[0]  = 0.0;
             coord_array_compx[1]  = 1.0;
             coord_array_compx[2]  = 2.0;
             coord_array_compx[3]  = 0.0;
             coord_array_compx[4]  = 1.0;
             coord_array_compx[5]  = 2.0;
             coord_array_compx[6]  = 0.0;
             coord_array_compx[7]  = 1.0;
             coord_array_compx[8]  = 2.0;
             coord_array_compx[9]  = 0.0;
             coord_array_compx[10] = 1.0;
             coord_array_compx[11] = 2.0;
             coord_array_compx[12] = 0.0;
             coord_array_compx[13] = 1.0;
             coord_array_compx[14] = 2.0;
             coord_array_compx[15] = 0.0;
             coord_array_compx[16] = 1.0;
             coord_array_compx[17] = 2.0;
             coord_array_compx[18] = 0.0;
             coord_array_compx[19] = 1.0;
             coord_array_compx[20] = 2.0;
             coord_array_compx[21] = 0.0;
             coord_array_compx[22] = 1.0;
             coord_array_compx[23] = 2.0;

             coord_array_compy[0]  = 0.0;
             coord_array_compy[1]  = 0.0;
             coord_array_compy[2]  = 0.0;
             coord_array_compy[3]  = 1.0;
             coord_array_compy[4]  = 1.0;
             coord_array_compy[5]  = 1.0;
             coord_array_compy[6]  = 0.0;
             coord_array_compy[7]  = 0.0;
             coord_array_compy[8]  = 0.0;
             coord_array_compy[9]  = 1.0;
             coord_array_compy[10] = 1.0;
             coord_array_compy[11] = 1.0;
             coord_array_compy[12] = 0.0;
             coord_array_compy[13] = 0.0;
             coord_array_compy[14] = 0.0;
             coord_array_compy[15] = 1.0;
             coord_array_compy[16] = 1.0;
             coord_array_compy[17] = 1.0;
             coord_array_compy[18] = 0.0;
             coord_array_compy[19] = 0.0;
             coord_array_compy[20] = 0.0;
             coord_array_compy[21] = 1.0;
             coord_array_compy[22] = 1.0;
             coord_array_compy[23] = 1.0;

             coord_array_compz[0]  = 0.0;
             coord_array_compz[1]  = 0.0;
             coord_array_compz[2]  = 0.0;
             coord_array_compz[3]  = 0.0;
             coord_array_compz[4]  = 0.0;
             coord_array_compz[5]  = 0.0;
             coord_array_compz[6]  = 1.0;
             coord_array_compz[7]  = 1.0;
             coord_array_compz[8]  = 1.0;
             coord_array_compz[9]  = 1.0;
             coord_array_compz[10] = 1.0;
             coord_array_compz[11] = 1.0;
             coord_array_compz[12] = 2.0;
             coord_array_compz[13] = 2.0;
             coord_array_compz[14] = 2.0;
             coord_array_compz[15] = 2.0;
             coord_array_compz[16] = 2.0;
             coord_array_compz[17] = 2.0;
             coord_array_compz[18] = 3.0;
             coord_array_compz[19] = 3.0;
             coord_array_compz[20] = 3.0;
             coord_array_compz[21] = 3.0;
             coord_array_compz[22] = 3.0;
             coord_array_compz[23] = 3.0;

             node_id_array[0]  = 1;
             node_id_array[1]  = 2;
             node_id_array[2]  = 3;
             node_id_array[3]  = 4;
             node_id_array[4]  = 5;
             node_id_array[5]  = 6;
             node_id_array[6]  = 7;
             node_id_array[7]  = 8;
             node_id_array[8]  = 9;
             node_id_array[9]  = 10;
             node_id_array[10] = 11;
             node_id_array[11] = 12;
             node_id_array[12] = 13;
             node_id_array[13] = 14;
             node_id_array[14] = 15;
             node_id_array[15] = 16;
             node_id_array[16] = 17;
             node_id_array[17] = 18;
             node_id_array[18] = 19;
             node_id_array[19] = 20;
             node_id_array[20] = 21;
             node_id_array[21] = 22;
             node_id_array[22] = 23;
             node_id_array[23] = 24;

Elemset 14:  ijk_dimension[0] = 3
             ijk_dimension[1] = 2
             ijk_dimension[2] = 4
             ijk_dimension[3] = 1
             ijk_dimension[4] = 3
             ijk_dimension[5] = 1
             ijk_dimension[6] = 2
             ijk_dimension[7] = 1
             ijk_dimension[8] = 4

             stype = Z_CURVILINEAR
             conn_changing_flag = FALSE
             ghost_flag = FALSE;
             transient_var_flag = FALSE
             num_elem_variables = 2

             elem_id_array[0]  = 10;
             elem_id_array[1]  = 20;
             elem_id_array[2]  = 30;
             elem_id_array[3]  = 40;
             elem_id_array[4]  = 50;
             elem_id_array[5]  = 60;


--------------------------------------------------------------------------------
Uniform structured block part
  - no iblanking
  - assigning node and element ids
  - has ghosts


                                                   j
                                                   |
                                                   |
                                                   *------------*------------*
                                                  /            /            /|
                                                 *------------*------------* |
                                                /            /            /| |
                                               *------------*------------* | |
                                              /            /            /| | |
                                             *------------*------------* | | * ----- i
                                             |            |            | | |/
                                             |            |            | | *
                                             |            |            | |/
                                             |            |            | *
                                             |     ^      |     ^      |/
                                             *-----|------*-----|------*
                                            /      |            |
                                           /       |____________|____________ 2 ghost cells
                                          k



 Part 7:  part_descriptions: "block 2"
          part_index: 7
          part_id: 8
          number_of_geoms: 1
           geom_index[0] = 11

  Geom 11: geom_type = Z_STRUCTURED
           nodeset_index = 7
           number_of_elemsets = 1
            elemset_index[0] = 15

  Nodeset 7: ijk_dimension[0] = 3
             ijk_dimension[1] = 2
             ijk_dimension[2] = 4
             ijk_dimension[3] = 1
             ijk_dimension[4] = 3
             ijk_dimension[5] = 1
             ijk_dimension[6] = 2
             ijk_dimension[7] = 1
             ijk_dimension[8] = 4

             stype = Z_UNIFORM
             iblanking_options[Z_EXT]    = FALSE
             iblanking_options[Z_INT]    = FALSE
             iblanking_options[Z_BND]    = FALSE
             iblanking_options[Z_INTBND] = FALSE
             iblanking_options[Z_SYM]    = FALSE

             interleave_flag = FALSE
             coords_changing_flag = FALSE
             transient_var_flag = FALSE
             num_node_variables = 2

             coord_array_compx[0]  = 3.0;
             coord_array_compx[1]  = 3.0;
             coord_array_compx[2]  = 3.0;
             coord_array_compx[3]  = 1.0;
             coord_array_compx[4]  = 1.0;
             coord_array_compx[5]  = 1.0;

             node_id_array[0]  = 1;
             node_id_array[1]  = 2;
             node_id_array[2]  = 3;
             node_id_array[3]  = 4;
             node_id_array[4]  = 5;
             node_id_array[5]  = 6;
             node_id_array[6]  = 7;
             node_id_array[7]  = 8;
             node_id_array[8]  = 9;
             node_id_array[9]  = 10;
             node_id_array[10] = 11;
             node_id_array[11] = 12;
             node_id_array[12] = 13;
             node_id_array[13] = 14;
             node_id_array[14] = 15;
             node_id_array[15] = 16;
             node_id_array[16] = 17;
             node_id_array[17] = 18;
             node_id_array[18] = 19;
             node_id_array[19] = 20;
             node_id_array[20] = 21;
             node_id_array[21] = 22;
             node_id_array[22] = 23;
             node_id_array[23] = 24;

Elemset 15:  ijk_dimension[0] = 3
             ijk_dimension[1] = 2
             ijk_dimension[2] = 4
             ijk_dimension[3] = 1
             ijk_dimension[4] = 3
             ijk_dimension[5] = 1
             ijk_dimension[6] = 2
             ijk_dimension[7] = 1
             ijk_dimension[8] = 4

             stype = Z_UNIFORM
             conn_changing_flag = FALSE
             ghost_flag = TRUE;
             transient_var_flag = FALSE
             num_elem_variables = 2

             elem_id_array[0]  = 10;
             elem_id_array[1]  = 20;
             elem_id_array[2]  = 30;
             elem_id_array[3]  = 40;
             elem_id_array[4]  = 50;
             elem_id_array[5]  = 60;

             ghost_flag_array[0] = 0;
             ghost_flag_array[1] = 0;
             ghost_flag_array[2] = 0;
             ghost_flag_array[3] = 0;
             ghost_flag_array[4] = 1;
             ghost_flag_array[5] = 1;
             
-----------------------------------------------------------------------------------
rectilinear structured block
- with iblanking                        all nodes on the indicated j-k planes are:
  - with node and element ids
  - no ghosts                            Z_INT        Z_INT        Z_SYM
                                     j  /            /            /
                                     | /            /            /
                                     |
                                     *------------*------------*
                                    /            /            /|
                                   *------------*------------* |
                                  /            /            /| |
                                 *------------*------------* | |
                                /            /            /| | |
                               *------------*------------* | | * ----- i
                               |            |            | | |/
                               |            |            | | *
                               |            |            | |/<- So this surface is
                               |            |            | *    a symmetry plane
                               |            |            |/
                               *------------*------------*
                              /
                             /
                            k


  Part 8:  part_descriptions: "block 3"
           part_index: 8
           part_id: 9
           number_of_geoms: 1
            geom_index[0] = 12

  Geom 12: geom_type = Z_IBLANKED
           nodeset_index = 8
           number_of_elemsets = 1
            elemset_index[0] = 16

  Nodeset 8: ijk_dimension[0] = 3
             ijk_dimension[1] = 2
             ijk_dimension[2] = 4
             ijk_dimension[3] = 1
             ijk_dimension[4] = 3
             ijk_dimension[5] = 1
             ijk_dimension[6] = 2
             ijk_dimension[7] = 1
             ijk_dimension[8] = 4

             stype = Z_RECTILINEAR
             iblanking_options[Z_EXT]    = FALSE
             iblanking_options[Z_INT]    = TRUE
             iblanking_options[Z_BND]    = FALSE
             iblanking_options[Z_INTBND] = FALSE
             iblanking_options[Z_SYM]    = TRUE

             interleave_flag = FALSE
             coords_changing_flag = FALSE
             transient_var_flag = FALSE
             num_node_variables = 2

             coord_array_compx[0]  = 1.5;
             coord_array_compx[1]  = 2.5;
             coord_array_compx[2]  = 3.5;

             coord_array_compy[0]  = -2.0;
             coord_array_compy[1]  = -1.0;

             coord_array_compz[0]  = 0.0;
             coord_array_compz[1]  = 1.0;
             coord_array_compz[2]  = 2.0;
             coord_array_compz[3]  = 3.0;

             node_id_array[0]  = 1;
             node_id_array[1]  = 2;
             node_id_array[2]  = 3;
             node_id_array[3]  = 4;
             node_id_array[4]  = 5;
             node_id_array[5]  = 6;
             node_id_array[6]  = 7;
             node_id_array[7]  = 8;
             node_id_array[8]  = 9;
             node_id_array[9]  = 10;
             node_id_array[10] = 11;
             node_id_array[11] = 12;
             node_id_array[12] = 13;
             node_id_array[13] = 14;
             node_id_array[14] = 15;
             node_id_array[15] = 16;
             node_id_array[16] = 17;
             node_id_array[17] = 18;
             node_id_array[18] = 19;
             node_id_array[19] = 20;
             node_id_array[20] = 21;
             node_id_array[21] = 22;
             node_id_array[22] = 23;
             node_id_array[23] = 24;

             iblanking_array[0]  = Z_INT
             iblanking_array[1]  = Z_INT
             iblanking_array[2]  = Z_SYM
             iblanking_array[3]  = Z_INT
             iblanking_array[4]  = Z_INT
             iblanking_array[5]  = Z_SYM
             iblanking_array[6]  = Z_INT
             iblanking_array[7]  = Z_INT
             iblanking_array[8]  = Z_SYM
             iblanking_array[9]  = Z_INT
             iblanking_array[10] = Z_INT
             iblanking_array[11] = Z_SYM
             iblanking_array[12] = Z_INT
             iblanking_array[13] = Z_INT
             iblanking_array[14] = Z_SYM
             iblanking_array[15] = Z_INT
             iblanking_array[16] = Z_INT
             iblanking_array[17] = Z_SYM
             iblanking_array[18] = Z_INT
             iblanking_array[19] = Z_INT
             iblanking_array[20] = Z_SYM
             iblanking_array[21] = Z_INT
             iblanking_array[22] = Z_INT
             iblanking_array[23] = Z_SYM

 Elemset 16: ijk_dimension[0] = 3
             ijk_dimension[1] = 2
             ijk_dimension[2] = 4
             ijk_dimension[3] = 1
             ijk_dimension[4] = 3
             ijk_dimension[5] = 1
             ijk_dimension[6] = 2
             ijk_dimension[7] = 1
             ijk_dimension[8] = 4

             stype = Z_RECTILINEAR
             conn_changing_flag = FALSE
             ghost_flag = FALSE;
             transient_var_flag = FALSE
             num_elem_variables = 2

             elem_id_array[0]  = 10;
             elem_id_array[1]  = 20;
             elem_id_array[2]  = 30;
             elem_id_array[3]  = 40;
             elem_id_array[4]  = 50;
             elem_id_array[5]  = 60;

*------------------------------------------------------------------------------------------*/

/*------------------------------------------------------------------------------------------
 *  ======================
 *  Dealing with geometry
 *  ======================
 *
 *  Parts
 *  =====
 *  1. Set number of model parts in:
 *       USERD_get_number_of_model_parts
 *
 *  2. Set the part id, part description, number of geoms for each part in:
 *     (as well as the flag for border geom and the border geom index - if 
 *     the part has such)
 *       USERD_get_part_info
 *
 *  3. Set the list of geoms in each part in:
 *       USERD_get_geoms_in_part
 *
 *  Geoms
 *  =====
 *  1. Set the geom type, the nodeset index, and the number of elemsets 
 *     for each geom in:
 *       USERD_get_geom_info
 *
 *  2. Set the list of elemsets in each geom in:
 *     (Structured will only have one elemset)
 *       USERD_get_elemsets_in_geom
 *
 *  Nodesets
 *  ========
 *  Unstructured:
 *  1. Set the number of nodes, the interleave flag, the coords changing flag, and 
 *     the number of nodal variables for each nodeset in:
 *       USERD_get_unode_info
 *
 *  Structured:
 *  1. Set the structured type, the ijk dimensions, the interleave flag, the 
 *     coords changing flag the iblanking options, the transient variable 
 *     flag, and the number of nodal variables for each nodeset in:
 *       USERD_get_snode_info
 *
 *  2. Set the nodal iblanking values in the iblanking_array in:
 *       USERD_get_snode_iblanking
 *
 *  Both Unstructured and Structured:
 *  1. Set the coordinates for the nodes in the nodeset in:
 *       USERD_get_node_coords
 *
 *  2. Set the ids for the nodes in the nodeset in:
 *     (only called if USERD_get_node_label_status indicates that the ids will 
 *     be provided)
 *       USERD_get_node_ids 
 *
 *  Elemsets
 *  ========
 *  Unstructured:
 *  1. Set the number of elements, the element type, the contents index mode,
 *     the conn changing flag, and the number of elem variables for each 
 *     elemset in:
 *       USERD_get_uelem_info
 *
 *  2. For element connectivities, set things in the following routines: 
 *       USERD_get_uelem_faces_per_elem
 *       USERD_get_uelem_nodes_per_face
 *       USERD_get_uelem_conn
 *
 * according to the following table:
 *     
 * etype      USERD_get_uelem_faces_per_elem    USERD_get_uelem_nodes_per_face
 * ------     ------------------------------    ------------------------------
 * regular    Need not call. If you do, this    Need not call if caller knows the
 *            routine should return fpe[0]=1    conlength. If you call, should 
 *                                              return npf[0] = conlength
 *
 * nsided     Need not call. If you do, this    Need to call. This routine needs 
 *            routine should return fpe[0]=1    to return the npf array 
 *                                              (#nodes/elem). This is needed 
 *                                              to be able to figure the total 
 *                                              length of conn_array.
 *
 * nfaced     Need to call. This routine        Need to call.  This routine needs 
 *            should return the fpe array       to return the npf array (#nodes/face).
 *            (#faces/elem). This is needed     This is needed to be able to
 *            to be able to figure the total    figure the total length of
 *            number of faces (length of the    the conn_array.
 *            npf array.
 *
 * all        Need to call the USERD_get_uelem_conn routine which will return the 
 *            connectivity array for each element in the elemset.
 *
 *  Structured:
 *  1. Set the structured type, the ijk dimensions, the conn changing flag, the 
 *      ghost flag, the transient variable flag, and the number of elem variables 
 *      for the one elemset in: USERD_get_selem_info
 *
 *  2. Set the ghost flags for each element in the elemset in:
 *       USERD_get_selem_ghost_flags
 *
 *  Both Unstructured and Structured:
 *  1. Set the ids for the elements of the elemset in:
 *     (only called if USERD_get_element_label_status indicates that the ids 
 *     will be provided)
 *       USERD_get_elem_ids
*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------
 *  ======================
 *  Dealing with variables
 *  ======================
 *
 *  Constants:
 *  ==========
 *  1. Need to set the total number of constant variables in the model in:
 *       USERD_get_number_of_model_constants
 *
 *  2. Return the attributes of model constant variables in:
 *       USERD_get_model_constant_info
 *
 *  3. Return the value of model constant variables in:
 *       USERD_get_model_constant_val
 *
 *
 *  Non-Constants:
 *  =============
 *  1. Need to set the total number of non-constant variables in the model in:
 *       USERD_get_number_of_vars
 *     This will be var_index = 0, 1, ... (number of non-constant vars - 1)
 *
 *  2. Return the attributes of a given variable in:
 *       USERD_get_var_info
 *     Reference will be the var_index.
 *     (One important attribute is the interleave_flag - because it will control 
 *      whether values will be obtained by component or all at once.)
 *
 *  Nodal:
 *  ------
 *  3. Set the number of nodal variables in a given nodeset in:
 *
 *     Unstructured:
 *       USERD_get_unode_info
 *
 *     Structured:
 *       USERD_get_snode_info
 *       
 *  4. Return the var_index (and the number of values) for each nodal variable 
 *     in this
 *     nodeset_index in:
 *       USERD_get_node_var_info
 *
 *  5. Return the values for each var_index nodal variable in:
 *       USERD_get_node_var_values
 *     This will be be by component, unless it is an interleaved variable.
 *
 *
 *  Elemental:
 *  ----------
 *  6. Set the number of elemental variables in a given elemset in:
 *
 *     Unstructured:
 *       USERD_get_uelem_info
 *
 *     Structured:
 *       USERD_get_selem_info
 *     
 *  7. Return the var_index (and the number of values) for each elemental 
 *     variable in this elemset_index in:
 *       USERD_get_elem_var_info
 *
 *  8. Return the values for each var_index elemental variable in:
 *       USERD_get_elem_var_values
 *     This will be be by component, unless it is an interleaved variable.
 *-------------------------------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>


#include "global_extern.h"          /* Any files containing these routines */
                                    /* should include this header file     */

/*==========================================================================
 * Required Structure Typedef
 * --------------------------
 * 1. Name can be whatever, but must be returned in USERD_reader_open
 * 2. The first item in the structure must be the ReaderHandle_30 structure.
 * 3. You can then add whatever reader specific items you desire.
 *===========================================================================*/
typedef struct {

  /* Required 1st item
   *------------------*/
  ReaderHandle_30 server;

  /* Reader specific info
   *---------------------*/
  char *filename;
  char *path;
} EnSightRdrHandle;



/* Local reader specific
 *----------------------*/
static int Current_time_step   = 0;
static int Current_timeset     = 1;
static int Num_Geoms_in_Part[13];
static int Geoms_in_Part[13][2];





4.5.2. Reader API 3 Routines

The following topics are included in this section:

4.5.2.1. USERD_reader_open

/*----------------------------------------------------
* USERD_reader_open - creates the handle. 
 * --------------------------------------------------                
 * ===================================================
* This routine is called first by the EnSight Server!
* ===================================================
*
* Note that the return from this routine is USERDHandle, which is a pointer.
*
* A) You should have typedef'ed a structure, something like the following:
*
*    typedef struct {
*
*       * Required 1st item
*       *------------------*
*        ReaderHandle_30 server;
*
*       * Reader specific info
*       *---------------------*
*        char *filename;
*        char *path;
*    } EnSightRdrHandle;
*
*    Where:
*      1. Name can be whatever, but must be returned from this routine.
*      2. The first item in the structure must be the ReaderHandle_30 structure.
*         This struct is defined in ../extern/global_extern.h
*      3. You can then add whatever reader specific members you desire after 
 *         the ReaderHandle_30 structure.
*
* B) Allocate the handle, something like:
*      EnSightRdrHandle *hdl = (EnSightRdrHandle *) calloc(sizeof(EnSightRdrHandle),1);
*
* C) Load the items in the ReaderHandle_30 portion of the handle.
*    (You can see this structure in ../extern/global_extern.h)
* 
 *    WARNING: The EnSight server, on startup, checks each of these members for each
*      reader. These must be populated properly. And, you cannot use strcpy into these 
 *      char pointers below as they are null pointers. A strcpy will crash the reader 
 *      and, consequently, crash the server immediately on startup. Use an assignment 
 *      operator, as below, or use the C strdup function.
*
*      hdl->server.APIVersion = "3.00";                              <<< Warning max length is Z_MAX_USERD_NAME
*      hdl->server.reader_name = "Ensight Sample 3.0";               <<< Warning max length is Z_MAX_USERD_NAME
*      hdl->server.reader_description = "EnSightSample 3.0 Reader";  <<< Warning max length Z_MAXFILENP
*      hdl->server.reader_release = "1.0 Beta";                      <<< Warning length limit is Z_MAX_USERD_NAME
*      hdl->server.iTwoFields = 0;                                   <<< 1 (TRUE) if two fields used for two files
*                                                                        (e.g. a geometry and a variable file)
*      hdl->server.iUseAutoDistribute                                <<< set to 1 (TRUE) if not parallel SOS, otherwise
*                                                                        see section 'E' below.
*      hdl->server.file_button_label_1 = "Set case";                 <<< Warning length limit is Z_MAX_USERD_NAME 
 *      hdl->server.file_button_label_2 = "";                         <<< Warning length limit is Z_MAX_USERD_NAME
*                                                                        this is only used if iTwoFields is TRUE 
 *      etc...
*
* D) If your reader needs to give the user some extra options to control the way the reader behaves,
*     there is a space in the data reader dialog in the Format Options tab where you can supply 
 *     customized GUI options to solicit user input as defined using the struct:
*   
 *         UserDefinedGUI_10 *gui_options
*         This struct is defined in ../extern/global_extern.h.
*         Using this this struct, you can define
*         the toggles, pulldowns, and fields that show up in the 
 *         Data reader format options tab, and provide the
*         defaults for them.  This all goes in the handle.
*  
 *         The User choices or entries will be avaiable in the handle
*         as well.  These are available by the time the USERD_set_filenames
*         routine is called.  So that is typically a good place to set things
*         appropriately for the given responses.  But, of course user selections
*         can be used later as well.
*
*         Three routines are supplied in the test3u_advance example reader found in
*         your src/readers/test3u_advanced folder in your EnSight install in order
*         to demonstrate the coding and usage of this feature: 
 *           define_gui_options - defined the presentation and defaults options
*           handle_gui_options - extract the user choices 
 *           free_gui_options - called from USERD_reader_close to free up memory
*           when the EnSight session ends.
*
*         If you don't want the extra GUI features,
*         simply set the numbers of each type to zero.
*
*         Toggle data will return an integer
*                             TRUE if checked
*                             FALSE if unchecked
*
*         Pulldown menu will return an integer representing
*                             the menu item selected
*
*         Field will return a string Z_LEN_GUI_FIELD_STR long.
*
*         In this routine define the numbers of toggles, pulldowns & fields
*
*        The following are defined in the ../extern/global_extern.h
*          Z_MAX_NUM_GUI_PULL_ITEMS max num GUI pulldowns
*          Z_LEN_GUI_PULL_STR  max length of GUI pulldown string
*          Z_LEN_GUI_FIELD_STR  max length of field string
*          Z_LEN_GUI_TITLE_STR   max length of title string
*
* E) Server of Servers (parallel) 
 *    Notes:
*     In API 3, the handle has three attributes for handling server of servers
*       that replace two routines from API 2.0
*     hdl->server.iCurrentServer        - this is set by the server to tell the 
 *                                         reader which server number (1-based)
*                                         (replaces call to USERD_set_server)
*     hdl->server.iTotalNumberOfServers - this is set by the servr to tell the
*                                         reader the total number of servers 
 *                                         (replaces USERD_set_server).
*     hdl->server.iUseAutoDistribute    - this must be set in the USERD_reader_open 
 *                                         if running EnSight in parallel Server of 
 *                                         Server (SOS) mode,  
 *                                         (replaces USERD_prefer_auto_distribute).
*                                         Set this flag to communicate the reader  
 *                                         expectation for how to handle data, as
*                                         described below  
 *                                         (replaces USERD_prefer_auto_distribute).
*
*    How to use the iUseAutoDistribute flag
*    When running in parallel, with multiple server (Server of Servers, SOS mode)
*     EnSight has three options. 
 *       Autodistribute -    The reader returns all data up for all servers and leaves 
 *                            it to EnSight to self-partition the data and apportion 
 *                            it among the Servers.  
 *                            In this case, the server will tell the reader
*                            on all the servers that it is server 1 
 *                            (hdl->server.iCurrentServer will be set by the server to 1) 
 *                            of a total of 1 servers
*                            (hdl->server.iTotalNumberOfServers will be set to 1).
*                            In this situation, set iUseAutoDistribute to FALSE.
*
*       Don't Distribute -  The data is already partitioned and physically separated
*                            such that each reader and each server can consume all the
*                            data unchanged and pass it upwards to EnSight. This is rare,
*                            In this case, the server will tell the reader
*                            on all the servers that it is server 1 
 *                            (hdl->server.iCurrentServer will be set by the server to 1) 
 *                            of a total of 1 servers
*                            (hdl->server.iTotalNumberOfServers will be set to 1).
*                            In this situation, set iUseAutoDistribute to FALSE.
*       Reader Distribute -  set iUseAutoDistribute to TRUE to tell EnSight that each
*                            reader, on each server, will take the responsibility for
*                            the decomposition of the data
*                            In this situation, hdl->server.iCurrentServer will be the
*                            the actual 1-based, current server number, and 
 *                            hdl->server.iTotalNumberOfServers will be the total number 
 *                            of servers.
*
* F) Load any items you desire in the reader specific portion.  Now or later.
*
* G) Return the handle from USERD_reader_open(), casting it to USERDHandle, like:
*      return ((USERDHandle)hdl);
*
* H) Output text meant for the user, that is in one of the following 
 *    calls will ensure that it will end up in the EnSight message window and be
*    useable to the user to understand what is happening. The level of output 
 *    is characterized by Normal, Verbose, and Debug. Note there are many, many
*    examples in this reader on how to use these routines.
*
*    USERD_info  - Letting you know what is happening 
 *    USERD_warn  - A problem was encountered but code will proceed as described
*                   and perhaps a description of how to avoid this issue in
*                   the future.
*    USERD_error - An insurmountable problem was encountered and the reader
*                  is going to cease reading.
*    
 *
* I) ERROR handling in USERD routines
*
*    1. Many of the USERD routines return Z_OK or Z_ERR and it is expected that 
 *       a Z_ERR return will be preceeded by a USERD_error call with text that 
 *         explains what went wrong, and perhaps how to fix it.
*
*    2. A USERD routine may have a return value to use for an error, and also,
*       for User Defined Reader API 3.x,  most of the routines 
 *       check the status of an integer named iErrorFlag.
*       hdl->server.iErrorFlag  (values defined as enum _error_codes from
*       ../extern/global_extern.h, as follows
*       
 *             Z_ERR_NONE, 
 *             Z_ERR_ALLOC,
*             Z_ERR_FOPEN,
*             Z_ERR_FREAD,
*             Z_ERR_FWRITE,
*             Z_ERR_FSEEK,
*             Z_ERR_PCREATE,
*             Z_ERR_INVALID,
*            
 *      and if the value of iErrorFlag is not Z_ERR_NONE, then it prints off an
*      error message from 
 *      hdl->server.sErrorString which is a string Z_MAXSTR (1024) long as follows.
*      char sErrorString[Z_MAXSTR];
*     
 *       which is handled on the server by printing the error string and then clearing 
 *       the error string and the error code and, sometimes, sending the appropriate
*       error up to the EnSight server. In practice it prints the error code to the 
 *       message box and sometimes just continues on, so this is not a good error 
 *       handling methodology.
*      
 *      More details: the server routine is in userd_read.c in
*      process_udr_error(ReaderHandle_30 *handle, int print_flag, int clear_flag)
*      in which print_flag (currently always TRUE, prints the string using cvf_report
*      and clear_flag (always TRUE) clears the iErrorFlag and sErrorString and creates
*      an EnSight server error corresponding to the above error codes. This is not 
 *      really handled always by the server, so this is not a good error methodology.
*     
 *      Up to date information will always be in the source code of the demo 
 *      test3u_advanced.c reader found in the EnSight installation.

4.5.2.2. USERD_get_name_of_reader

/* -----------------------------------------------
USERD_get_name_of_reader

*                                            (version 2.00 and later)
 *--------------------------------------------------------------------
 *
 *  Gets the name of your user defined reader.  The user interface will
 *  ask for this and include it in the available reader list.
 *
 *  (OUT) reader_name          = the name of the reader (data format)
 *                             (max length is Z_MAX_USERD_NAME, which
 *                              is 20)
 *
 *  (OUT) *two_fields          = FALSE if only one data field is required
 *                                     in the data dialog of EnSight.
 *                               TRUE if two data fields required
 *
 *                              -1   if one field (Geom) required 
 *                                   and one field (Param) is optional
 *                                   Param field can contain any text
 *                                   for example a file name, modifiers,
 *                                   etc. that can be used to modify the
 *                                   reader's behavior.
 * 
 *  returns: Z_OK  if successful
 *           Z_ERR if not successful
 *
 *  Notes:
 *  * Always called.  Provide a name for your custom reader format
 *--------------------------------------------------------------------*/
int
USERD_get_name_of_reader(char reader_name[Z_MAX_USERD_NAME],
                         int *two_fields)



4.5.2.3. USERD_get_reader_descrip

/* -----------------------------------------------
USERD_get_reader_descrip

 *                               <optional>   (Version 2.00 and later)
 *--------------------------------------------------------------------
 *
 *  Gets the description of the reader, so gui can give more info
 *
 *  (OUT) reader_descrip       = the description of the reader
 *                             (max length is MAXFILENP, which
 *                              is 255)
 *
 *  returns: Z_OK  if successful
 *           Z_ERR if not successful
 *
 *--------------------------------------------------------------------*/
int
USERD_get_reader_descrip(char descrip[Z_MAXFILENP])



4.5.2.4. USERD_get_reader_version

/* -----------------------------------------------
USERD_get_reader_version

 *                                            (Version 2.00 and later)
 *--------------------------------------------------------------------
 *
 *   Gets the API version number of the user defined reader
 *
 *   The functions that EnSight will call depends on this API
 *   version.  See the README files for more information.
 *
 *  (OUT) version_number       = the version number of the reader
 *                             (max length is Z_MAX_USERD_NAME, which
 *                              is 20)
 *
 *  returns: Z_OK  if successful
 *           Z_ERR if not successful
 *
 *  Notes:
 *  * Always called.
 *
 *  * This needs to be "2.000" or greater. Otherwise EnSight will assume
 *    this reader is API 1.0 instead of 2.0
 *--------------------------------------------------------------------*/
int
USERD_get_reader_version(char version_number[Z_MAX_USERD_NAME])



4.5.2.5. USERD_get_reader_release

/* -----------------------------------------------
USERD_get_reader_release

 *                                <optional>  (Version 2.00 and later)
 *--------------------------------------------------------------------
 *
 *   Gets the release string for the reader.
 *
 *   This release string is a free-format string which is for
 *   informational purposes only.  It is often useful to increment
 *   the release number/letter to indicate a change in the reader.
 *   The given string will simply be output by the EnSight server
 *   when the reader is selected.
 *
 *  (OUT) release_number       = the release number of the reader
 *                             (max length is Z_MAX_USERD_NAME, which
 *                              is 20)
 *
 *  returns: Z_OK  if successful
 *           Z_ERR if not successful
 *
 *  Notes:
 *  * Called when the reader is selected for use.
 *--------------------------------------------------------------------*/
int
USERD_get_reader_release(char version_number[Z_MAX_USERD_NAME])



4.5.2.6. USERD_reader_close

/*-----------------------------------------------
* USERD_reader_close - destroy the handle
* ------------------
*
*  (IN)  handle         = The USERDHandle pointer
*                         created in USERD_reader_open
*
*
* This is the last reader routine called prior to
*  shutting down the EnSight server. It provides a 
 *  chance to cleanly free the memory used in this 
 *   reader. 
 *
* 
 * Free memory, first for 
 *   any allocated members of the handle memory 
 *   and then the handle itself.
*
*
*
*------------------------------------------------*/
int
USERD_reader_close(USERDHandle handle)

4.5.2.7. USERD_exit_routine

//*--------------------------------------------------------------------
* USERD_exit_routine
*--------------------------------------------------------------------
*
*  (IN)  handle         = The USERDHandle pointer
*                         created in USERD_reader_open
*
*  When the EnSight server receives the command to shut down, 
 *   and it is connected to a user-defined reader, it calls the
*   following two cleanup routines, in the following order:
*
*   USERD_exit_routine - clean up external connections.
*   USERD_reader_close - free memory
*  
 *   So, this second-to-last reader routine called prior to server
*   shutdown can be used to close and/or clean up temporary files, 
 *   end comm connections, etc. 
 *
*   Note: It is most often simply a sample routine.
*--------------------------------------------------------------------*/
void
USERD_exit_routine(USERDHandle handle)

4.5.2.8. USERD_get_descrip_lines

/*--------------------------------------------------------------------
* USERD_get_descrip_lines - 
 *-------------------------------------------------------------------- 
 * 
 *   This routine is called to get descriptive text line(s) which can
*    be used by the user in EnSight annotations.
*   
 *   This routine is called once for geometry (which_type set to Z_GEOM) 
 *    and expects two lines of text. Then it is called once for each
*    variable (which_type is set to Z_VARI) and expects to get one
*    text line for each variable.
*   
 *   Get two description lines associated with geometry per time step, 
 *   or one description line associated with a variable per time step. 
 * 
 *  (IN)  handle               = The USERDHandle pointer
*                               created in USERD_reader_open
*
*        which_type           = Z_GEOM for geometry 
 *                             = Z_VARI for variable 
 * 
 *        which_var            = If it is a variable, which one. 
 *                               Ignored if geometry type. 
 * 
 *        imag_data            = TRUE if want imaginary data file. 
 *                               FALSE if want real data file. 
 * 
 *  (OUT) line1                = The 1st geometry description line, 
 *                               or the variable description line. 
 * 
 *        line2                = The 2nd geometry description line 
 *                               >>> Not used if variable type. 
 * 
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *   This will be based on hdl->current_time_step
* 
 *   These are the lines EnSight can echo to the screen in 
 *    annotation mode. 
 *--------------------------------------------------------------------*/ 
int 
USERD_get_descrip_lines(USERDHandle handle,
                        int which_type,
                        int which_var,
                        int imag_data,
                        char line1[Z_BUFL],
                        char line2[Z_BUFL])

4.5.2.9. USERD_attribute

USERD_attribute(int attribute name, 
int *value, 
int get_set_flag)
/* -----------------------------------------------------------------
   * Brief tutorial on USERD_attribute
   * 
   *
   * This routine is unusual in that it is not called BY the server,
   * but rather calls UP to the server to get or set some attribute value.
   * You put into another USERD routine no later than the end of 
   * USERD_set_filenames 
   * 
   * Further, it is unusual, in that it can be called both by a User Defined
   * reader OR a User Defined Writer.
   *
   *
   *
   *  (IN) get_set_flag – set to USERD_ATTR_GET or USERD_ATTR_SET
   *
   *   A. get a specific attribute value in order to change the behavior
   *      of your reader, where get_set_flag = USERD_ATTR_GET 
   *      or 
   *   B. set a specific attribute that changes the behavior of the 
   *      EnSight server, where get_set_flag = USERD_ATTR_SET 
   *      (Note: not all parameters can be set!)   
   *      or
   *   C. get the value of a attribute from the server, 
   *      get_set_flag = USERD_ATTR_SET on the first call, and then 
   *      set it to affect the server behavior (if it can be set), 
   *      where get_set_flag = USERD_ATTR_SET on the second call
   *
   *  (IN or OUT) *value – can be a float or an int or a pointer to a 
   *                       pointer to a string. 
   *                       If GET then never deallocate *value
   *                       If SET, then deallocate *value after the call is OK
   *
   *  (IN) attribute_name  - can be one of the following:
   *       USERD_ATTR_UNDEFINED_VALUE –    (get/set) the current 'undefined' float *value
   *       USERD_ATTR_DYNAMIC_DATA_FLAG –  (get/set) nonzero if the server will be polling 
   *                                        for dynamic data int *value
   *       USERD_ATTR_TEMPORAL_XY_QUERIES –(get/set) if nonzero int *value, then the reader 
   *                                        has queries that change over time
   *       USERD_ATTR_TEMPORAL_SOS –       (get only) int *value, is nonzero if the temporal SOS 
   *                                        mode is in use
   *       USERD_ATTR_SPATIAL_SOS -        (get only) int *value, is nonzero if the spatial SOS 
   *                                        mode is in use
   *       USERD_ATTR_SERVER_NUMBER -      (get only) int *value, one based server number 
   *                                       (useful in writers)
   *       USERD_ATTR_NUMBER_OF_SERVERS -  (get only) int *value, number of servers 
   *                                       (useful in writers)
   *       USERD_ATTR_MAX_SERVER_THREADS – (get/set) int *value, maximum number of threads 
   *                                        that a reader should use (useful if it is known that
   *                                        multiple servers are running on one machine to 
   *                                        limit each server's reader from using up all the threads
   *       USERD_ATTR_CEI_HOME -           (get only) const char **value, the current location of where 
   *                                       EnSight is running known informally as the CEI_HOME string 
   *                                       (not the environmental variable)
   *       USERD_ATTR_CEI_ARCH -           (get only) const char **value, the current platform string
   *                                       e.g. "win64", "linux_2.6_64" or "apple"
   *       USERD_ATTR_CEI_SUFFIX -         (get only) const char **value, the current "suffix" string 
   *                                       (e.g. "211") for the 2021R1 build
   *       USERD_ATTR_WRITER_BASEFILENAME –(get only) const char **value, ONLY in a user-defined writer, 
   *                                       the base output filename without SOS, server specific 
   *                                       extension for parallel I/O aware USERD writers.
   *
   *   NOTE: When running EnSight in parallel, with multiple Servers, each reading 
   *         a portion of a dataset, and all connected to a communication hub, known as
   *         a Server of Servers (SOS), if your reader calls this function,
   *         the function will always return an error. Further, if the get_set_flag
   *         is set to USERD_ATTR_SET, then this will NOT set this attribute on any 
   *         of the other Servers, nor the SOS.
   *
   *
   * some examples:
   * 1. Ordinarily the xy query routines are called once and never updated.
   * To tell the server to re-call the three xy query routines when time changes,
   * so you can update the xy data pairs,
   * do the following into the USERD_set_filenames routine:
   */
  int xy_query_tmp = 0;  // change to 1 to update 
  if (Z_ERR == USERD_attribute(USERD_ATTR_TEMPORAL_XY_QUERIES, &xy_query_tmp, USERD_ATTR_SET)) {
    if (xy_query_tmp==1) {USERD_warn("Failed to set xy_queries to update on timestep change\n");}
    else                 {USERD_warn("Failed to set xy_queries to not update on timestep change, which is the default\n");}
  }
  // note for now we get all the xy query values once
  // This will need to be changed if xy_query_tmp == 1
  if (Z_ERR == read_xy_queries_once(hdl)) return(Z_ERR);
  
  /* Note the default is that queries are not updated on time change 
   *  and with xy_query_tmp = 0 this changes nothing 
   *
   * if xy_query_tmp = 1, then 
   * The following three routines will be called every time that time is changed:
   * USERD_get_num_xy_queries – You must not change the number of queries!
   * USERD_get_xy_query_info – You can change the number of pairs, as well as
   * the name and titles, but they may not update in the plot
   * unless replotted.
   * USERD_get_xy_query_data – You can freely change the x and y data values
   *
   * Note: If you are using SOS, then all of the servers will be called to update
   * the xy query data. You only need to have one of the servers handle this; the
   * others should ignore it.
   *
   * Note: there is an attribute in the client python used as a flag which can be changed
   * as well independently to enable this capability interactively.
   *
   * 2. Ordinarily the isovolume is a bit jagged because it uses an elemental variable.
   */
  int tmp_iso = 0;  // this will do the equivalent of a test: simple_isovolume_off
                    // from the client command window
  if (Z_ERR == USERD_attribute(USERD_ATTR_SIMPLE_ISOVOLUME,&tmp_iso,USERD_ATTR_SET)) {
    USERD_warn("Failed to set isovolumes to use interpolated nodal variable\n");
  }
  /* And now your isovolumes will use an interpolated nodal variable for smoothness
   *
   * 3. Suppose you want to locate your reader, perhaps to read a meta data file
   * colocated with your reader. USERD_attributes can supply you with the
   * CEI locations that will enable you to reconstruct the path to your reader
   * as follows.
   *
   *
   *  CEI_HOME, CEI_ARCH, CEI_SUFFIX
   * And use it to print out the location of this reader
   *
   * ---------------------------------------------------- */
  USERD_info("--------- CEI_HOME -- CEI_ARCH ---- CEI_SUFFIX -----\n");
  const char *tmp  = NULL;
  char *cei_home   = NULL;
  char *cei_arch   = NULL;
  char *cei_suffix = NULL;

  if (Z_ERR != USERD_attribute(USERD_ATTR_CEI_HOME, &tmp, USERD_ATTR_GET)) {
    // can use std::string cei_home(tmp);    
    if (tmp && strlen(tmp) > 0) {
      cei_home =  (char *) calloc (sizeof(char), strlen(tmp)+1 );
      if (cei_home) {
        strcpy(cei_home, tmp);
        USERD_info("CEI_HOME: '%s'", cei_home);
      }
    }
  }
  
  if (Z_ERR != USERD_attribute(USERD_ATTR_CEI_ARCH, &tmp, USERD_ATTR_GET)) {
    // can use std::string cei_arch(tmp);    
    if (tmp && strlen(tmp) > 0) {
      cei_arch = (char *)calloc(sizeof(char), strlen(tmp) + 1);
      if (cei_arch) {
        strcpy(cei_arch, tmp);
        USERD_info("CEI_ARCH: '%s'", cei_arch);
      }
    }
  }

  if (Z_ERR != USERD_attribute(USERD_ATTR_CEI_SUFFIX, &tmp, USERD_ATTR_GET)) {
    // std::string cei_suffix(tmp);    
    if (tmp && strlen(tmp) > 0) {
      cei_suffix = (char *)calloc(sizeof(char), strlen(tmp) + 1);
      if (cei_suffix) {
        strcpy(cei_suffix, tmp);
        USERD_info("CEI_SUFFIX: '%s'", cei_suffix);
      }
    }
  }
  /* Put it all together */
  if (cei_arch && cei_suffix && cei_home) {
    char cei_libsuffix[14] = { '\0' };
    if ( 0 == strcasecmp(cei_arch, "win64")) {
      strcpy(cei_libsuffix, "dll");
    }  else if (0==strcasecmp(cei_arch,"linux_2.6_64")) {
      strcpy(cei_libsuffix,"so");
    }  else if (0 == strcasecmp(cei_arch, "apple")) {
      strcpy(cei_libsuffix, "dylib");
    }
    USERD_info("Location of this reader: '%s/ensight%s/machines/%s/lib_readers/libuserd-test3u_advanced.%s",cei_home,cei_suffix,cei_arch,cei_libsuffix);
  }
  
  // note you can free the cei_home, cei_arch, cei_suffix, but do not free tmp
  safe_free(cei_arch);
  safe_free(cei_home);
  safe_free(cei_suffix);
  
  USERD_info("---------------------------- -----\n\n");

4.5.2.10. USERD_get_metadata

/* -----------------------------------------------
USERD_get_metadata

 *                                            (version 2.00 and later)
 *                                
 *--------------------------------------------------------------------
 * 
 * This provides a mechanism to provide the EnSight client extra
 * information designed to customize EnSight directly from the reader
 * Meta data is XML formatted string of chars sent up to EnSight in two
 * sequential calls of this routine. 
 * 
 * Presumably you would open the dataset file(s) in USERD_set_filenames,
 *  understand the dataset, the parts, and the variables, and assemble
 *  together this array of metadata in an XML character string.
 * 
 * The first call of this routine is designed to send the actual length
 *   of the meta_char so EnSight can allocate the char container.
 *  (IN)  handle     = The USERDHandle pointer


 *                     created in USERD_reader_open

 * (IN)  meta_char = (char *) NULL <- this indicates its the first call
 * 
(OUT) actual len is the strlen(meta_char)
 * 
 * The second call of this routine is designed to fetch the char array.
 *  (IN)  handle     = The USERDHandle pointer


 *                     created in USERD_reader_open

 * (IN) actual_len = this is the length of the char array in bytes that EnSight
 *                   has allocated, ready to receive your xml formatted chars
 * (OUT) meta_char = (char *) pointer ready to be populated
 *
 * Here's a sample (without the asterisks):
 *
<?xml version="1.0" encoding="UTF-8"?>
<CEImetadata version="1.0"> 
  <parts>
    <partlist>
      <group name="simple group">
        <part name="anotherpart"></part>
      </group>
      <part name="mypart"></part>
    </partlist>
  </parts>
  <vars>
    <metatags>
      <tag name="ENS_UNITS_LABEL" type="str"></tag>
      <tag name="ENS_UNITS_DIMS" type="str">/</tag>
    </metatags>
    <varlist>
      <var name="myvar" ENS_UNITS_LABEL="m s^-1" ENS_UNITS_DIMS="L/T"></var>
      <var name="Coordinates" ENS_UNITS_LABEL="m" ENS_UNITS_DIMS="L"></var>
      <var name="Time" ENS_UNITS_LABEL="s" ENS_UNITS_DIMS="T"></var>
    </varlist>
  </vars>
  <xy_queries>
    <metatags>
      <tag name="ENS_UNITS_QUERY_X_VAR" type="str"></tag>
      <tag name="ENS_UNITS_QUERY_Y_VAR" type="str"></tag>
    </metatags>
    <querylist>
     <query name="myvar vs time" ENS_UNITS_QUERY_X_VAR="Time" ENS_UNITS_QUERY_Y_VAR="myvar"></query>
     <query name="myvar vs Re" ENS_UNITS_QUERY_X_VAR="myvar"     ENS_UNITS_QUERY_Y_VAR=""></query>
    </querylist>
  </xy_queries>
  <case>
    <metatags>
      <tag name="ENS_UNITS_LABEL" type="flt">2.0</tag>
      <tag name="ENS_UNITS_DIMS" type="flt">1.0</tag>
      <tag name="ENS_UNITS_SYSTEM" type="flt">1.0</tag>
      <tag name="ENS_UNITS_SYSTEM_NAME" type="str">SI</tag>
    </metatags>
  </case>
</CEImetadata>
 * 
 * Note: some datasets may record this metadata into a separate file
 *  which is a perfectly valid methodology for recording this data.
 * The XML format is the same: this is done in EnSight Case Gold format.
 * A user defined reader can just read the data in and pass it up
 *  via this mechanism.
 * 
 * There are sections for parts, variables, xy_queries 
 * (only used by user-defined readers that support xy queries) 
 * and the case.  Note that in each section, objects are matched to metadata 
 * using their name (the DESCRIPTION property on the corresponding EnSight 
 * Python object). Each section begins by defining the attributes to be 
 * defined for the objects in the section using a <metatags> section.  
 * It defines all the attributes and their type (flt=float, str=string).  
 * The value specified for the <tag> is the default attribute value that 
 * is assigned if an object does not specify the attribute.  
 * When debugging metadata files, it can be useful to review what 
 * EnSight sees.  The Python command:
 * ensight.objs.core.CURRENTCASE[0].SERVERXML
 * will return the XML metadata for the current case. 
 * 
 * In the example, the <parts> section just defines the grouping hierarchy 
 * that should be used when the dataset is loaded.  Spatial units for 
 * parts are defined by the (implicit) 'Coordinates' variable. 
 * In the <vars> section, ENS_UNITS_DIMS and ENS_UNITS_LABEL metatags 
 * are defined. In the example, the former is set to default to unit-less "/".
 *  Each variable defined in the dataset is then listed in the <varlist> 
 * section with the appropriate values for ENS_UNITS_DIMS and ENS_UNITS_LABEL.
 *   
 *  Note that label strings should have the format: {unit}[{^{power}] 
 * with spaces between individual units.  If the power is 1, 
 * the ^{power} can be dropped. If the unit is in the denominator, 
 * the power should be negative.  No '/' characters should be in the label 
 * and all positive powers should appear before negative powers. An example 
 * for m/s= "m s^-1" and for m2/s2= "m^2 s^-2".
 * Always include the implicit "Coordinates" and "Time" variables.
 * 
 * Queries are handled a little differently.  
 * The <xy_queries> should only be used by a user-defined reader that 
 * implements the USERD_get_num_xy_queries, USERD_get_xy_query_info and
 *  USERD_get_xy_query_data functions. The two attributes: 
 * ENS_UNITS_QUERY_X_VAR and ENS_UNITS_QUERY_Y_VAR should be defined 
 * and set to the name of a variable in the dataset that has the same 
 * dimensions as the specified axis.  The units for that specific axis 
 * will be taken from the variables named by those attributes. 
 * Note: there is no requirement that the variable name provided is 
 * the variable in the query, only that the units of that variable 
 * match the units of the axis of the specific query.
 * 
 * The <case> section serves to define two things. First, it defines the 
 * versions of the ENS_UNITS_LABEL, ENS_UNITS_DIM and ENS_UNITS_SYSTEM_NAME
 * protocols.  These are all float values and should be set to 2.0, 1.0 
 * and 1.0 respectively as shown in the example (there is an earlier 
 * version of the ENS_UNITS_LABEL protocol, but it is not recommended 
 * for new development).  Second, the name of the unit system that 
 * all the data that will be returned by the user-defined reader or is 
 * stored in the case gold format files.  
 * The list of valid unit system names includes the system string values 
 * from this table:
 * 
 * System name  	    System string	   Units: mass, length, time, temperature, 
 *                                  current, angle, intensity, substance amount	   
 * 
 * Metric SI	         SI	             kg, m, s, A, K, rad, mol, cd	   
 * Metric CGS   	     CGS	            g, cm, s, A, C, rad, mol, cd	   
 * US ft Consistent  	BFT            	slug, ft, s, A, F, rad, slugmol, cd	   
 * US in Consistent	  BIN	            slinch, in, s, A, F, rad, lbmmol, cd	   
 * Metric MKS        	MKS            	kg, m, s, A, C, rad, mol, cd	   
 * Metric MPA        	MPA            	tonne, mm, s, mA, C, rad, mol, cd	   
 * Metric uMKS	       uMKS           	kg, um, s, pA, C, rad, mol, cd	   
 * Metric CGSK	       CGSK           	g, cm, s, A, K, rad, mol, cd	   
 * Metric NMM	        NMM	            kg, mm, s, mA, C, rad, mol, cd	   
 * Metric uMKSS	      uMKSS          	kg, um, s, mA, C, rad, mol, cd	   
 * Metric NMMDAT     	NMMDAT         	decatonne, mm, s, mA, C, rad, mol, cd	   
 * Metric NMMTON     	NMMTON	         tonne, mm, s, mA, C, rad, mol, cd	   
 * US ft	             BFTS           	lbm, ft, s, A, F, rad, lbmmol, cd	   
 * US in             	BINS           	lbm, in, s, A, F, rad, lbmmol, cd	   
 * US Engineering	    USENG          	lb, in, s, A, R, rad, lbmmol, cd	 
 * 
 * It should be noted that for proper unit support in EnSight, only the 
 * ENS_UNITS_DIMS and ENS_UNITS_SYSTEM_NAME protocols need to be defined.
 * The ENS_UNITS_LABEL protocol allows a dataset to specify a custom label 
 * to be used when a dataset is loaded in its natural unit system 
 * (for example, "Pa" for M/LTT dimensions instead of the generated "kg/(mENTITY___middot;s2)").
 * 
 * EnSight will generate a valid unit label from the dimension string 
 * and the unit system if no label is specified, the current session 
 * unit system does not match the one in the dataset and for all 
 * computed variables.
 * 
 * ------------------------------------------------- */

int 
USERD_get_metadata(
USERDHandle handle, 

int *actual_len, char *meta_char)

4.5.2.11. USERD_get_element_label_status

/* -----------------------------------------------
USERD_get_element_label_status

 *-------------------------------------------------------------------- 
 * 
 *  Answers the question as to whether element labels will be provided. 
 * 
 *  (IN)  handle         = The USERDHandle pointer
 *                         created in USERD_reader_open
 *
 *  returns:  TRUE   if element labels will be provided by this reader 
 *            FALSE  if element labels will NOT be provided by this reader
 * 
 *  Notes: 
 *  * These are needed in order to do any element querying, or 
 *    element labeling on-screen. 
 *--------------------------------------------------------------------*/



4.5.2.12. USERD_get_node_label_status

/* -----------------------------------------------
USERD_get_node_label_status

 *-------------------------------------------------------------------- 
 * 
 *  Answers the question as to whether node labels will be provided. 
 * 
 *  (IN)  handle         = The USERDHandle pointer
 *                         created in USERD_reader_open
 *
 *  returns:  TRUE    if node labels will be provided in this reader 
 *            FALSE   if node labels will NOT be provided in this reader
 * 
 *  Notes: 
 *  * These are needed in order to do any node querying, or node 
 *    labeling on-screen                               . 
 *--------------------------------------------------------------------*/ 
int
USERD_get_node_label_status(USERDHandle handle)
{
  EnSightRdrHandle *hdl = (EnSightRdrHandle *)handle;

  if(hdl->server.iVerboseLevel == Z_FULL) {
    fprintf(stderr,"  > Node Labels will be provided\n");
  }

  return(TRUE);
}




4.5.2.13. USERD_get_number_of_timesets

/* -----------------------------------------------
USERD_get_number_of_timesets

 *--------------------------------------------------------------------
 *
 *  Gets the number of timesets used in the model.
 *
 *  (IN)  handle         = The USERDHandle pointer
 *                         created in USERD_reader_open
 *
 *  If you have a static model, both geometry and variables, you should
 *  return a value of zero. 
 *
 *  If you have a transient model, then you should return one or more.
 *
 *  For example:
 *
 *     Geometry    Variables                                 No. of timesets
 *     ---------   ------------------------------            ---------------
 *     static      static                                      0
 *     static      transient, all using same timeset           1
 *
 *     transient   transient, all using same timeset as geom   1
 *
 *     static      transient, using 3 different timesets       3
 *
 *     transient   transient, using 3 different timesets and
 *                            none of them the same as the
 *                            geometry timeset                 4
 *         etc.
 *
 *  NOTE: ALL GEOMETRY MUST USE THE SAME TIMESET!!! You will have to provide
 *                                                  the timeset number to use
 *                                                  for geometry in:
 *                                              USERD_get_geom_timeset_number
 *
 *        Variables can use the same timeset as the geometry, or can use
 *        other timesets. More than one variable can use the same timeset.
 *
 *  example:  changing geometry at 5 steps, 0.0, 1.0, 2.0, 3.0, 4.0
 *            variable 1 provided at these same five steps
 *            variable 2 provided at 3 steps, 0.5, 1.25, 3.33
 *
 *       This routine should return a value of 2, because only
 *       two different timesets are needed. Timeset 1 would be for the
 *       geometry and variable 1 (they both use it). Timeset 2 would
 *       be for variable 2, which needs its own in this case.
 *
 *  Notes:
 *--------------------------------------------------------------------*/




4.5.2.14. USERD_get_timeset_description

/* -----------------------------------------------
USERD_get_timeset_description

 *-------------------------------------------------------------------- 
 * 
 *  Get the description to associate with the desired timeset.
 * 
 *  (IN)  handle              = The USERDHandle pointer
 *                              created in USERD_reader_open
 *
 *        timeset_number      = the timeset number
 *
 *                              For example: If USERD_get_number_of_timesets
 *                                           returns 2, the valid
 *                                           timeset_number's would be 1 and 2.
 *
 *  (OUT) timeset_description  = timeset description string 
 * 
 * 
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *  * A string of NULLs is valid for timeset_description
 *--------------------------------------------------------------------*/ 
int 
USERD_get_timeset_description(USERDHandle handle,
                              int timeset_number,
                              char timeset_description[Z_BUFL]) 
{ 
  EnSightRdrHandle *hdl = (EnSightRdrHandle *)handle;

#if 0
  if(timeset_number == 1) {
    strcpy(timeset_description,"Static Geometry timeset");
  }
  else if(timeset_number == 2) {
    strcpy(timeset_description,"Transient Variable timeset");
  }

#else
  strcpy(timeset_description,"Static Geometry timeset");

#endif

  if(hdl->server.iVerboseLevel == Z_FULL) {
    fprintf(stderr,"  > Description for timeset %d = %s\n",timeset_number, timeset_description);
  }

  return(Z_OK);
}



4.5.2.15. USERD_get_num_of_time_steps

/*--------------------------------------------------------------------
* USERD_get_num_of_time_steps - 
 *-------------------------------------------------------------------- 
 * 
 *   Get the number of time steps of data available for desired timeset. 
 *
*  (IN)  handle               = The USERDHandle pointer
*                               created in USERD_reader_open
*
*        timeset_number       = the timeset number
*                                    
 *
*  returns: number of time steps (>0 if okay, <=0 if problems). 
 * 
 *  Notes: 
 *  * This should be >= 1       1 indicates a static timeset 
 *                             >1 indicates a transient problem 
 *
* returns: number of time steps (>0 if okay, <=0 if problems).
*
* Notes:
* * This should be >= 1, and  1 indicates a static timeset
*                            >1 indicates a transient problem
*
*
* SPECIAL NOTE: Normally this routine is called just once through the normal
*          pipeline. The timeset_number sent to it will be a positive value.
*
*          However, if 1) a USERD_get_max_time_steps routine is implemented, and
*                      2) the USERD_get_max_time_steps routine returns a
*                         value greater than 1, and
*                      3) the user hits the GUI button that calls for time to
*                         be reloaded (or it is set to automatic),
*
*                      Then the timeset_number sent to this routine will be
*                       the negative of the actual value. Indicating that it
*                       is being called for a reload purpose. Basically a
*                       "coprocessing" purpose. Then this routine must also do
*                       the following:
*
*                       a) Check for the negtive timeset_number, and reverse it.
*                       b) Go get the new current number of time steps.
*                       c) Ensure that when USERD_get_sol_times is called again,
*                          that the new solution times are included. 
 *                       d) Note also that model constant values need to have
*                          their values updated to add the additional time steps
*                          USERD_get_model_constant_val will be called using the 
 *                          new timestep(s). So you may need to resize your model
*                          constant array in this routine.
*
*                       For example: If USERD_get_number_of_timesets
*                                    returns 2, the valid timeset_numbers 
 *                                    would be 1 or 2 to get the number of timesteps
*                                    or -1 or -2 to update the number of timesteps
*                                    for timestep 1 or 2.  
 * 
 *--------------------------------------------------------------------*/


4.5.2.16. USERD_get_max_time_steps

/*--------------------------------------------------------------------
* USERD_get_max_time_steps -
*--------------------------------------------------------------------
*
* Get the max number of time steps for a changing timestep model.
* You must use this routine if you want EnSight to consider a growing
* number of timesteps.
*
* So its presence, and a maximum greater than 1 is needed to flag EnSight
* to actuall do a rereading of the timesteps when prompted to do so.
*
* returns: max number of time steps
*--------------------------------------------------------------------*/
int
USERD_get_max_time_steps( void )

4.5.2.17. USERD_get_sol_times

/* -----------------------------------------------
USERD_get_sol_times

 *-------------------------------------------------------------------- 
 * 
 *   Get the solution times associated with each time step. 
 * 
 *  (IN)  handle             = The USERDHandle pointer
 *                             created in USERD_reader_open
 *
 *        timeset_number     = the timeset number
 *
 *                             For example: If USERD_get_number_of_timesets
 *                                          returns 2, the valid
 *                                          timeset_number's would be 1 and 2.
 *
 *  (OUT) solution_times     = 1D array of solution times per time step 
 * 
 *                                  (Array will have been allocated 
 *                                   Num_time_steps[timeset_number] long) 
 * 
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *  * These must be non-negative and increasing. 
 *--------------------------------------------------------------------*/ 



4.5.2.18. USERD_get_geom_timeset_number

/* -----------------------------------------------
USERD_get_geom_timeset_number

 *--------------------------------------------------------------------
 *
 *  Gets the timeset number to be used for geoemtry
 *
 *  It must be in the valid range of timeset numbers
 *       For example,  If USERD_get_number_of_timesets
 *                     returns 2, the valid timeset_number's
 *                     would be 1 and 2.
 *
 *  (IN)  handle         = The USERDHandle pointer
 *                         created in USERD_reader_open
 *
 *  Notes:
 *  * If your model is static, which you indicated by returning a zero
 *    in USERD_get_number_of_timesets, you can return a zero here as well.
 *--------------------------------------------------------------------*/



4.5.2.19. USERD_get_uns_failed_params

* API 3.0 and later
*--------------------------------------------------------------------
*
* Provides the failure variable and and failure/filter criteria 
*  for failed/filtered elements. Return TRUE from this function 
*  and every element whose elemental variable value meets the
*  specified criteria is removed from being used in EnSight for
*  calculation of all values and from visualization.
*
* (IN) handle                 = The USERDHandle pointer
*                               created in USERD_reader_open
*
* (OUT) fail_var_name         = Variable name to be used for failure.
*                               NOTE: Must be a per-elem scalar!
*
* (OUT) threshold_val1        = 1st number for failure comparison
*                               Always used in the determination.
*                               If threshold_operator1 is Z_ELE_FAILED_EQUAL,
*                               then only this threshold value is used.
*
* (OUT) threshold_val2        = 2nd number for failure comparison
*                               Will be used if threshold_operator1 is not
*                               set to Z_ELE_FAILED_EQUAL and logic_criteria2 is set to
*                                 Z_ELE_FAILED_LOGIC_AND or
*                                 Z_ELE_FAILED_LOGIC_OR
*
* (OUT) threshold_operator1   = 1st threshold operator
*                                 Z_ELE_FAILED_GREATER - greater than
*                                 Z_ELE_FAILED_LESS - less than
*                                 Z_ELE_FAILED_EQUAL - equal
*                                 Z_ELE_FAILED_NOT_EQUAL - not equal
*                               Sets the logic for use of threshold_val1
*
* (OUT) threshold_operator2   = 2nd threshold operator
*                                 Z_ELE_FAILED_GREATER - greater than
*                                 Z_ELE_FAILED_LESS - less than
*                                 Z_ELE_FAILED_EQUAL - equal
*                                 Z_ELE_FAILED_NOT_EQUAL - not equal
*                               Used if logic_criteria2 is set to
*                                 Z_ELE_FAILED_LOGIC_AND or
*                                 Z_ELE_FAILED_LOGIC_OR
*                               Sets the loginc for use of threshold_val2
*
* (OUT) logic_criteria2       = Determines if using second criteria and if it is an and or or condition
*                                 Z_ELE_FAILED_LOGIC_NONE
*                                 Z_ELE_FAILED_LOGIC_AND
*                                 Z_ELE_FAILED_LOGIC_OR
*
* returns: TRUE if failed elements should be used
*          FALSE if not using failed elements
*
* Notes:
*
*   Example 1:
*     If variable "failure" is an element scalar that has values which
*       are either 0.0 (for not-failed) or 1.0 (for failed), then:
*         fail_var_name = "failure"
*         threshold_val1 = 1.0
*         threshold_operator1 = Z_ELE_FAILED_EQUAL
*           **rest is ignored**
*
*
*
*   Example 2:
*     If variable "Stress" is an element scalar, and failure occurs
*       when the stress exceeds 3000.0
*         fail_var_name = "Stress"
*         threshold_val1 = 3000.0
*         threshold_operator1 = Z_ELE_FAILED_GREATER
*         logic_criteria2 = Z_ELE_FAILED_LOGIC_NONE
*
*   Example 3:
*     If variable "Stress" is an element scalar, and failure occurs
*       when the value is less than -500, or greater than 400
*         fail_var_name = "Stress"
*         threshold_val1 = -500.0
*         threshold_operator1 = Z_ELE_FAILED_LESS
*         threshold_val2 = 400.0
*         threshold_operator2 = Z_ELE_FAILED_GREATER
*         logic_criteria2 = Z_ELE_FAILED_LOGIC_OR
*-------------------------------------------------------------------*/
int USERD_get_uns_failed_params(char *fail_var_name,
                                float *threshold_val1,
                                float *threshold_val2,
                                int *threshold_operator1,
                                int *threshold_operator2,
                                int *logic_criteria2)

4.5.2.20. USERD_set_filenames

/* -----------------------------------------------
USERD_set_filenames

 *--------------------------------------------------------------------
 *
 *   Receives the geometry and result filenames entered in the data
 *   dialog.  The user written code will have to store and use these
 *   as needed.  The user written code must manage its own files!!
 *
 *  (IN)  handle      = The USERDHandle pointer
 *                      created in USERD_reader_open
 *
 *       filename_1   = the filename entered into the geometry
 *                         field of the data dialog.
 *       filename_2   = the filename entered into the result
 *                         field of the data dialog.
 *                         (If the two_fields flag in USERD_get_name_of_reader
 *                          is FALSE, this will be null string)
 *       the_path     = the path info from the data dialog.
 *                      Note: filename_1 and filename_2 have already
 *                            had the path prepended to them.  This
 *                            is provided in case it is needed for
 *                            filenames contained in one of the files
 *       swapbytes    = TRUE if should swap bytes when reading data.
 *                    = FALSE normally
 *
 *
 *  returns: Z_OK  if successful
 *           Z_ERR if not successful
 *
 *  Notes:
 *  * Since you must manage everything from the input that is entered in
 *    these data dialog fields, this is an important routine!
 *
 *  * Since you manage these files, they can be whatever.  Perhaps
 *    you will use only one, and have references to everything else
 *    you need within it, like EnSight's case file does.
 *
 *  * This is also the typical place to utilize other things in the
 *    handle.  Such as the server number, extra GUI user repsonses, etc.
 *--------------------------------------------------------------------*/


4.5.2.21. USERD_set_time_set_and_step

/* -----------------------------------------------
USERD_set_time_set_and_step
 *--------------------------------------------------------------------
 *
 *   Set the current time step in the desired timeset.  All functions that
 *   need time, and that do not explicitly pass it in, will use the timeset
 *   and step set by this routine, if needed.
 *
 *  (IN)  handle         = The USERDHandle pointer
 *                         created in USERD_reader_open
 *
 *       timeset_number  = the timeset number (1 based).
 *
 *                         For example:  If USERD_get_number_of_timesets
 *                                       returns 2, the valid timeset_number's
 *                                       would be 1 and 2.
 *
 *       time_step       = The current time step
 *
 *  Notes:
 *  * Current_time_step and Current_timeset would be set here
 *--------------------------------------------------------------------*/





4.5.2.22. USERD_get_number_of_model_parts

/* -----------------------------------------------
USERD_get_number_of_model_parts

 *------------------------------------------------------------------- 
 * 
 *   Gets the total number of unstructured and structured parts 
 *   in the model, for which you can supply information. 
 *
 *   This value is typically called:  Numparts_available
 * 
 *  (IN)  handle         = The USERDHandle pointer
 *                         created in USERD_reader_open
 *
 *  returns:  Numparts_available  (>0 if okay, <=0 if probs) 
 * 
 *  Notes: 
 *  * IMPORTANT!!  The part or block numbers that get passed to various
 *                 routines in this API, will be the one-based table index
 *                 of these parts.
 *
 *                 For example, if you have three parts, the part or block
 *                 numbers of these parts will be:  1,2,3
 *
 *  * If going to have to read down through the parts in order to 
 *    know how many, you may want to build a table of pointers to 
 *    the various parts, so can easily get to particular parts in 
 *    later processes.  If you can simply read the number of parts 
 *    at the head of the file, then you would probably not build the 
 *    table at this time. 
 *-------------------------------------------------------------------*/



4.5.2.23. USERD_get_part_info

/*--------------------------------------------------------------------
* USERD_get_part_info - 
 *-------------------------------------------------------------------- 
 * 
 *   Retrieve the information and metadata for a given part 
 * 
 *  (IN)  handle                 = The USERDHandle pointer
*                                 created in USERD_reader_open
*
*        part_index             = zero-based part index
*
*  (OUT) part_id                = the external part id for the model part. 
 * 
 *                                 IMPORTANT: 
 *                                  External Part ids must be >= 1 because
*                                  of the way they are used in the GUI 
  *
*                                 WARNING:
*                                  EnSight dimensions the part_id array from
*                                  1 to the maximum part_id. For optimization,
*                                  please make the part_id from 1 to the number
*                                  of parts. If your three part_ids are 4, 7,
*                                  and 7000000, then EnSight will make an array
*                                  of size 7000000 and the slowdown can be dramatic.
*                                  DO NOT use part ID labels that you have read 
 *                                  from your dataset, because these can be unpredictable.
*                               
 *
*
* 
 *             ******************************************* 
 *              The ids provided here are the numbers by 
 *              which the parts will be referred to in the 
 *              GUI (if possible) and are 1-Number of parts. 
 *
*              example:  If Numparts_available = 3
*                        
 *                        part index        part_id
*                        -----------        -------
*                         0                  1
*                         1                  2
*                         2                  3
*
*                         ^                   ^
*                         |                   |
*                         |                    These are placed in:
*                         |                      part_id[0] = 1
*                         |                      part_id[1] = 2
*                         |                      part_id[2] = 3
*                         |                    for GUI labeling purposes.
*                         |
*
*             ******************************************** 
 * 
 *        part_description       = Array containing a description for the model part 
 * 
 *                                  (Array will have been allocated Z_BUFL long) 
 *
*        number_of_geoms        = number of geoms in the part
*
*        has_border_geom        = TRUE if a border geom will be provided for this part
*                                 by the reader.
*
*        border_geom_index      = The zero-based geom index which is the border for this
*                                 part, if provided - as indicated by previous argument. 
 * 
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *  * If you haven't built a table of pointers to the different parts, 
 *    you might want to do so here as you gather the needed info. 
 * 
 *  * This will be based on hdl->current_time_step
 *--------------------------------------------------------------------*/ 
int 
USERD_get_part_info(USERDHandle handle,
                    int part_index,
                    int *part_id,
                    char part_description[Z_BUFL],
                    int *number_of_geoms,
                    int *has_border_geom,
                    int *border_geom_index)

4.5.2.24. USERD_get_geoms_in_part

/* -----------------------------------------------
USERD_get_geoms_in_part

 *-------------------------------------------------------------------- 
 *
 *  Retrieve the list of geoms in a given part
 *
 *  (IN)  handle         = The USERDHandle pointer
 *                         created in USERD_reader_open
 *
 *        part_index     = zero-based part index
 *
 *  (OUT) geoms          = Pointer to list of geoms in the part
 *                         (Length is the number_of_geoms returned in
 *                          USERD_get_part_info)
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *--------------------------------------------------------------------*/ 
int
USERD_get_geoms_in_part(USERDHandle handle,
                        int part_index,
                        int *geoms)
{
  int i;
  int ierr = Z_OK;
  EnSightRdrHandle *hdl = (EnSightRdrHandle *)handle;

  if(hdl->server.iVerboseLevel == Z_FULL) {
    fprintf(stderr,"  > For part_index: %d\n",part_index);
  }

  /* For now, we simply have a single geom per part
   *-----------------------------------------------*/
  for(i=0; i<Num_Geoms_in_Part[part_index]; ++i) {
    geoms[i] = Geoms_in_Part[part_index][i];

    if(hdl->server.iVerboseLevel == Z_FULL) {
      fprintf(stderr,"    > geoms[%d]          = %d\n",i,Geoms_in_Part[part_index][i]);
    }
  }


  return(ierr);
}



4.5.2.25. USERD_get_geom_info

/* -----------------------------------------------
USERD_get_geom_info

 *-------------------------------------------------------------------- 
 *
 *  Retrieve the information for a given geom
 *
 *  (IN)  handle             = The USERDHandle pointer
 *                             created in USERD_reader_open
 *
 *        geom_index         = zero-based geom index
 *
 *  (OUT) geom_type          = Z_UNSTRUCTURED,
 *                             Z_STRUCTURED, or
 *                             Z_IBLANKED
 *
 *        nodeset_index      = zero-based nodeset index used by the geom
 *
 *        number_of_elemsets = the list of elemsets in the geom
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *--------------------------------------------------------------------*/ 
int
USERD_get_geom_info(USERDHandle handle,
                    int geom_index,
                    int *geom_type,
                    int *nodeset_index,
                    int *number_of_elemsets)



4.5.2.26. USERD_get_elemsets_in_geom

/*--------------------------------------------------------------------
* USERD_get_elemsets_in_geom
*-------------------------------------------------------------------- 
 *
*  Retrieve the list of elemset indicies (zero-based) in a given geom
*
*  (IN)  handle              = The USERDHandle pointer
*                              created in USERD_reader_open
*
*        geom_index          = zero-based geom index
*
*  (OUT) elemset_index_array = Pointer to the list of elemset indicies in the geom
*                              (Length of the array is number_of_elemsets
*                               returned in USERD_get_geom_info)
*
*  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: In a subsequent call, these element indicies in the elemset_index_array
*    will be supplied to  USERD_get_uelem_info in order to get the details
*    including the number of elements and their type.
*--------------------------------------------------------------------*/ 
int
USERD_get_elemsets_in_geom(USERDHandle handle,
                           int geom_index,
                           int *elemset_index_array)

4.5.2.27. USERD_get_unode_info

/* -----------------------------------------------
USERD_get_unode_info

 *-------------------------------------------------------------------- 
 *
 *  Retrieve the information for a given unstructured nodeset
 *
 *  (IN)  handle                = The USERDHandle pointer
 *                                created in USERD_reader_open
 *
 *        nodeset_index         = zero-based nodeset index
 *
 *  (OUT) number_of_nodes       = number of nodes in the nodeset
 *
 *        interleave_flag       = TRUE if nodes come xyzxyz... and will be accessed
 *                                     all at once.
 *                              = FALSE if nodes will be accessed by component,
 *                                      thus, they are usually arranged xxxx...yyyy...zzzz
 *                                      or separately by components.
 *
 *        coords_changing_flag  = TRUE if number of nodes can vary over time,
 *                                FALSE if number of nodes stay constant over time.
 *
 *        num_node_variables    = the number of nodal variables available per node.
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *--------------------------------------------------------------------*/ 
int
USERD_get_unode_info(USERDHandle handle,
                     int nodeset_index,
                     int *number_of_nodes,
                     int *interleave_flag,
                     int *coords_changing_flag,
                     int *num_node_variables)




4.5.2.28. USERD_get_snode_info

/* -----------------------------------------------
USERD_get_snode_info

 *--------------------------------------------------------------------
 *
 *  Retrieve the information for a given structured nodeset
 *
 *  (IN)  handle             = The USERDHandle pointer
 *                             created in USERD_reader_open
 *
 *        nodeset_index      = zero-based nodeset index
 *
 *  (OUT) stype              = Z_CURVILINEAR,
 *                             Z_RECTILINEAR, or
 *                             Z_UNIFORM
 *
 *        ijk_dimensions     = [0] = number of i planes
 *                             [1] = number of j planes
 *                             [2] = number of k planes
 *
 *                             if full range for each, then:
 *                             [3] = -1;
 *
 *                             or if ranges to be used, then:
 *                             [3] = 1-based imin of portion
 *                             [4] = 1-based imax of portion
 *                             [5] = 1-based jmin of portion
 *                             [6] = 1-based jmax of portion
 *                             [7] = 1-based kmin of portion
 *                             [8] = 1-based kmax of portion
 *
 *                             example, if you wanted to specify full ranges yourself
 *                                      for a 2 x 4 x 3 block:
 *
 *                             You could specify:             or      just:
 *                               ijk_dimensions[0] = 2                  ijk_dimension[0] = 2
 *                               ijk_dimensions[1] = 4                  ijk_dimension[1] = 4
 *                               ijk_dimensions[2] = 3                  ijk_dimension[2] = 3
 *                               ijk_dimensions[3] = 1                  ijk_dimension[3] = -1
 *                               ijk_dimensions[4] = 2
 *                               ijk_dimensions[5] = 1
 *                               ijk_dimensions[6] = 4
 *                               ijk_dimensions[7] = 1
 *                               ijk_dimensions[8] = 3
 *
 *                             But,if you only wanted the k=2 slice, you could specify: 
 *                               ijk_dimensions[0] = 2
 *                               ijk_dimensions[1] = 4
 *                               ijk_dimensions[2] = 3
 *                               ijk_dimensions[3] = 1
 *                               ijk_dimensions[4] = 2
 *                               ijk_dimensions[5] = 1
 *                               ijk_dimensions[6] = 4
 *                               ijk_dimensions[7] = 2
 *                               ijk_dimensions[8] = 2
 *
 *        interleave_flag       = TRUE if nodes come xyzxyz... and will be accessed
 *                                     all at once.
 *                              = FALSE if nodes will be accessed by component,
 *                                      thus, they are usually arranged xxxx...yyyy...zzzz
 *                                      or separately by components.
 *
 *        coords_changing_flag  = TRUE if number of nodes can vary over time,
 *                                FALSE if number of nodes stay constant over time.
 *
 *        iblanking_options     = [Z_EXT]    = TRUE if some Exterior iblanked nodes
 *                                [Z_INT]    = TRUE if some Interior iblanked nodes
 *                                [Z_BND]    = TRUE if some Boundary iblanked nodes
 *                                [Z_INTBND] = TRUE if some Internal Boundary/Baffle nodes
 *                                [Z_SYM]    = TRUE if some Symmetry surfaace nodes
 *
 *        num_node_variables    = the number of nodal variables available per node.
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *--------------------------------------------------------------------*/
int
USERD_get_snode_info(USERDHandle handle,
                     int nodeset_index,
                     int *stype,
                     int ijk_dimensions[9],
                     int *interleave_flag,
                     int *coords_changing_flag,
                     int iblanking_options[6],
                     int *num_node_variables)



4.5.2.29. USERD_get_snode_iblanking

/* -----------------------------------------------
USERD_get_snode_iblanking

 *--------------------------------------------------------------------
 *
 *  Retrieve the iblanking values for the nodes in a given structured nodeset
 *
 *  (IN)  handle             = The USERDHandle pointer
 *                             created in USERD_reader_open
 *
 *        nodeset_index      = zero-based nodeset index
 *
 *  (OUT) iblanking_array    = Pointer to array of iblanking values per node.
 *                             Each node will have one of the following
 *                             iblank values:
 *                                 Z_EXT    exterior
 *                                 Z_INT    interior
 *                                 Z_BND    boundary
 *                                 Z_INTBND internal boundary/baffle
 *                                 Z_SYM    symmetry surface
 *
 *                              (Length of the array is the number of nodes in the nodeset.)
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *  * Only called if geom_type returned from USERD_get_geom_info is Z_IBLANKED
 *----------------------------------------------------------------------------*/
int
USERD_get_snode_iblanking(USERDHandle handle,
                          int nodeset_index,
                          int *iblanking_array)



4.5.2.30. USERD_get_node_coords

/* -----------------------------------------------
USERD_get_node_coords

 *-------------------------------------------------------------------- 
 *
 *  Retrieve the coordinates for the nodes in a given nodeset
 *
 *  (IN)  handle             = The USERDHandle pointer
 *                             created in USERD_reader_open
 *
 *        nodeset_index      = zero-based nodeset index
 *
 *  (OUT) coord_array_compx  = Pointer to array of x components of coordinates if
 *                             interleave_flag is FALSE in USERD_get_unode_info or
 *                                                         USERD_get_snode_info
 *
 *                             Pointer to entire coordinate array if
 *                             interleave_flag is TRUE in USERD_get_unode_info or
 *                                                        USERD_get_snode_info
 *
 *        coord_array_compy  = Pointer to array of y components of coordinates if
 *                             interleave_flag is FALSE in USERD_get_unode_info or
 *                                                         USERD_get_snode_info
 *
 *        coord_array_compz  = Pointer to array of z components of coordinates
 *                             interleave_flag is FALSE in USERD_get_unode_info or
 *                                                         USERD_get_snode_info
 *              So, if doing interleaved:
 *                  only pointer to coord_array_compx is used.  And you should load it
 *                  in an xyzxyzxyz... fashion.  (Length of array will be 3 x number of nodes
 *                                                in the nodeset.)
 *
 *               But, if not doing interleaved:
 *                  all three pointers are used.
 *                    coord_array_compx = xxxx...
 *                    coord_array_compy = yyyy...
 *                    coord_array_compz = zzzz...
 *                    (Each is the number of nodes in the nodeset long.)
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *   * Having the three pointers (and the interleave flag) is intended to
 *     give you flexibility in providing the data - hopefully without having
 *     to use any temporary arrays.
 *---------------------------------------------------------------------------*/ 
int
USERD_get_node_coords(USERDHandle handle,
                      int nodeset_index,
                      float *coord_array_compx,
                      float *coord_array_compy,
                      float *coord_array_compz)



4.5.2.31. USERD_get_node_ids

/* -----------------------------------------------
USERD_get_node_ids

 *-------------------------------------------------------------------- 
 *
 * Retrieve the node ids for nodes in a given nodeset
 *
 *  (IN)  handle             = The USERDHandle pointer
 *                             created in USERD_reader_open
 *
 *        nodeset_index      = zero-based nodeset index
 *
 *  (OUT) node_id_array      = Pointer to array of node ids.
 *                             (Length will be number of nodes in the nodeset)
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *   * Will only be called if the USERD_get_node_label_status specifies
 *     that node labels will be provided for the model.
 *--------------------------------------------------------------------*/ 
int
USERD_get_node_ids(USERDHandle handle,
                   int nodeset_index,
                   int *node_id_array)




4.5.2.32. USERD_get_uelem_info

/* -----------------------------------------------
USERD_get_uelem_info

 *-------------------------------------------------------------------- 
 *
 * Retrieve information for a given unstructured elemset
 *
 *  (IN)  handle                = The USERDHandle pointer
 *                                created in USERD_reader_open
 *
 *        elemset_index         = zero-based elemset index
 *
 *  (OUT) number_of_elements    = number of elements in the elemset
 *
 *        etype                 = One of the following (See global_extern.h)
 *                                  Z_POINT      node point element
 *                                  Z_G_POINT    node point ghost element
 *                                  Z_BAR02      2 node bar
 *                                  Z_G_BAR02    2 node ghost bar
 *                                  Z_BAR03      3 node bar
 *                                  Z_G_BAR03    3 node ghost bar
 *                                  Z_TRI03      3 node triangle
 *                                  Z_G_TRI03    3 node ghost triangle
 *                                  Z_TRI06      6 node triangle
 *                                  Z_G_TRI06    6 node ghost triangle
 *                                  Z_QUA04      4 node quad
 *                                  Z_G_QUA04    4 node ghost quad
 *                                  Z_QUA08      8 node quad
 *                                  Z_G_QUA08    8 node ghost quad
 *                                  Z_TET04      4 node tetrahedron
 *                                  Z_G_TET04    4 node ghost tetrahedron
 *                                  Z_TET10     10 node tetrahedron
 *                                  Z_G_TET10   10 node ghost tetrahedron
 *                                  Z_PYR05      5 node pyramid
 *                                  Z_G_PYR05    5 node ghost pyramid
 *                                  Z_PYR13     13 node pyramid
 *                                  Z_G_PYR13   13 node ghost pyramid
 *                                  Z_PEN06      6 node pentahedron
 *                                  Z_G_PEN06    6 node ghost pentahedron
 *                                  Z_PEN15     15 node pentahedron
 *                                  Z_G_PEN15   15 node ghost pentahedron
 *                                  Z_HEX08      8 node hexahedron
 *                                  Z_G_HEX08    8 node ghost hexahedron
 *                                  Z_HEX20     20 node hexahedron
 *                                  Z_G_HEX20   20 node ghost hexahedron
 *                                  Z_NSIDED    nsided polygon
 *                                  Z_G_NSIDED  nsided ghost polygon
 *                                  Z_NFACED    nfaced polyhedron
 *                                  Z_G_NFACED  nfaced ghost polyhedron
 *
 *        contents_index_mode   = BY_INDEX_0  if conn_array in USERD_get_uelem_conn will
 *                                            contain zero-based node indicies.
 *
 *                                BY_INDEX_1  if conn_array in USERD_get_uelem_conn will
 *                                            contain one-based node indicies
 *
 *                                BY_ID       id conn_array in USERD_get_uelem_conn will
 *                                            contain node ids.
 *
 *        conn_changing_flag    = TRUE if element connectivities can vary over time,
 *                                FALSE if element connectivities will stay constant over time.
 *
 *        transient_var_flag    = TRUE if element variables change over time
 *                              = FALSE if element variables are static
 *
 *        num_elem_variables    = the number of elem variables available per element.
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *--------------------------------------------------------------------*/ 
int
USERD_get_uelem_info(USERDHandle handle,
                     int elemset_index,
                     int *number_of_elements,
                     int *etype,
                     int *contents_index_mode,
                     int *conn_changing_flag,
                     int *transient_var_flag,
                     int *num_elem_variables)



4.5.2.33. USERD_get_uelem_faces_per_elem

if any NFACED or NSIDED elems

/* -----------------------------------------------
USERD_get_uelem_faces_per_elem

 *-------------------------------------------------------------------- 
 *
 *  Retrieve the list of the number of faces per element for a given
 *  unstructured elemset. 
 *
 *  (IN)  handle                = The USERDHandle pointer
 *                                created in USERD_reader_open
 *
 *        elemset_index         = zero-based elemset index
 *
 *  (OUT) fpe                   = Pointer to an array containing the number of faces
 *                                per element.
 *                                  If called for:
 *                                     regular elements or
 *                                     nsided elements (which isn't needed),
 *                                       it will be of length 1, so return a fpe[0] = 1; 
 *
 *                                     nfaced elements (which is needed), it will be of
 *                                        length number of elems in the elemset. Return
 *                                        the number of faces per element.
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *--------------------------------------------------------------------*/ 
int
USERD_get_uelem_faces_per_elem(USERDHandle handle,
                               int elemset_index,
                               int *fpe)




4.5.2.34. USERD_get_uelem_nodes_per_face

if any NFACED or NSIDED elems

/* -----------------------------------------------
USERD_get_uelem_nodes_per_face

 *-------------------------------------------------------------------- 
 *
 *  Retrieves the list of number of nodes per face for a given elemset
 *
 *  (IN)  handle                = The USERDHandle pointer
 *                                created in USERD_reader_open
 *
 *        elemset_index         = zero-based elemset index
 *
 *  (OUT) npf                   = Pointer to an array containing the number of nodes
 *                                per face for each face of each element in the elemset.
 *                                  If called for:
 *                                     regular elements (which isn't needed), it will be of
 *                                       lenght 1, so return npf[0] = conlength.
 *
 *                                     nsided elements (which is needed),
 *                                       it will be of length number of elements in elemset.
 *                                       Return with the number of nodes per each element.
 *
 *                                     nfaced elements (which is needed), it will be of
 *                                        length total number of faces in the elemset. Which
 *                                        has to be summed up from the fpe array called in
 *                                        USERD_get_uelem_faces_per_elem.  Return
 *                                        the number of nodes for each of these faces.
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *--------------------------------------------------------------------*/ 
int
USERD_get_uelem_nodes_per_face(USERDHandle handle,
                               int elemset_index,
                               int *npf)




4.5.2.35. USERD_get_uelem_conn

/* -----------------------------------------------
USERD_get_uelem_conn

 *-------------------------------------------------------------------- 
 *
 * Retrieves the unstructured connectivites for a given elemset
 *
 *  (IN)  handle                = The USERDHandle pointer
 *                                created in USERD_reader_open
 *
 *        elemset_index         = zero-based elemset index
 *
 *  (OUT) conn_array            = Pointer to an array containing the connectivities
 *                                of the elements in the elemset.  One right after the other.
 *                                So length will be:
 *                                  regular elements:   number of elems in elemset * conlength
 *                                  nsided elements:  summation of contents of npf_array
 *                                                    from a call to USERD_get_uelem_nodes_per_face.
 *                                                    (The npf_array will be # of elements long)
 *                                  nfaced elements: summation of contents of npf_array, from a
 *                                                   call to USERD_get_uelem_nodes_per_face.
 *                                                   (The npf_array will be total number of faces
 *                                                    long.  Which was determined by a summation
 *                                                    of the fpe_array, from a call to
 *                                                    USERD_get_uelem_faces_per_elem)
 *                                  Examples:
 *                                  1. If elemset is composed of quad4's, then conn_array will be:
 *                                        conn_array[0] = q1n1     (quad 1, node 1)
 *                                        conn_array[1] = q1n2     (quad 1, node 2)
 *                                        conn_array[2] = q1n3          etc.
 *                                        conn_array[3] = q1n4
 *
 *                                        conn_array[4] = q2n1     (quad 2, node 1)
 *                                        conn_array[5] = q2n2          etc.
 *                                        conn_array[6] = q2n3
 *                                        conn_array[7] = q2n4
 *
 *                                        conn_array[8] = q3n1
 *                                        conn_array[9] = q3n2
 *                                                etc.
 *
 *                                   2. If elemset is composed of 3 nsided elements
 *                                        first is 5 nodes long, second is 7 nodes long, and
 *                                        third is 6 nodes long:
 *                                        conn_array[0]  = ns1n1     (nsided 1, node 1)
 *                                        conn_array[1]  = ns1n2     (nsided 1, node 2)
 *                                        conn_array[2]  = ns1n3          etc.
 *                                        conn_array[3]  = ns1n4
 *                                        conn_array[4]  = ns1n5
 *
 *                                        conn_array[5]  = ns2n1     (nsided 2, node 1)
 *                                        conn_array[6]  = ns2n2          etc.
 *                                        conn_array[7]  = ns2n3
 *                                        conn_array[8]  = ns2n4
 *                                        conn_array[9]  = ns2n5
 *                                        conn_array[10] = ns2n6
 *                                        conn_array[11] = ns2n7
 *
 *                                        conn_array[12] = ns3n1
 *                                        conn_array[13] = ns3n2
 *                                        conn_array[14] = ns3n3
 *                                        conn_array[15] = ns3n4
 *                                        conn_array[16] = ns3n5
 *                                        conn_array[17] = ns3n6
 *
 *                                   3. If elemset is composed of nfaced elements
 *                                        conn_array[0]  = nf1f1n1   (nfaced 1, face 1, node 1)
 *                                        conn_array[1]  = nf1f1n2   (nfaced 1, face 1, node 2)
 *                                        conn_array[2]  = nf1f1n3   (nfaced 1, face 1, node 3)
 *                                        conn_array[3]  = nf1f2n1   (nfaced 1, face 2, node 1)
 *                                        conn_array[4]  = nf1f2n2   (nfaced 1, face 2, node 2)
 *                                        conn_array[5]  = nf1f2n3   (nfaced 1, face 2, node 3)
 *                                        conn_array[6]  = nf1f2n4   (nfaced 1, face 2, node 4)
 *                                        conn_array[7]  = nf1f2n5   (nfaced 1, face 2, node 5)
 *                                        conn_array[8]  = nf1f3n1   (nfaced 1, face 3, node 1)
 *                                        conn_array[9]  = nf1f3n2   (nfaced 1, face 3, node 2)
 *                                        conn_array[10] = nf1f3n3   (nfaced 1, face 3, node 3)
 *                                        conn_array[11] = nf1f3n4   (nfaced 1, face 3, node 4)
 *
 *                                        conn_array[12] = nf2f1n1   (nfaced 2, face 1, node 1)
 *                                        conn_array[13] = nf1f1n1   (nfaced 2, face 1, node 2)
 *                                                       etc.
 *                                                       etc.
 *                                                       etc.
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *--------------------------------------------------------------------*/ 
int
USERD_get_uelem_conn(USERDHandle handle,
                     int elemset_index,
                     int *conn_array)



4.5.2.36. USERD_get_selem_info

/* -----------------------------------------------
USERD_get_selem_info

 *--------------------------------------------------------------------
 *
 *  Retrieves information  for a given structured elemset
 *
 *  (IN)  handle             = The USERDHandle pointer
 *                             created in USERD_reader_open
 *
 *        elemset_index      = zero-based elemset index
 *
 *  (OUT) stype              = Z_CURVILINEAR,
 *                             Z_RECTILINEAR, or
 *                             Z_UNIFORM
 *
 *        ijk_dimensions     = [0] = number of i planes
 *                             [1] = number of j planes
 *                             [2] = number of k planes
 *
 *                             if full range for each, then:
 *                             [3] = -1;
 *
 *                             or if ranges to be used, then:
 *                             [3] = 1-based imin of portion
 *                             [4] = 1-based imax of portion
 *                             [5] = 1-based jmin of portion
 *                             [6] = 1-based jmax of portion
 *                             [7] = 1-based kmin of portion
 *                             [8] = 1-based kmax of portion
 *
 *                             example, if you wanted to specify full ranges yourself
 *                                      for a 2 x 4 x 3 block:
 *
 *                             You could specify:             or      just:
 *                               ijk_dimensions[0] = 2                  ijk_dimension[0] = 2
 *                               ijk_dimensions[1] = 4                  ijk_dimension[1] = 4
 *                               ijk_dimensions[2] = 3                  ijk_dimension[2] = 3
 *                               ijk_dimensions[3] = 1                  ijk_dimension[3] = -1
 *                               ijk_dimensions[4] = 2
 *                               ijk_dimensions[5] = 1
 *                               ijk_dimensions[6] = 4
 *                               ijk_dimensions[7] = 1
 *                               ijk_dimensions[8] = 3
 *
 *                             But,if you only wanted the k=2 slice, you could specify: 
 *                               ijk_dimensions[0] = 2
 *                               ijk_dimensions[1] = 4
 *                               ijk_dimensions[2] = 3
 *                               ijk_dimensions[3] = 1
 *                               ijk_dimensions[4] = 2
 *                               ijk_dimensions[5] = 1
 *                               ijk_dimensions[6] = 4
 *                               ijk_dimensions[7] = 2
 *                               ijk_dimensions[8] = 2
 *
 *        conn_changing_flag   = TRUE if element connectivities can vary over time,
 *                                FALSE if element connectivities stay constant over time.
 *
 *        ghost_flag           = TRUE if ghost values are to be assigned to the elements.
 *                               FALSE if no ghost values to be considered.
 *
 *        transient_var_flag   = TRUE if element variables will vary over time.
 *                             = FALSE, if element variables are static
 *
 *        num_elem_variables   = the number of elem variables available per element.
 *
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *--------------------------------------------------------------------*/
int
USERD_get_selem_info(USERDHandle handle,
                     int elemset_index,
                     int *stype,
                     int ijk_dimensions[9],
                     int *conn_changing_flag,
                     int *ghost_flag,
                     int *transient_var_flag,
                     int *num_elem_variables)



4.5.2.37. USERD_get_selem_ghost_flags

/* -----------------------------------------------
USERD_get_selem_ghost_flags

 *--------------------------------------------------------------------
 *
 *  Retrieves the ghost flag for the elements in a given structured elemset
 *
 *  (IN)  handle             = The USERDHandle pointer
 *                             created in USERD_reader_open
 *
 *        elemset_index      = zero-based elemset index
 *
 *  (OUT) ghost_flag_array   = Pointer to ghost flag array per element.
 *                             0 if not a ghost (a regular element)
 *                             1 if a ghost element
 *                             (Length of array will be number of elements in elemset)
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes:
 *   * Will not be called unless the ghost_flag is TRUE from a call to
 *     USERD_get_selem_info 
 *--------------------------------------------------------------------*/
int
USERD_get_selem_ghost_flags(USERDHandle handle,
                            int elemset_index,
                            int *ghost_flag_array)



4.5.2.38. USERD_get_elem_ids

/* -----------------------------------------------
USERD_get_elem_ids

 *-------------------------------------------------------------------- 
 *
 *  Retrieves the element ids for the elements in a given elemset
 *
 *  (IN)  handle                = The USERDHandle pointer
 *                                created in USERD_reader_open
 *
 *        elemset_index         = zero-based elemset index
 *
 *  (OUT) elem_id_array         = Pointer to an array containing the element ids.
 *                                (Length of array will be number of elements in elemset)
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *--------------------------------------------------------------------*/ 
int
USERD_get_elem_ids(USERDHandle handle,
                   int elemset_index,
                   int *elem_id_array)


4.5.2.39. USERD_ get_num_xy_queries

/*--------------------------------------------------------------------
*
* (IN) handle         = The USERDHandle pointer
*                       created in USERD_reader_open
*
*   Get the total number of xy queries in the dataset.
*
*  returns: the total number of xy queries in the dataset
*
* Notes:
* 
*   *You can be as complete as you want about this. If you don't
*    care about xy queries, return a value of 0
*    If you only want certain xy queries, you can just include them. But,
*    you will need to supply the info and data USERD_get_xy_query_info
*    and USERD_get_xy_query_data for each xy query you include here.
*--------------------------------------------------------------------*/
int
USERD_get_num_xy_queries(USERDHandle handle)
/*--------------------------------------------------------------------

4.5.2.40. USERD_get_xy_query_info

/*----------------------------------------------------------------------------
*
*   Gets name, axis titles, and number of xy pairs for a particular xy_query
*
* (IN) handle             = The USERDHandle pointer
*                         created in USERD_reader_open
*
* (IN) query_num          = query number (zero based)
*                         (0 to one less than the number of querys
*                         returned in USERD_get_num_xy_queries)
*
* (OUT) query_name        = Name for the xy query. (80 chars long)
*
* (OUT) query_xtitle      = Title for x axis (80 chars long)
*
* (OUT) query_ytitle      = Title for y axis (80 chars long)
*
* (OUT) query_num_pairs   = number of xy pairs
*
* returns: Z_OK if successful
*          Z_ERR if a problem
*
* Notes:
*---------------------------------------------------------------------------*/
int USERD_get_xy_query_info(
USERDHandle handle,
          int query_num,
          char *query_name,
          char *query_xtitle,
          char *query_ytitle,
          int *query_num_pairs )

4.5.2.41. USERD_get_xy_query_data

/*-----------------------------------------------------------------------------
*
* Gets the xy values for a particular xy_query
*
* (IN) handle               = The USERDHandle pointer
*                              created in USERD_reader_open
*
* (IN)  query_num           = query number (zero based)
*                             (0 to one less than the number of queries
*                             returned in USERD_get_num_xy_queries)
*
* (IN) num_vals             = number of xy pairs in the query
*
* (OUT) xvals               = array of x values, dimensioned to num_vals (0 based)
*
* (OUT) yvals               = array of y values, dimensioned to num_vals (0 based)
*
* returns: Z_OK if successful
*          Z_ERR if a problem
*
* Notes:
*----------------------------------------------------------------------------*/
int USERD_get_xy_query_data(
USERDHandle handle,
          int query_num,
          int num_vals,
          float *xvals,
          float *yvals)

4.5.2.42. USERD_get_number_of_vars

/* -----------------------------------------------
USERD_get_number_of_vars

 *-------------------------------------------------------------------- 
 *
 * Retrieves the number of  non-constant vars in the model
 *
 *  (IN)  handle         = The USERDHandle pointer
 *                         created in USERD_reader_open
 *
 *  returns: number of non-constant vars in the model
 * 
 *  Notes: 
 *--------------------------------------------------------------------*/ 
int
USERD_get_number_of_vars(USERDHandle handle)
{
  EnSightRdrHandle *hdl = (EnSightRdrHandle *)handle;
  int num_vars;

  num_vars = 4;

  if(hdl->server.iVerboseLevel == Z_FULL) {
    fprintf(stderr,"  > Number of (non-constant) vars = %d\n",num_vars);
  }

  return(num_vars);
}



4.5.2.43. USERD_get_var_info

/* -----------------------------------------------
USERD_get_var_info

 *-------------------------------------------------------------------- 
 *
 *  Retrieves the information for a given var
 *
 *  (IN)  handle               = The USERDHandle pointer
 *                               created in USERD_reader_open
 *
 *        var_index            = The zero-based var_index
 *
 *  (OUT) var_description      = Pointer to description array
 *
 *                               (Array will have been allocated
 *                                Num_variables by Z_BUFL long)
 *
 *        var_type             = Variable type
 *                               types are:  Z_CONSTANT_PER_PART
 *                                           Z_SCALAR
 *                                           Z_VECTOR
 *                                           Z_TENSOR
 *                                           Z_TENSOR9
 *
 *        var_classify         = Variable classification
 *                               types are:  Z_PER_NODE
 *                                           Z_PER_ELEM
 *
 *        var_complex          = Complex flag
 *                               Set to TRUE if complex, FALSE otherwise
 *
 *        var_freq             = Complex frequency  (if complex)
 *
 *        var_timeset          = Timeset the variable will use (1 based).
 *                               (For static models, set it to 1)
 *
 *                              For example:  If USERD_get_number_of_timesets
 *                                            returns 2, the valid
 *                                            timeset_number's would be 1 or 2.
 *
 *        interleave_flag       = TRUE if values come xyzxyz... and will be accessed
 *                                     all at once.
 *                              = FALSE if values will be accessed by component,
 *                                      thus, they are usually arranged xxxx...yyyy...zzzz
 *                                      or separately by components.
 *
 *  returns: Z_OK  if successful
 *           Z_ERR if not successful
 *
 * Notes:
 *  1. interleave_flag is currently constrained in the API to be a
 *     variable-wide attribute.  In other words, we don't allow the same
 *     variable to be interleaved for some geoms,but non-interleaved for
 *     others.  (This is mainly due to the way Ensight handles variables -
 *     so it could be changed if we want to. It will just make EnSight
 *     do more work to determine how large to make vbuf)
 *  
 *--------------------------------------------------------------------*/ 
int
USERD_get_var_info(USERDHandle handle,
                   int var_index,
                   char *var_description,
                   int *var_type,
                   int *var_classify,
                   int *var_complex,
                   float *var_freq,
                   int *var_timeset,
                   int *interleave_flag)




4.5.2.44. USERD_get_node_var_info

/* -----------------------------------------------
USERD_get_node_var_info

 *-------------------------------------------------------------------- 
 *
 *  Retrieves the var_index associated with and the and the number of values
 *  from the given nodeset var
 *
 *  (IN)  handle             = The USERDHandle pointer
 *                             created in USERD_reader_open
 *
 *        nodeset_index      = zero-based nodeset index
 *
 *        node_var_index     = zero-based local var index for the nodeset
 *
 *  (OUT) var_index          = zero-based var index
 *
 *        number_of_values   = The number of nodes in the nodeset 
 *                             (This is kind of redundant with what you can
 *                              get from the nodeset info).
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 * Notes:
 * 1. number_of_values is the number of nodes.  It does not consider the
 *    number of components for the given variable type.
 *
 *    So for a nodeset containing 100 nodes, the number_of_values is 100 no
 *    matter whether the variable is a nodal scalar, vector, or tensor.
 *--------------------------------------------------------------------*/ 
int
USERD_get_node_var_info(USERDHandle handle,
                        int nodeset_index,
                        int node_var_index,
                        int *var_index,
                        int *number_of_values)




4.5.2.45. USERD_get_node_var_values

/* -----------------------------------------------
USERD_get_node_var_values

 *-------------------------------------------------------------------- 
 *
 *  Retrieves the variable values associated with a given nodeset var
 *
 *  (IN)  handle             = The USERDHandle pointer
 *                             created in USERD_reader_open
 *
 *        nodeset_index      = zero-based nodeset index
 *
 *        node_var_index     = zero-based local var index for the nodeset
 *
 *        comp               = variable component to retrieve if interleaved.
 *                             Otherwise is ignored and all values are obtained.
 *
 *  (OUT) values             = Pointer to values array.
 *                             Load with all values if interleaved.  Load with the
 *                             appropriate component if not interleaved.
 *                             (Length will either be the number of nodes long if
 *                              not interleaved, or will be the number of nodes times
 *                              the number of components for the type long.)
 *
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful
 *           Z_UNDEF if undefined. 
 * 
 * Notes:
 * 1. comp is ignored if the var is interleaved, otherwise it is used.
 *
 *    Thus, the calling programs should call this only once per nodeset
 *    for an interleaved variable, but should call it once per
 *    component for all other situations.  
 *--------------------------------------------------------------------*/ 
int
USERD_get_node_var_values(USERDHandle handle,
                          int nodeset_index,
                          int node_var_index,
                          int comp,
                          float *values)





4.5.2.46. USERD_get_elem_var_info

/* -----------------------------------------------
USERD_get_elem_var_info

 *-------------------------------------------------------------------- 
 *
 *  Retrieves the var_index associated with and the number of values
 *  from the given elemset var
 *
 *  (IN)  handle             = The USERDHandle pointer
 *                             created in USERD_reader_open
 *
 *        elemset_index      = zero-based elemset index
 *
 *        elem_var_index     = zero-based local var index for the elemset
 *
 *  (OUT) var_index          = zero-based var index
 *
 *        number_of_values   = The number of elements in the elemset 
 *                             (This is kind of redundant with what you can
 *                              get from the elemset info).
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 * Notes:
 * 1. number_of_values is the number of elements that have values in the
 *    elemset.  It does not consider the number of components for the given
 *    variable type.
 *
 *    So for an elemset containing 50 triangles, the number_of_values is 50 no
 *    matter whether the variable is a elemental scalar, vector, or tensor.
 *--------------------------------------------------------------------*/ 
int
USERD_get_elem_var_info(USERDHandle handle,
                        int elemset_index,
                        int elem_var_index,
                        int *var_index,
                        int *number_of_values)




4.5.2.47. USERD_get_elem_var_values

/* -----------------------------------------------
USERD_get_elem_var_values

 *-------------------------------------------------------------------- 
 *
 *  Retrieves the variable values associated with a given elemset var
 *
 *  (IN)  handle             = The USERDHandle pointer
 *                             created in USERD_reader_open
 *
 *        elemset_index      = zero-based elemset index
 *
 *        elem_var_index     = zero-based local var index for the elemset
 *
 *        comp               = variable component to retrieve if interleaved.
 *                             Otherwise is ignored and all values are obtained.
 *
 *  (OUT) values             = Pointer to values array.
 *                             Load with all values if interleaved.  Load with the
 *                             appropriate component if not interleaved.
 *                             (Length will either be the number of elements long if
 *                              not interleaved, or will be the number of elements times
 *                              the number of components for the type long.)
 *
 *
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 *           Z_UNDEF if undefined. 
 * 
 *
 * Notes:
 * 1. comp is ignored if the var is interleaved, otherwise it is used.
 *
 *    Thus, the calling programs should call this only once per set of
 *    elems for an interleaved variable, but should call it once per
 *    component for all other situations.  
 *--------------------------------------------------------------------*/ 
int
USERD_get_elem_var_values(USERDHandle handle,
                          int elemset_index,
                          int elem_var_index,
                          int comp,
                          float *values)





4.5.2.48. USERD_get_number_of_model_constants

/* -----------------------------------------------
USERD_get_number_of_model_constants

 *--------------------------------------------------------------------
 *
 * Get the number of model constants for which you will be providing info.
 *
 * (IN) handle = The USERDHandle pointer
 * created in USERD_reader_open
 *
 * returns: number of model constants
 * >=0 if okay
 * <0 if problem
 *--------------------------------------------------------------------*/
int
USERD_get_number_of_model_constants(USERDHandle handle)

4.5.2.49. USERD_get_model_constant_info

/*--------------------------------------------------------------------
 * USERD_get_model_constant_info - 

 *-------------------------------------------------------------------- 
 * 
 *   Get info about model constant 
 * 
 *  (IN)  handle               = The USERDHandle pointer
 *                               created in USERD_reader_open
 *
 *  (IN)  which_constant       = The constant number (0, 1, 2, ... num_constants-1) 
 * 
 *  (OUT) description          = Constant description 
 * 
 *                               (Array will have been allocated Z_BUFL long) 
 * 
 *  (OUT) complex              = TRUE if complex, FALSE otherwise 
 * 
 *  (OUT) freq                 = complex frequency  (if complex) 
 * 
 *  (OUT) contran              = TRUE if constant changes per time step 
 *                               FALSE if constant truly same at all time steps
 * 
 *  (OUT) timeset              = Timeset the constant will use (1 based).
 *                               (For static models, set it to 1)
 *
 *                              For example:  If USERD_get_number_of_timesets
 *                                            returns 2, the valid
 *                                            timeset_number's would be 1 or 2.
 *
 *  returns: Z_OK  if no problems
 *           Z_ERR if any errors
 * 
 *  
 *  Notes: 
 *  For each constant, the EnSight server will allocate real and 
 *   imaginary (if complex == True) float arrays sized for the number
 *   of timesteps. Each value of the float array(s) will be initialized 
 *   to FLT_MIN, which is a flag indicating that the value has not yet 
 *   been read at that timestep, allowing the call to be made once at
 *   each timestep.
 *
 * 
 *--------------------------------------------------------------------*/
int
USERD_get_model_constant_info(USERDHandle handle,
                             int which_constant,
                             char *description,
                             int *complex,
                             float *freq,
                             int *contran,
                             int *timeset)

4.5.2.50. USERD_get_model_constant_val

/*--------------------------------------------------------------------
 * USERD_get_model_constant_val - 

 *-------------------------------------------------------------------- 
 * 
 *   Get the value of a constant at a time step 
 * 
 *  (IN)  handle               = The USERDHandle pointer
 *                               created in USERD_reader_open
 *
 *  (IN)  which_constant       = The constant number (0, 1, 2, ... num_constants-1) 
 * 
 *  (IN)  imag_data            = TRUE if want imaginary data value. 
 *                               FALSE if want real data value. 
 * 
 *  returns: float value of the requested constant variable 
 * 
 *  Notes: 
 *   The server will make a call to update the timestep by calling
 *    USERD_set_time_set_and_step, and then will call this routine, so
 *    the value requested is based on hdl->current_time_step. 
 *
 *  Important change:
 *   In all past versions of all the reader APIs, the EnSight server
 *    would step through all timesteps up front and request the constant 
 *    values, forcing the reader to read the constants, up front through 
 *    all timesteps. This has been changed:
 *    New in 2021R2, in API 3, this call will be made only when timestep
 *    is changed rather than stepping through all timesteps up front. 
 *   
 *
 * 
 *
 *--------------------------------------------------------------------*/ 
 float
 USERD_get_model_constant_val(USERDHandle handle,
                             int which_constant,
                             int imag_data)

4.5.2.51. USERD_get_constant_per_part_data

/*--------------------------------------------------------------------
USERD_get_constant_per_part_data
 *                                    This routine will be called for each of 
 *                                    variables whose part type is 
 *                                    Z_CONSTANT_PER_PART as defined in
 *                                    USERD_get_gold_variable_info
 *
 *                                    This returns the desired constant per part
 *                                    variable values, for the time step desired,
 *                                    for the parts that have this variable type.
 *--------------------------------------------------------------------
 *  (IN)  handle               = The USERDHandle pointer
 *                               created in USERD_reader_open
 *
 *  (IN)  v         = The variable number
 *                                                                                    
 *  (IN)  imag_data = TRUE if want imaginary portion.  (not currently using)
 *                    FALSE if want real portion
 *                                                                                    
 *  (IN) itstep     = Time step
 *                                                                                    
 *  (OUT) extparts  = Array to receive the external part numbers that have
 *                    a value for this per_part constant.
 *                    This is the part number used in the file (or the part label)
 *                                                                                    
 *                    The array is zero-based and will be Numparts_available long, so
 *                    all original parts will fit. It is initialized to an 
 *                    impossible part number (-1) for every entry in the array.
 *                    You do not have to have values for all parts.
 *                                                                                    
 *  (OUT) values    = Array to receive the per_part constant value for the parts loaded
 *                    in extparts.
 *                                                                                    
 *                    The array is zero-based and will be Numparts_available long. Each
 *                    array entry is intialized to Z_UNDEF.
 *  Notes:
 *     Example:  Model with 5 parts
 *               At the input itstep:
 *                 part 1  has no value (is undefined for this part)
 *                 part 4  has a value of 13.45
 *                 part 5  has a value of 102.50
 *                 part 23 had no value
 *                 part 24 had a value of -4.75
 *                                                                                     
 *               Thus,
 *                 extparts[0] = 4
 *                 extparts[1] = 5
 *                 extparts[2] = 24
 *                 Note: extpats[3] and extpats[4] are their init values, -1
 *
 *                 values[0]   = 13.45
 *                 values[1]   = 102.50
 *                 values[2]   = -4.75
 *                 Note: values[3] and values[4] are their init values of Z_UNDEF
 *
 *               Since there are two of the original parts (part 1 and part 23) that
 *               do not have a defined value for this constant per part, you should 
 *               leave their values to the init values in extparts & values. So,
 *               extparts[3-4] & values[3-4] are -1 and Z_UNDEF, respectively for
 *               proper interpretation by EnSight. 
 *                                                                                    
 *     IMPORTANT: The constant per part variables are not treated like case constant  
 *                variables, but rather similar to scalars, vectors, tensor 
 *                variables so you must set their classification and type
 *                in the USERD_get_gold_variable_info routine.
 *                                                                                    
 *                      var_type[ ] = Z_CONSTANT_PER_PART
 *                      var_classify[ ] = Z_PER_PART
 * 
 * The return is either Z_OK or Z_ERR. 
 *
 * If all the per-part constants are undefined at the given timestep, simply 
 *  return Z_OK without setting anything in extparts nor values.
 *---------------------------------------------------------------------------------*/
int
USERD_get_constant_per_part_data(  
                                 USERDHandle handle,
                                 int v,
                                 int imag_data,
                                 int itstep,
                                 int *extparts,
                                 float *values) {

4.5.2.52. USERD_get_dataset_query_file_info

/*--------------------------------------------------------------------
* USERD_get_dataset_query_file_info - 
 *-------------------------------------------------------------------- 
 * 
 *   Get the information about files in the dataset.  Used for the 
 *   dataset query option. 
 * 
 *  (IN) handle = The USERDHandle pointer
*                created in USERD_reader_open
*
*  (OUT) qfiles   = Structure containing information about each file 
 *                   of the dataset. The Z_QFILES structure is defined 
 *                   in the global_extern.h file 
 * 
 *                   (The structure will have been allocated 
 *                    Num_dataset_files long, with 10 description 
 *                    lines per file). 
 *                    (See USERD_get_number_of_files_in_dataset) 
 * 
 *      qfiles[].name        = The name of the file 
 *                             (Z_MAXFILENP is the dimensioned length 
 *                              of the name) 
 * 
 *      qfiles[].sizeb       = The number of bytes in the file 
 *                             (Typically obtained with a call to the 
 *                              "stat" system routine) 
 * 
 *      qfiles[].timemod     = The time the file was last modified 
 *                             (Z_MAXTIMLEN is the dimesioned length 
 *                              of this string) 
 *                             (Typically obtained with a call to the 
 *                              "stat" system routine) 
 * 
 *      qfiles[].num_d_lines = The number of description lines you 
 *                              are providing from the file. Max = 10 
 * 
 *      qfiles[].f_desc[]    = The description line(s) per file, 
 *                              qfiles[].num_d_lines of them 
 *                              (Z_MAXFILENP is the allocated length of 
 *                               each line) 
 * 
 *  returns: Z_OK  if successful 
 *           Z_ERR if not successful 
 * 
 *  Notes: 
 *  * If Num_dataset_files is 0, this routine will not be called. 
 *    (See USERD_get_number_of_files_in_dataset) 
 *--------------------------------------------------------------------*/ 
int
USERD_get_dataset_query_file_info(USERDHandle handle, Z_QFILES *qfiles)

4.5.2.53. USERD_get_extra_data

int 
USERD_get_extra_data(USERDHandle handle,                           /* must be always be defined */
                     int *target, int *nint, int *nflt, int *nchr, /* populated on first call */
                     int *pint, float *pflt, char *pchr)           /* populated on second call */
* this routine is optional. It provides the ability to customize
* the behavior of EnSight.
* 
* (IN) handle = The USERDHandle pointer
*               created in USERD_reader_open
*
* It is called twice: the first time to define the size of arrays 
*  and what to do with them, the second time to actually populate the
*  arrays.
* 
* FIRST CALL:
* If this routine is present, then the server will call into it 
*  expecting you to define the following: 
*  (IN) target = a defined DATA_TARGET_* values in the ../extern/global_extern.h 
*  (IN) nint = number of integers
*  (IN) nflt = number of floats
*  (IN) nchr = number of floats
*  (IN) pint = NULL  (do not write to this pointer on the first call!)
*  (IN) pflt = NULL  (do not write to this pointer on the first call!)
*  (IN) pchr = NULL  (do not write to this pointer on the first call!)
*
*  SECOND CALL:
*  EnSight will then allocate integer, float, and char arrays and
*  call back into this routine to populate these arrays.
*  (IN) pint[nint] with integer values
*  (IN) pflt[nflt] with float values
*  (IN) pchr[nchr] with char values
*  
*  and then EnSight will do something with these values depending on 
*  the value of the target.
*  
*  One example usage is, on the first call 
*  to define *target = DATA_TARGET_UNDEF_VAL
*  and to defined nflt = 1
*  then on the second call, pflt will be an array of 1
*  (and the other arrays will still be NULL)
*  Now defined pflt[0] to be some float value that is your custom
*  undefined value for EnSight to handle as undefined.
*
* returns: 
* Z_OK if successful
* Z_ERR if not successful

4.5.2.54. USERD_get_matf_escalars_desc

 * 
*--------------------------------------------------------------------
*
* Gets the list of descriptions of scalar per element variables to be defined
* as the specified materials. This list of element scalar descriptions must be
* given in the same order, or sequence as the listed material ids.
*
* (IN) handle         = The USERDHandle pointer
*                       created in USERD_reader_open* 
*   set_index         = The material set index
*
* (OUT) mesv_desc     = 2D array of per element scalar descriptions
*                       Array will have beeen allocated by:
*                       [Num_materials[set_index]] by [Z_BUFL]
*
* returns: Z_OK if no problems
*          Z_ERR if an error
*
*
* Notes:
* * See USERD_get_number_of_material_sets header for explanatory example
* * Will not be called unless the set_type in USERD_get_matf_set_type
* is Z_MISET_VIA_ESCAL_VARS
* * Use this in place of the sparse material list interfacing method, which
* uses USERD_size_matf_data and USERD_load_matf_data
* * This function does not work with material SPECIES, i.e. with the function
* calls USERD_get_matsp_info and USERD_get_number_of_species
* * The mesv_desc array is NOT the same as the mat_desc array given via the
* function USERD_get_matf_var_info
*--------------------------------------------------------------------*/
int
USERD_get_matf_escalars_desc(USERDHandle handle, int set_index,
                                                  char **mesv_desc)
/*--------------------------------------------------------------------

4.5.2.55. USERD_get_matf_set_info

* 
*--------------------------------------------------------------------
*
* Get the material set ids and names
*
* (IN) handle               = The USERDHandle pointer
*                             created in USERD_reader_open
* 
* (OUT) mat_set_ids         = 1D material set ids array. (A list of unique, non-zero,
*                             positive number ids to be associated with each material
*                             set)
*
*                         (Array will have been allocated
*                          Num_material_sets long)
*
* (OUT) mat_set_name        = 2D material set name array
*
*                         (Array will have been allocated
*                          Num_material_sets by Z_BUFL long)
*
* returns: Z_OK if successful
*          Z_ERR if not successful
*
* Notes:
* * Will not be called if Num_material_sets is zero
* * See USERD_get_number_of_material_sets header for explanatory example
*--------------------------------------------------------------------*/
int
USERD_get_matf_set_info(USERDHandle handle, int *mat_set_ids,
                                            char **mat_set_name)
/*--------------------------------------------------------------------

4.5.2.56. USERD_get_matf_set_type

 * 
*--------------------------------------------------------------------
* Gets the material set type
*
* (IN) handle                   = The USERDHandle pointer
*                                 created in USERD_reader_open
* 
*                                set_index = The material set index
*
* returns: set_type = Z_MISET_VIA_SPARSE_MIX (default)
*                     Z_MISET_VIA_ESCAL_VARS
*
* Notes:
* * See USERD_get_number_of_material_sets header for explanatory example
* * Z_MISET_VIA_ESCAL_VARS does not work with the material species functions, i.e.
* USERD_get_number_of_species and USERD_get_matsp_info
* * Use Z_MISET_VIA_SPARSE_MIX to interface materials via sparse material id,
* mixed id, and mixed value lists (see USERD_size_matf_data and
* USRERD_load_matf_data).
* * Use Z_MISET_VIA_ESCAL_VARS to interface materials via/as scalar per element
* variables (see USERD_get_matf_escalars_desc).
*--------------------------------------------------------------------*/
int
USERD_get_matf_set_type(USERDHandle handle, int set_index)
/*--------------------------------------------------------------------

4.5.2.57. USERD_get_matf_var_info

 
*--------------------------------------------------------------------
*
* Get the material ids and descriptions for the material set
*
* (IN) handle                     = The USERDHandle pointer
*                                   created in USERD_reader_open
* 
*      set_index = the material set index (zero based)
*
* (OUT) mat_ids[set_index]        = 1D materials ids array (internal, non-zero,
*                                                             positive numeric id)
*
*                                   (Array will have been allocated
*                                     Num_materials long)
*
* (OUT) mat_desc[set_index]       = 2D material descriptions array (description in GUI
*                                                                     material list)
*
*                                   (Array will have been allocated
*                                     Num_materials by Z_BUFL long)
*
* returns: Z_OK if successful
*          Z_ERR if not successful
*
* Notes:
* * See USERD_get_number_of_material_sets header for explanatory example
*
* * Will not be called if Num_material_sets is zero, or
* Num_materials[set_index] is zero
*--------------------------------------------------------------------*/
int
USERD_get_matf_var_info(USERDHandle handle,
                        int set_index,
                        int *mat_ids,
                        char **mat_desc)
/*--------------------------------------------------------------------

4.5.2.58. USERD_get_matsp_info

 *--------------------------------------------------------------------
*
* Get the material ids and descriptions for the material set
*
* (IN) handle                           = The USERDHandle pointer
*                                         created in USERD_reader_open
* 
* (IN) set_index                        = Material set index (zero based)
*
* (OUT) sp_ids[set_index]               = 1D material species ids array (non-zero, positive
*                                                                         numeric id)
*
*                                       (Array will have been allocated
*                                         Num_species long)
*
* (OUT) sp_desc[set_index]              = 2D material species descriptions array
*
*                                       (Array will have been allocated
*                                         Num_species by Z_BUFL long)
*
* (OUT) sp_per_mat_cnt[set_index]       = 1D species per material count array
*
*                                       (Array will have been allocated
*                                         Num_materials long)
*
* (OUT) sp_per_mat_lis[set_index]       = 1D concatonated lists of species
*                                         per material array
*
*                                       (Array will have been allocated
*                                         Num_materials*Num_species long)
*
* returns: Z_OK if successful
*          Z_ERR if not successful
*
* Notes:
* * See USERD_get_number_of_material_sets header for explanatory example
*
* * Will not be called if Num_material_sets is zero, or
* Num_materials[set_index] is zero
*--------------------------------------------------------------------*/
int
USERD_get_matsp_info(USERDHandle handle,
                      int set_index,
                      int *sp_ids,
                      char **sp_desc,
                      int *sp_per_mat_cnt,
                      int *sp_per_mat_lis)

4.5.2.59. USERD_get_maxsize_info

*--------------------------------------------------------------------
* USERD_get_maxsize_info - Get maximums of geometry entities over all 
*                           time for all parts, in order to save EnSight 
*							from expensive memory reallocations.
*
*                          NOTE: This routine is optional and, in fact, is
*                          rarely included in readers because most solvers
*                          do not keep track of maximums and write them into
*                          their solution files and it is far too time 
*                          consuming to pre-read through all timesteps and 
*                          determine these maximums.
*--------------------------------------------------------------------
*
* Transient models (especially those that increase in size) can cause
* reallocations, at time step changes, to keep chewing up more and
* more memory. The way to avoid this is to know what the maximum
* size of such memory will be, and allocate for this maximum initially.
*
* Accordingly, if you choose to provide this information (it is optional),
* EnSight will take advantage of it.
*
* (IN) handle                     = The USERDHandle pointer created in USERD_reader_open
*
* (OUT) max_number_of_nodes       = Maximum number of unstructured nodes
*                                   that will be in the part (over all time). Note: Array will have been 
*                                   allocated Numparts_available long
*
* max_number_of_elements          = 2D array containing maximum number of
*                                   each type of element for each unstructured model part (over all 
*                                   time). * (Array will have been allocated Numparts_available by
*                                   Z_MAXTYPE long)
*
*                                   Possible element types are:
*
*                                   Z_POINT = point
*                                   Z_BAR02 = 2-noded bar
*                                   Z_BAR03 = 3-noded bar
*                                   Z_TRI03 = 3-noded triangle
*                                   Z_TRI06 = 6-noded triangle
*                                   Z_QUA04 = 4-noded quadrilateral
*                                   Z_QUA08 = 8-noded quadrilateral
*                                   Z_TET04 = 4-noded tetrahedron
*                                   Z_TET10 = 10-noded tetrahedron
*                                   Z_PYR05 = 5-noded pyramid
*                                   Z_PYR13 = 13-noded pyramid
*                                   Z_PEN06 = 6-noded pentahedron
*                                   Z_PEN15 = 15-noded pentahedron
*                                   Z_HEX08 = 8-noded hexahedron
*                                   Z_HEX20 = 20-noded hexahedron
*                                   Z_G_POINT ghost node point element
*                                   Z_G_BAR02 2 node ghost bar
*                                   Z_G_BAR03 3 node ghost bar
*                                   Z_G_TRI03 3 node ghost triangle
*                                   Z_G_TRI06 6 node ghost triangle
*                                   Z_G_QUA04 4 node ghost quad
*                                   Z_G_QUA08 8 node ghost quad
*                                   Z_G_TET04 4 node ghost tetrahedron
*                                   Z_G_TET10 10 node ghost tetrahedron
*                                   Z_G_PYR05 5 node ghost pyramid
*                                   Z_G_PYR13 13 node ghost pyramid
*                                   Z_G_PEN06 6 node ghost pentahedron
*                                   Z_G_PEN15 15 node ghost pentahedron
*                                   Z_G_HEX08 8 node ghost hexahedron
*                                   Z_G_HEX20 20 node ghost hexahedron
*
*                                   (Only used for Z_UNSTRUCTURED data)
* 
* max_ijk_dimensions               = 2D array containing maximum ijk dimensions
*                                    for each structured model part (over_all_time). Note: Array will 
*                                    have been allocated Numparts_available by 3 long)
*                                    (Only used for Z_STRUCTURED data)
*
* max_ijk_dimensions[][0]          = maximum I dimension
* max_ijk_dimensions[][1]          = maximum J dimension
* max_ijk_dimensions[][2]          = maximum K dimension
*
* Returns 
*         Z_OK - execution ok, supplying maximum geometry data
*         Z_ERR - execution problem: ignore the maximum data
* or
*          Largest time step + 2 - if supplying maximum data 
*          and the zero-based time step at which it occurred.
*          (The +2 is needed to be able to distinguish this
*          properly from Z_OK or Z_ERR. It will be subtracted 
*          again in EnSight.)
*
* Notes:
* 
* This routine is optional, and rarely included in readers
* 
* Note: this routine is called after
*   USERD_get_number_of_model_parts and
*   USERD_get_gold_part_build_info, 
*  so Numparts_available is used to dimension the arrays, and 
*  so EnSight will know what the type is (Z_UNSTRUCTURED, Z_STRUCTURED,
*   or Z_IBLANKED) of each part.
*
* These maximums will NOT be based on Current_time_step - it is to be 
*  the maximum values over all time!!
*
* If you do not include this routine, or if you return Z_ERR, Ensight will 
* still process things fine, reallocating as needed, etc. However, for
* large transient models you will likely use considerably more memory
* and take more processing time for the memory reallocations. So, if it
* is possible to provide this information "up front", it is recommended
* to do so.
*--------------------------------------------------------------------*/
int
USERD_get_maxsize_info(USERDHandle handle,
                        int *max_number_of_nodes,
                        int *max_number_of_elements[Z_MAXTYPE],
                        int *max_ijk_dimensions[3])
/*--------------------------------------------------------------------

4.5.2.60. USERD_get_model_extents

* int
* USERD_get_model_extents - Get the bounding box extents
*
*                           Note that this routine is optional
*                           and is rarely included in a reader
*                           because most solvers do not included
*                           this information at each timestep.
*-------------------------------------------------------------------
*
* Calculating the bounding box extents consumes time. This routine
*  can save EnSight compute time.
* If this routine is not in the reader, or if it returns Z_ERR, 
*  then EnSight will find the bounding box by looping through all 
*  the coordinates of all the nodes and calculate this info.
*
* (OUT) extents[0] = min x
*              [1] = max x
*              [2] = min y
*              [3] = max y
*              [4] = min z
*              [5] = max z
*
* Returns: 
*           Z_ERR if no extents given (EnSight will read all coords and
*                                       calculate)
*           Z_OK if extents given
*
* Notes:
* * This will be based on Current_time_step
*--------------------------------------------------------------------*/
int
USERD_get_model_extents( USERDHandle handle,
                          float extents[6] )
/*--------------------------------------------------------------------

4.5.2.61. USERD_get_number_of_files_in_dataset

*--------------------------------------------------------------------
*  USERD_get_number_of_files_in_dataset - Provide the server with the number 
*                                         of files in the dataset for use with
*                                         USERD_get_dataset_query_file_info
*--------------------------------------------------------------------
*
* Get the total number of files in the dataset. 
*
* (IN) handle         = The USERDHandle pointer created in USERD_reader_open
*
* Return the total number of files in the dataset
*
* Notes:
* 
* You can be as complete as you want about this. If you don't
* care about the dataset query option, return a value of 0
* If you only want certain files, you can just include them. But,
* you will need to supply the info in USERD_get_dataset_query_file_info
* for each file you include here.
*
* 
*   Num_dataset_files would be set here
*--------------------------------------------------------------------*/
int
USERD_get_number_of_files_in_dataset( USERDHandle handle )

4.5.2.62. USERD_rigidbody_existence

/*--------------------------------------------------------------------
 * USERD_rigidbody_existence - Returns a flag indicating that
 *                             rigidbody transformations occur in
 *                             this dataset
 * ------------------------------------------------------------
 *
 *  (IN)  handle         = The USERDHandle pointer
 *                         created in USERD_reader_open
 *
 * returns: Z_OK if rigid body values exist for the model
 *          Z_UNDEF if no rigid body values exist
 *          Z_ERR if an error
 *
 * Notes:
 * This will be based on Current_time_step
 *--------------------------------------------------------------------*/
int
USERD_rigidbody_existence( voidUSERDHandle handle )

4.5.2.63. USERD_rigidbody_values

/*--------------------------------------------------------------------
 * USERD_rigidbody_values - get rigid body transformations for each
 *                          at the current timestep
 * ------------------------------------------------------------
 *
 *  (IN)  handle         = The USERDHandle pointer
 *                         created in USERD_reader_open
 *
 *        part_number    = The 1-based part number
 *                         from 1...Numparts_available
 *
 *
 * It is NOT the part_id that is
 * loaded in USERD_get_gold_part_build_info)
 *
 * (OUT) values[14] (values[0] to [13])
 *
 *
 * Order that transformations will be applied is:
 * 1. The yaw,pitch,roll rotations, if present
 *    (values[11] through values[13]
 *    in the order specified in rot_order, values[10])
 * 2. The cg offsets, if present (values[7] through values[9])
 * 3. The euler parameter rotations (values[3] through values[6])
 * 4. The translations (values[0] through values[2])
 *
 *  See below for more details
 *
 * 1. === YAW, PITCH, & ROLL ===
 *     The last 4 values ([10]-[13] are applied first.
 *     They are for an optional initial yaw,
 *     pitch, roll operation. This is useful to get parts
 *     from one standard layout to a different standard
 *     layout.
 *     (example, flex body parts computed in an axis system
 *     different than that of rigid body parts manipulation)
 *     If not needed or desired, set these to 0.0
 *
 *     values[10] = rot_order (order the rotations are applied)
 *       0.0 = no rotations
 *       1.0 = xyz order
 *       2.0 = xzy order
 *       3.0 = yxz order
 *       4.0 = yzx order
 *       5.0 = zxy order
 *       6.0 = zyx order)
 *     values[11] = xrot (initial x rotation - degrees)
 *     values[12] = yrot (initial y rotation - degrees)
 *     values[13] = zrot (initial z rotation - degrees)
 *
 * 2. === EULER CENTER OF ROTATION ===
 *     The next 3 are for an optional Center of Rotation offset.
 *     The euler rotations happen about the global
 *      origin. If the RBM rotation happens about
 *      a location on the part that is not the global
 *      origin, then set this here.  Note that this is
 *      the negative of the center of rotation location,
 *      because it represents the vector from the center of
 *      rotation to the origin. Otherwise set it
 *      to (0.0,0.0,0.0)
 *     Stated differently, if the center of rotation is
 *       not at the global origin, then you must do a pre-translation
 *       that will place the desired part center of rotation at
 *       global origin, then apply the euler rotation, then
 *       translate the part back to where it should be.
 *    
 *     values[7] = xoff (initial center of rotation x offset)
 *     values[8] = yoff (initial center of rotation y offset)
 *     values[9] = z0ff (initial center of rotation z offset)
 *
 * 3. === EULER ROTATION PARAMETERS ===
 *     Next, the Euler rotational parameters are applied
 *      which rotate about the global origin (0.0,0.0,0.0)
 *    
  *
 *     values[3] = E0 (e0 euler value) = cos(phi/2)
 *     values[4] = E1 (e1 euler value) = n1 * sin(phi/2)
 *     values[5] = E2 (e2 euler value) = n2 * sin(phi/2)
 *     values[6] = E3 (e3 euler value) = n3 * sin(phi/2)
 *    
 *     NOTE: if E0^2+E1^2+E2^2+E3^2 is not equal to 1,
 *           then strange transformations occur.
 *
 * 4. === TRANSLATION ===
 *     Finally , the translational values are applied
 *     values[0] = Translation X
 *     values[1] = Translation Y
 *     values[2] = Translation Z
 *    
 *
 *
 * ORDER of OPERATIONS REVIEW
 * First the yaw, pitch and roll values[11] through values[13])
 *   in the order defined by values[10])
 * Then the translations of values[7] through values[9] to
 *  align the center of rotation to the global origin
 * Then the euler rotations of values[3] through values[6]
 *  about the global orgin
 * Then the translations of values[0] through values[2]
 *  to translate the part to the desired location
 * ================================
 * So, perhaps a simple 2d example:
 * ================================
 * Given a square at the location shown (centered on x=2, y=1).
 *
 * It is oriented as desired in the global coordinate system
 *  so no pre-rotation is necessary,
 *  values[10] through values[13] are all 0.0.
 *
 * Y
 * |
 * |  3            4
 * |  *------------*
 * |  |            |
 * |  |            |
 * |  |     .      | Center is at (2,1)
 * |  |            |
 * |  |            |
 * |  *------------*
 * |  1            2
 * o----------------------------- x
 *   We desire to have it rotate 90 degrees about the z axis,
 *   and translate to x=3,y=0
 * Y
 * |
 * |
 * |
 * |
 * |
 * |
 * |
 * |            4 *------------* 2
 * |              |            |
 * |              |            |
 * 0--------------|      .     |--- x Center is now at (3,0)
 *                |            |
 *                |            |
 *              3 *------------* 1
 * The values needed are:
 *
 * These are the initial translations to get center to the origin
 *   values[7] = -2 
 *   values[8] = -1
 *   values[9] =  0
 *
 * These are the euler parameters for the 90 degree rotation
 *  about the Z axis. Which will now occur about the part center,
 *  because that center has been moved to the coordinate system origin.
 *   values[3] = 0.7071 
 *   values[4] = 0.0 
 *   values[5] = 0.0 
 *   values[6] = 0.7071
 *
 *
 * values[0] = 3 These are the final translations to get the center
 * values[1] = 0 the origin to the desired final location.
 * values[2] = 0
 *
 *
 * So you can think of this as
 *  a) moving the part to the origin back to (0.0,0.0,0.0),
 *  b) doing the rotation about (0.0,0.0,0.0),
 *  c) and then moving the part back out to where you want it to end up.
 *
 *
 * returns: Z_OK if rigid body values sent for this part
 *          Z_UNDEF if no rigid body values exist for this part
 *          Z_ERR if an error
 *
 *
 * Notes:
 * This will be based on Current_time_step
 * IF USERD_rigidbody_existence returns Z_OK, then ALL parts must return
 *  valid values.  Setting all values to 0.0 except values[3]=1.0 indicates
 *  that the part is not rotated nor translated.  
 *  Setting all values to zero is invalid and causes unpredictable results.
 *
 * This routine is not called if USERD_rigidbody_existence does not return Z_OK. *
 *
 *--------------------------------------------------------------------*/
int
USERD_rigidbody_values(USERDHandle handle,
                        int part_number,
                        float values[14]) 

4.5.2.64. USERD_get_var_value_at_xyz_specific

 /*--------------------------------------------------------------------
 * USERD_get_var_value_at_xyz_specific - Get the value of a particular variable
 *                                       at a specific XYZ location
 *
 *                                       This optional routine avoids the need for 
 *                                       the server to request all variable values
 *                                       at a given timestep in order to determine 
 *                                       a single value of interest, thus saving time
 *                                       and memory.
 *
 *                                       This would save memory, limit I/O, and improve
 *                                       performance, for example, for a query of a 
 *                                       variable value at aa specific location over time.
 *
 *--------------------------------------------------------------------
 *    
 * (IN) handle         = The USERDHandle pointer created in USERD_reader_open
 *
 *   which_var - Which variable
 *
 *   xyz[3] - the xyz coordinates of the desired point.
 *
 *   which_part - the (1-based) index of the part (1-Numparts_available)
 *                It is NOT the part_id that is loaded in
 *                  USERD_get_gold_part_build_info
 *
 *  time_step = Time step to use (0 to Num_time_steps[the proper var timeset])
 *
 * (IN) imag_data = TRUE if imaginary data, FALSE if real data
 *
 * (OUT)
 *
 *  values[3] - variable value(s):
 *              values[0] if Z_SCALAR or
 *              values[0..2] if Z_VECTOR
 *
 * Return:
 * Z_OK if xyz found in part provided.
 * Z_UNDEF if not found in part provided
 * Z_ERR if something went wrong
 * 
 * Notes:
 * This routine is optional If not included in your reader,
 *  EnSight will do searches in each time step (which can be
 *  slow because it will have to update all results at each
 *  timestep).
 *
 *--------------------------------------------------------------------*/
 int
 USERD_get_var_value_at_xyz_specific(USERDHandle handle 
 int which_var,
 float xyz[3],
 int which_part,
 int time_step,
 float values[3],
 int imag_data)
 /*-----------------------------------------------------------------------------

4.5.2.65. USERD_get_number_of_material_sets

 /*--------------------------------------------------------------------
 * USERD_get_number_of_material_sets - Optional routine to get the number  
 *                                     of material sets in the model
 *--------------------------------------------------------------------
 * 
 * (IN) handle - The USERDHandle pointer created in USERD_reader_open
 *
 * Return: Num_material_sets = number of material sets
 *                             (Zero would indicate that you have no materials
 *                             to deal with in the model)
 *                 or 
 *            if your data does not have material sets, then leave this routine
 *            out entirely from your reader
 *                 or
 *            -1 if an error condition
 * Notes:
 *
 * Store the number of material sets in the handle, for use in other routines.
 *
 *
 * ================================================================
 * A very simple explanatory example, to use as a reference for the materials
 * routines:
 *
 * Given a 2D mesh composed of 9 quad (Z_QUA04) elements, with two materials.
 * Most of the model is material 1, but the top left corner is material 9 -
 * basically as shown:
 *
 * 
 *
 *        *--------*--------*--------*
 *        |        |   /    |        |
 *        |     Mat 9 /     |        |
 *        |        | /      |        |
 *        |        |/       |        |
 *        |  e7    /   e8   |   e9   |
 *        |       /|        |        |
 *        |      / |        |        |
 *        |     /  |        |        |
 *        *----/---*--------*--------*
 *        |   /    |        |        |
 *        |  /     |        |        |
 *        | /      |      Mat 1      |
 *        |/       |        |        |
 *        |   e4   |   e5   |   e6   |
 *        |        |        |        |
 *        |        |        |        |
 *        |        |        |        |
 *        *--------*--------*--------*
 *        |        |        |        |
 *        |        |        |        |
 *        |        |        |        |
 *        |        |        |        |
 *        |   e1   |   e2   |   e3   |
 *        |        |        |        |
 *        |        |        |        |
 *        |        |        |        |
 *        *--------*--------*--------*
 *
 *
 * Thus, in this routine, set:
 *   Num_material_sets = 1
 *
 * In USERD_get_matf_set_info, set:
 *   mat_set_ids[0] = 1
 *   mat_set_name[0] = "Material Set 1" (or whatever name desired)
 *
 * In USERD_get_number_of_materials, input would be set_index = 0, and
 * would need to set:
 *   Num_materials[0] = 2
 *
 * For simplicity, the ids and descriptions that would be returned in
 * USERD_get_matf_var_info could be:
 *   mat_ids[0] = 1
 *
 Detailed Specifications
 *   mat_ids[1] = 9
 *   mat_desc[0] = "mat 1" (or whatever desired)
 *   mat_desc[2] = "mat 9"
 *
 * Option 1: For readers that accommodate sparse material lists.
 * In USERD_get_matf_set_type, the input would be set_index = 0, and if
 * set_type = Z_MISET_VIA_SPARSE_MIX, the following 3 lists (material ids,
 * mixed-material ids, and mixed-material values) would be needed and
 * communicated by the following two USERD calls,
 * i.e. USERD_size_matf_data and USERD_load_matf_data.
 *
 * The per element material ids list would need to be:
 *
 * material ids:
 * -------------
 * ids_list[0] = 1 (material id 1, for elem e1)
 * ids_list[1] = 1 ( " e2)
 * ids_list[2] = 1 ( " e3)
 * ids_list[3] = -1 (neg. of index into mixed-material id list, for elem e4)
 * ids_list[4] = 1 (material id 1, for elem e5)
 * ids_list[5] = 1 ( " e6)
 * ids_list[6] = -5 (neg. of index into mixed-material id list, for elem e7)
 * ids_list[7] = -9 ( " e8)
 * ids_list[8] = 1 (material id 1, for elem e9)
 *
 * Finally we need the mixed material ids list and the mixed materials
 * values list, which would need to be:
 *
 *       mixed-material ids:
 *       -------------------
 *   ==> 1  ids_list[0]  =  2  (the -1 in the material variable points here,
 *                                      2 indicates that two materials are present)
 *       2  ids_list[1]  =  1  (1st material is 1)
 *       3  ids_list[2]  =  9  (2nd material is 9)
 *       4  ids_list[3]  = -1  (negative of index into mixed-material val_list)
 *   ==> 5  ids_list[4]  =  2  (the -5 in the material variable points here,
 *                                      2 indicates that two materials are present)
 *       6  ids_list[5]  =  1  (1st material is 1)
 *       7  ids_list[6]  =  9  (2nd material is 9)
 *       8  ids_list[7]  = -3  (negative of index into mixed-material val_list)
 *   ==> 9  ids_list[8]  =  2     etc.
 *       10 ids_list[9]  =  1
 *       11 ids_list[10] =  9
 *       12 ids_list[11] = -5
 *
 *       mixed-material values:
 *       ----------------------
 *   ==> 1 val_list[0] = 0.875 (the -1 in the  mixed-material ids_list points here,
 *                                       and this is the value for material 1)
 *       2 val_list[1] = 0.125 (the value for material 9)
 *   ==> 3 val_list[2] = 0.125 (the -3 in the mixed-materials ids_list points here)
 *       4 val_list[3] = 0.875
 *   ==> 5 val_list[4] = 0.875 (the -5 in the mixed-materials ids_list points here)
 *       6 val_list[5] = 0.125
 *
 *  So, USERD_size_matf_data would need to return
 *       matf_size = 8, when called with set_id    = 1
 *                                       part_id   = 1
 *                                       wtyp      = Z_QUA04
 *                                       mat_type  = Z_MAT_INDEX
 *
 *       matf_size = 12, when called with set_id   = 1
 *                                        part_id  = 1
 *                                        mat_type = Z_MIX_INDEX
 *
 *                 = 6, when called with set_id   = 1
 *                                       part_id  = 1
 *                                       mat_type = Z_MIX_VALUE
 *
 *  So, USERD_size_matf_data would need to return
 *       matf_size = 8, when called with set_id    = 1
 *                                       part_id   = 1
 *                                       wtyp      = Z_QUA04
 *                                       mat_type  = Z_MAT_INDEX
 *
 *       matf_size = 12, when called with set_id   = 1
 *                                        part_id  = 1
 *                                        mat_type = Z_MIX_INDEX
 *
 *                 = 6, when called with set_id   = 1
 *                                       part_id  = 1
 *                                       mat_type = Z_MIX_VALUE
 *
 *  And, USERD_load_matf_data would need to return:
 *    the int array ids_list as shown above when called with:
 *       set_id   = 1
 *       part_id  = 1
 *       wtyp     = Z_QUA04
 *       mat_type = Z_MAT_INDEX (indicating id list).
 *
 *    the int array ids_list as shown above when called with:
 *       set_id   = 1
 *       part_id  = 1
 *       mat_type = Z_MIX_INDEX (indicating id list).
 *
 *    the float array val_list as shown above when called with:
 *       set_id   = 1
 *       part_id  = 1
 *       mat_type = Z_MIX_VALUE (indicating val list).
 *
 * Option 2: For readers that have the materials defined as
 *           per element scalar variables.
 * In USERD_get_matf_set_type, the input would be set_index = 0, and if
 * set_type = Z_MISET_VIA_ESCAL_VARS, then only USERD_get_matf_escalars_desc
 * would be called.
 *
 * In USERD_get_matf_escalars_desc, the input would be set_index = 0, and
 * the descriptions of the per element scalar variables assigned as
 *   materials would need to be:
 *   mesv_desc[0] = "Escalar_1"
 *   mesv_desc[1] = "Escalar_9"
 *
 * Then corresponding per element lists would be:
 * for list "Escalar_1"
 * escal1_lis[0] = 1 {elem scalar value for elem 1}
 * escal1_lis[1] = 1 {elem scalar value for elem 2}
 * escal1_lis[2] = 1 {elem scalar value for elem 3}
 * escal1_lis[3] = .875 {elem scalar value for elem 4}
 * escal1_lis[4] = 1 {elem scalar value for elem 5}
 * escal1_lis[5] = 1 {elem scalar value for elem 6}
 * escal1_lis[6] = .125 {elem scalar value for elem 7}
 * escal1_lis[7] = .875 {elem scalar value for elem 8}
 * escal1_lis[8] = 1 {elem scalar value for elem 9}
 *
 * for list "Escalar_9"
 * escal1_lis[0] = 0 {elem scalar value for elem 1}
 * escal1_lis[1] = 0 {elem scalar value for elem 2}
 * escal1_lis[2] = 0 {elem scalar value for elem 3}
 * escal1_lis[3] = .125 {elem scalar value for elem 4}
 * escal1_lis[4] = 0 {elem scalar value for elem 5}
 * escal1_lis[5] = 0 {elem scalar value for elem 6}
 * escal1_lis[6] = .875 {elem scalar value for elem 7}
 * escal1_lis[7] = .125 {elem scalar value for elem 8}
 * escal1_lis[8] = 0 {elem scalar value for elem 9}
 *
 * Note: Either Option 1 OR Option 2 can be used; not both simultaneously.
 * Option 1 should be used for readers that accommodate sparse material lists.
 * Option 2 should be used for readers that have the materials defined as
 *          per element scalar variables.
 *--------------------------------------------------------------------*/
 int
 USERD_get_number_of_material_sets( USERDHandle handle  )

4.5.2.66. USERD_load_matf_data

 /*--------------------------------------------------------------------
 * USERD_load_matf_data - Get the material id list,
 *                        mixed-material id list, or
 *                        mixed-material values list
 *                        for the given material set
 *                        and part (and element type
 *                        if material id list)
 *                        This optional routine becomes manditory 
 *                        if USERD_get_number_of_material_sets
 *                        is included in the reader
 *--------------------------------------------------------------------
 *
 *   Get the material id list, mixed-material id list, or
 *   mixed-material values list for the given material set and part (and
 *   element type if material id list)
 *
 *  (IN)  handle - The USERDHandle pointer created in USERD_reader_open
 *
 *        set_index         = the material set index (zero based)
 *
 *        part_id           = the part number desired
 *
 *        wtyp              = the element type        (used for Z_MAT_INDEX only)
 *
 *        mat_type          = Z_MAT_INDEX for material ids list
 *                            Z_MIX_INDEX for mixed-material ids list
 *                            Z_MIX_VALUE for mixed-material values list
 *                            Z_SPE_VALUE for material species values list
 *
 *  (OUT) ids_list          = If mat_type is Z_MAT_INDEX:
 *                            ---------------------------
 *                             1D material id list
 *                               (Int array will have been allocated
 *                                the appropriate size, as returned in
 *                                 USERD_size_matf_data for mat_type Z_MAT_INDEX)
 *
 *                            If mat_type is Z_MIX_INDEX:
 *                            ---------------------------
 *                             1D mixed-material id list
 *                               (Int array will have been allocated
 *                                the appropriate size, as returned in
 *                                 USERD_size_matf_data for mat_type Z_MIX_INDEX)
 *
 *  (OUT) val_list          = 1D mixed-materials values list
 *                            (only used if mat_type is Z_MIX_VALUE)
 *
 *                               (Float array will have been allocated
 *                                the appropriate size, as returned in
 *                                USERD_size_matf_data for mat_type Z_MIX_VALUE)
 *
 *  Returns: Z_OK  if successful
 *           Z_ERR if not successful
 *
 *  Notes:
 *
 * See USERD_get_number_of_material_sets header for explanatory example
 *
 * Will not be called if Num_material_sets is zero,
 *     or Num_materials[set_index] is zero,
 *     or the appropriate size from USERD_size_matf_data is zero
 *
 *
 * This function is used only if USERD_get_matf_set_type returns
 * Z_MISET_VIA_SPARSE_MIX.
 *
 * This function is NOT used if USERD_get_matf_set_type returns
 * Z_MISET_VIA_ESCAL_VARS (and thus is incompatible with
 * USERD_get_matf_escalars_desc)
 *--------------------------------------------------------------------*/
 int
 USERD_load_matf_data( int set_index,
                      int part_id,
                      int wtyp,
                      int mat_type,
                      int *ids_list,
                      float *val_list)

4.5.2.67. USERD_size_matf_data

 /*--------------------------------------------------------------------
 * USERD_size_matf_data - Get the length of the material id list,
 *                        mixed-material id list, or
 *                        mixed-material values list for the given
 *                        material set and part (and element type if
 *                        material id list)
 *
 *                        This optional routine becomes manditory 
 *                        if USERD_get_number_of_material_sets
 *                        is included in the reader
 *--------------------------------------------------------------------
 *
 *   Get the length of the material id list, mixed-material id list, or
 *   mixed-material values list for the given material set and part (and
 *   element type if material id list)
 *
 *  (IN)  set_index         = the material set index (zero based)
 *
 *        part_id           = the part number desired
 *
 *        wtyp              = the element type        (used for Z_MAT_INDEX only)
 *
 *        mat_type          = Z_MAT_INDEX for material ids list
 *                            Z_MIX_INDEX for mixed-material ids list
 *                            Z_MIX_VALUE for mixed-material values list
 *
 *  (OUT) matf_size         = the length of the material id list, or
 *                            mixed-material id list, or
 *                            mixed-material values list
 *                            for the given material set and part number
 *                            (and element type if Z_MAT_INDEX)
 *
 *  returns: Z_OK  if successful
 *           Z_ERR if not successful
 *
 *  Notes:
 *  * See USERD_get_number_of_material_sets header for explanatory example
 *  * Will not be called if Num_material_sets is zero, or
 *     Num_materials[set_index] is zero
 *--------------------------------------------------------------------*/
 int
 USERD_size_matf_data( int set_index,
                      int part_id,
                      int wtyp,
                      int mat_type,
                      int *matf_size)

4.5.2.68. USERD_get_number_of_materials

 /*--------------------------------------------------------------------
 * USERD_get_number_of_materials -  Get the number of materials in the
 *                                  material set.
 *                                  This optional routine becomes manditory 
 *                                  if USERD_get_number_of_material_sets
 *                                  is included in the reader
 *--------------------------------------------------------------------
 *
 *   Get the number of materials in the material set
 *
 *   (IN) handle - The USERDHandle pointer created in USERD_reader_open
 *
 *        set_index - (0-based) set index Num_material_sets long
 *   
 *
 *  returns: Num_materials[set_index] = number of materials in set
 *                                     (Zero would indicate that you have
 *                                      no materials to deal with in the
 *                                      material set)
 *               or
 *
 *           -1 if an error condition
 *
 *  Notes:
 *  * See USERD_get_number_of_material_sets header for explanatory example
 *  * Will not be called if Num_material_sets is zero
 *  * You may want to keep this as a global for use in other routines.
 *--------------------------------------------------------------------*/
 int
 USERD_get_number_of_materials( USERDHandle handle, int set_index )
 

4.5.2.69. USERD_stop_part_building

 /*--------------------------------------------------------------------
 *  USERD_stop_part_building - Indicates the part building dialog is 
 *                             closed. It is optional.
 *
 *  This routine is useful if your reader could benefit from releasing
 *   memory, structures, etc. that were only needed during the part 
 *   building process.
 * 
 * (IN) handle - The USERDHandle pointer created in USERD_reader_open
 *
 *--------------------------------------------------------------------*/
 void
 USERD_stop_part_building( USERDHandle handle )

4.5.2.70. USERD_set_right_side

 /* -------------------------------------------------------------------
 * USERD_set_right_side - Informs the reader that the time currently 
 *                        set is the right side of a time span used 
 *                        for variable interpolation between time steps.
 *                        This is optional
 * --------------------------------------------------------------------
 *
 * Notes:
 * 
 * Applies to Current_time_step
 * 
 * This is called just before USERD_get_var_by_component
 *
 * This information is only needed if your reader must do its own
 * interpolation along a variable timeline. This can occur when rigidbody
 * information has its own timeline, which is sent to EnSight as the
 * controlling time line, but the variables have a different timeline
 * known only to the reader.
 *
 * (IN) handle - The USERDHandle pointer created in USERD_reader_open
 *--------------------------------------------------------------------*/
 void
 USERD_set_right_side( USERDHandle handle )

4.5.2.71. USERD_set_block_range_and_stride

 * USERD_set_block_range_and_stride - Sets the min, max, and step values 
 *                                in each of the i, j, and k, directions
 *                                for the given part.
 *--------------------------------------------------------------------
 *
 * (IN) handle - The USERDHandle pointer created in USERD_reader_open* 
 *      part_number = The part number
 *                   (1-based index of part table, namely:
 *                    1 ... Numparts_available.
 *                    It is NOT the part_id that is
 *                    loaded in USERD_get_gold_part_build_info)
 *
 *      mini = min i plane desired (zero based)
 *      maxi = max i plane desired (zero based)
 *      stepi = i stride
 *      minj = min j plane desired (zero based)
 *      maxj = max j plane desired (zero based)
 *      stepj = j stride
 *      mink = min k plane desired (zero based)
 *      maxk = max k plane desired (zero based)
 *      stepk = k stride
 *
 *
 * returns: Z_OK if no problems
 * Z_ERR if an error
 *
 * Notes:
 * 
 * It will not be called unless USERD_get_structured_reader_cinching
 * indicates that this reader does structured cinching by returning
 * a Z_OK.
 *
 * 
 * It will actually be called before each geom component and before
 * each part variable - so if you are storing things locally, you should
 * make this routine be able to quickly check whether anything needs
 * updated or not.
 *
 * 
 * If the stride (step) does not hit right on the max, the last element
 * in each direction will be shortened appropriately.
 * For example, if a block had 0 to 12 in the i direction,
 * and the user specified min = 1
 * max = 8
 * step = 3
 *             0   1   2   3   4   5   6   7   8   9   10  11  12 
 *             |   |   |   |   |   |   |   |   |   |   |   |   | 
 * 
 *                 |           |           |   | 
 * 
 *      Namely, the coarser cell boundaries in this direction would be 
 *              at 1, 4, 7, and 8 
 *
 * IMPORTANT!! If your reader will be used for structured auto-distribute,
 * you must implement this feature, which includes this routine and
 * USERD_get_structured_reader_cinching
 *--------------------------------------------------------------------*/
 int
 USERD_set_block_range_and_stride(USERDHandle handle,
 int part_number,
 int mini, int maxi, int stepi,
 int minj, int maxj, int stepj,
 int mink, int maxk, int stepk)

4.5.2.72. USERD_get_number_of_species

/* --------------------------------------------------------------------
* USERD_get_number_of_species - Get the number of material species 
*                               in the material set
* --------------------------------------------------------------------
*
*   (IN) handle - The USERDHandle pointer created in USERD_reader_open
* 
*        set_index = the material set index (zero based)
*
* returns: Num_species[set_index] = number of material species in set
*                                   (0 would indicate that you have no materials to deal with in the
*                                   material set)
*       or
*                                   -1 if an error condition
*
* Notes:
*  See USERD_get_number_of_material_sets instruction for explanatory example
*  Will not be called if Num_material_sets is zero
*  You may want to store Num_material_sets in the handle for use in other routines.
*  This function only works when USERD_get_matf_set_type returns
*   Z_MISET_VIA_SPARSE_MIX; and is not available if USERD_get_matf_set_type
*   returns Z_MISET_VIA_ESCAL_VARS
*--------------------------------------------------------------------*/
int
USERD_get_number_of_species( USERDHandle handle, int set_index )

4.5.2.73. USERD_get_vglyph_counts

/* ----------------------------------------------------------------------------- 
* USERD_get_vglyph_counts - Gets the counts for the number of 
*                           vector glyphs in the model. Optional
* -----------------------------------------------------------------------------
*
* (IN) handle - The USERDHandle pointer created in USERD_reader_open
* 
* (OUT) num_vglyph_vectors = The number of vector glyphs in the model.
*                           (Must be set to zero if none)
*
* (OUT) num_vglyph_timelines = The number of vector glyph timelines
*                              in the model. (can be zero if all vector glyphs are static)
*
* returns: Z_OK if no problems
*          Z_ERR if an error
*
* Notes:
*   If the USERD_get_vglyph_counts routine is in the reader, and if
*     it returns num_vglyph_vectors then
*     the following routines will be called in the following order:
*     loop through num_vglyph_timelines:
*       USERD_get_vglyph_timeline_info
*       USERD_get_vglyph_timeline_times
*     loop through num_vglyph_vectors:
*       USERD_get_vglyph_vector_info
*       USERD_get_vglyph_vector_values
*       if not nid, eid:
*         USERD_get_vglyph_vector_xyzloc
*       
*
* 
*--------------------------------------------------------------------*/
int
USERD_get_vglyph_counts( USERDHandle handle, 
                          int *num_vglyph_vectors,
                          int *num_vglyph_timelines)

4.5.2.74. USERD_get_vglyph_timeline_info

/* -----------------------------------------------------------------------------
* USERD_get_vglyph_timeline_info - Gets the vector glyph timeline metadata.
*                                  Only called if USERD_get_vglyph_counts 
*                                  routine is in the reader, and if
*                                  it returns num_vglyph_vectors > 0 and
*                                  num_vglyph_timelines > 0
* -----------------------------------------------------------------------------
*
* 
* (IN) handle - The USERDHandle pointer created in USERD_reader_open
*
* (IN) vtl               = The vector glyph timeline index
*                           0 ... (Num_VGLYPH_Timelines-1)
*
* (OUT) id               = The vector glyph timeline id listed in the file
*
* (OUT) numtimes         = The number of times in the vector glyph timeline
*
* (OUT) before           = If EnSight time is before the first step in the
*                           vector glyph timeline, a value of
*                           VG_UNDEF makes the glyph undefined
*                           VG_NEAREST makes it act as if it is at the first step
*
* (OUT) amidst           = If EnSight time is between steps in the vector glyph
*                          timeline, VG_INTERPOLATE interpolates values linearly
*                          between them VG_NEAREST snaps to the closest step
*                          for its values.
*
* (OUT) after            = If EnSight time is after the last step in the
*                          vector glyph timeline, a value of
*                          VG_UNDEF makes the glyph undefined
*                          VG_NEAREST makes it act as if it is at the last step
*
* returns: Z_OK if no problems
*          Z_ERR if an error
*
* Notes:
*--------------------------------------------------------------------*/
int
USERD_get_vglyph_timeline_info( USERDHandle handle,
                                  int vtl,
                                  int *id,
                                  int *numtimes,
                                  int *before,
                                  int *amidst,
                                  int *after)

4.5.2.75. USERD_get_vglyph_timeline_times

/* -----------------------------------------------------------------------------
* USERD_get_vglyph_timeline_times - Gets the vector glyph timeline times.
*                                  Only called if USERD_get_vglyph_counts 
*                                  routine is in the reader, and if
*                                  it returns num_vglyph_vectors > 0 and
*                                  num_vglyph_timelines > 0
* 
*-----------------------------------------------------------------------------
*
* (IN) handle - The USERDHandle pointer created in USERD_reader_open
* 
* (IN) vtl                     = The vector glyph timeline index
*                                 0 ... (Num_VGLYPH_Timelines-1)
*
* (OUT) times                  = The array of times in the vector glyph timeline
*
* returns: Z_OK if no problems
*          Z_ERR if an error
*
*--------------------------------------------------------------------*/
int
USERD_get_vglyph_timeline_times( USERDHandle handle,
                                  int vtl,
                                  float *times)

4.5.2.76. USERD_get_vglyph_vector_info

/*-----------------------------------------------------------------------------
*   USERD_get_vglyph_vector_info - Gets the vector glyph metadata
*                                  Only called if USERD_get_vglyph_counts 
*                                  routine is in the reader, and if
*                                  it returns num_vglyph_vectors > 0 
* 
* -----------------------------------------------------------------------------
*
* (IN) handle - The USERDHandle pointer created in USERD_reader_open
* 
* (IN) vg                     = The vector glyph index
*                                 0 ... (Num_VGLYPH_Vectors-1)
*
* (OUT) id                    = The vector glyph id number listed in the file
*
* (OUT) description           = The vector glyph description.
*                               *** Note: This is what a user will see in
*                               the GUI to select the glyph
*
* (OUT) type                  = VG_FORCE or VG_MOMENT
*
* (OUT) time_condition        = VG_STATIC if vector glyph is always present,
*                                     no timeline assiciated with it.
*                               VG_TRANSIENT if vector glyph is associated 
*                                     with a timeline
*
* (OUT) time_line             = The external timeline index of the vector glyph,
*                               used on if time_condition is VG_TRANSIENT
*
* (OUT) part                  = The part that the vector glyph is associated with
*
* (OUT) nidloc                = The node id number where the vector glyph is located.
*                               (must be -1 if not located at a node)
*
* (OUT) eidloc                = The element id number where the vector glyph is
*                               located. (must be -1 if not located at an element)
*
*
* returns: Z_OK if no problems
*          Z_ERR if an error
*
* Notes:
*   For vector glyphs located at an xyz location, make sure both nidloc and
*   eidloc are both set to -1
*--------------------------------------------------------------------*/
int
USERD_get_vglyph_vector_info(USERDHandle handle,
                             int vg,
                             int *id,
                             char *description,
                             int *type,
                             int *time_condition,
                             int *time_line,
                             int *part,
                             int *nidloc,
                             int *eidloc)

4.5.2.77. USERD_get_vglyph_vector_values

/* 
*  USERD_get_vglyph_vector_values - Gets the vector glyph vector component values
*                                  Only called if USERD_get_vglyph_counts 
*                                  routine is in the reader, and if
*                                  it returns num_vglyph_vectors > 0 
* 
*-----------------------------------------------------------------------------
*
* (IN) handle - The USERDHandle pointer created in USERD_reader_open
*
* (IN) vg                     = The vector glyph index
*                               0 ... (Num_VGLYPH_Vectors-1)
*
* (OUT) values                = The vector glyph component vector values
*                               (2D array, with 3 values per timestep)
*
* for VG_STATIC vector glyph, would be 1 x 3 array
* [xc, yc, zc]
*
* for VG_TRANSIENT vector glyph, with a timeline
* that has 5 time steps, would be 5 x 3 array
* [xc1, yc1, zc1]
* [xc2, yc2, zc2]
* [xc3, yc3, zc3]
* [xc4, yc4, zc4]
* [xc5, yc5, zc5]
*
* returns: Z_OK if no problems
*          Z_ERR if an error
*
* Notes:
* This is called if USERD_get_vglyph_vector_info for this vector glyph
*   index sets the nidloc >= 0 or the eidloc >= 0
** Notes:
*--------------------------------------------------------------------*/
int
USERD_get_vglyph_vector_values( USERDHandle handle,
                                    nt vg,
                                    float **values)

4.5.2.78. USERD_get_vglyph_vector_xyzloc

/* -----------------------------------------------------------------------------
* USERD_get_vglyph_vector_xyzloc - Gets the vector glyph xyz locations
*                                  Only called if USERD_get_vglyph_counts 
*                                  routine is in the reader, and if
*                                  it returns num_vglyph_vectors > 0 
* 
*-----------------------------------------------------------------------------
*
* (IN) handle - The USERDHandle pointer created in USERD_reader_open
*
* (IN) vg                         = The vector glyph index
*                                   0 ... (Num_VGLYPH_Vectors-1)
*
* (OUT) xyzloc                    = The vector glyph xyz location(s)
*                                   (2D array, with 3 values per timestep)
*
*                                 for VG_STATIC vector glyph, would be 1 x 3 array
*                                 [x, y, z]
*
*                                 for VG_TRANSIENT vector glyph, with a timeline
*                                   that has 5 time steps, would be 5 x 3 array
*                                   [x1, y1, z1]
*                                   [x2, y2, z2]
*                                   [x3, y3, z3]
*                                   [x4, y4, z4]
*                                   [x5, y5, z5]
*
* returns: Z_OK if no problems
*          Z_ERR if an error
*
* Notes:
* This is called if USERD_get_vglyph_vector_info for this vector glyph
*   index sets the nidloc == -1 and the eidloc == -1
*--------------------------------------------------------------------*/
int
USERD_get_vglyph_vector_xyzloc( USERDHandle handle,
                                        int vg,
                                        float **xyzloc)