nces: netCDF Ensemble Statistics
a familiar operator with new features for group-level ensembles

nces goal: exploit parallelism of ensembles stored in group hierarchies

nces backward-compatible user migration:
deprecate ncea for nces=netCDF ensemble statistics?
deprecate ncra for ncrs=netCDF record   statistics?
give nces two personalities:
where --nsm_grp collapses group ensembles across files into statistics in parent group in output file
      --nsm_fl  collapses file  ensembles              into statistics                 in output file
or use --clp ("collapse"), or ... ?
current ncea becomes synonomous with nces --nsm_fl
optional argument --nsm_sfx="sng" store statistics at same level as members in new group named nsm_nm+"sng"
e.g., nsm_sfx="_avg" or nsm_sfx="_min"

nces design assumptions (some could be relaxed later):
ensemble members are leaf groups
ensemble has at least two members
members of a given ensemble contain identical variables/dimensions/ranks/sizes
different ensembles may have completely different variables
group can be parent of only one ensemble
group can be more distant ancestor (e.g., grandparent) of multiple ensembles
ensemble has one template (tpl) member to set ensemble output definitions/metadata
choice of template member is arbitrary---use first group returned in grp_id list
nsm_nbr and nsm_nm are identical in all following files
mbr_nbr and mbr_nm may _change_ in following files

nces new variables/structure members:

New structure members for variables and groups when prg==ncga:
char *nsm_nm; /* [sng] Ensemble parent group name */ i.e., full path to ensemble parent
nco_bool flg_nsm_tpl; /* [flg] Group is, or variable is in, template member group */
nco_bool flg_nsm_mbr; /* [flg] Group is, or variable is in, ensemble member group */
nco_bool flg_nsm_prn; /* [flg] Group is, or variable is in, ensemble parent group */

New structure members for groups when prg==ncga:
int mbr_nbr; /* [nbr] Number of members of ensemble */ i.e., number in this ensemble in this file
char **mbr_nm; /* [sng] List of member group names */ (size is mbr_nbr)

New structure members for top-levle trv_tbl when prg==ncga:
int nsm_nbr; /* [nbr] Number of ensembles */ i.e., number in first file
char **nsm_nm; /* [sng] List of ensemble parent group names */ (size is nsm_nbr)

nces code flow (details on changes follow):

nco_bld_trv_tbl(): room for new fields. no other changes
nco_bld_nsm(): new. fill-in nsm/mbr/tpl fields
nco_fll_var_trv(): ncga vars in ensembles get only one structure
nco_var_lst_dvd(): ncga rules depend heavily on flg_nsm_tpl
nco_var_prc_fix_trv(): no changes?
nco_xtr_dfn(): ensemble statistics by default defined in grp_nsm_prn
nco_cpy_fix_var_trv(): ncga output group name depends on flg_nsm_tpl

and then main loops like this:

fl_idx=0,fl_nbr-1
  nsm_idx=0,nsm_nbr-1
    nco_nsm_rfr(): new. refresh mbr_nbr, mbr_nm for this ensemble
    mbr_idx=0,mbr_nbr-1
      OpenMP over var loop:
      var_idx=0,nbr_var_prc-1
        if(var->nsm_nm == nsm_nm[nsm_idx]){ensemble statistics}; else skip/continue;

---or---

fl_idx=0,fl_nbr-1
  nco_nsm_rfr(): new. refresh mbr_nbr, mbr_nm for all ensembles
  OpenMP over var loop:
  var_idx=0,nbr_var_prc-1
    mbr_idx=0,mbr_nbr[var_idx]-1
      ensemble statistics (same as ncea)

nces code change details:

nco_bld_trv_tbl() first include/exclude -g -v --unn options. few if any changes.

multiple (nsm_nbr) copies of each output ensemble member are now flagged with flg_xtr

before nco_fll_var_trv() implement new function nco_bld_nsm(), similar to nco_bld_rec_dmn()

nco_bld_nsm() crawls trv_tbl and identifies similar leaf groups as ensemble members
their common parent group is the ensemble parent

nco_bld_nsm() sets flags/variables/arrays in member and parent groups/variables: 

nco_fll_var_trv() exports, for ncga, var list containing only
variables with (!flg_mbr && flg_xtr) and (flg_mbr && flg_nsm_tpl).

nco_var_lst_dvd() for ncga: 
as usual coordinates are typ_fix
variables with flg_nsm_tpl are typ_prc
variables without flg_nsm_tpl are typ_fix. 

nco_xtr_dfn() for ncga:
if !flg_nsm_tpl then grp_nm_fll_out=gpe(grp_nm_fll_in) (same as usual)
if flg_nsm_tpl then grp_nm_fll_out=gpe(grp_nm_nsm_prn)=gpe(grp_nm_fll_in-grp_nm_in)=gpe(grp_nm_fll_in,:-1)

nco_cpy_fix_var_trv() for ncga: 
if !flg_nsm_tpl grp_nm_fll_out=gpe(grp_nm_fll_in) (same as usual)
if flg_nsm_tpl grp_nm_fll_out=gpe(grp_nm_nsm_prn)=gpe(grp_nm_fll_in-grp_nm_in)=gpe(grp_nm_fll_in,:-1)

nco_nsm_rfr(): 
nsm_nbr and nsm_nm never change
for these ensembles, refresh mbr_nbr, mbr_nm once per file
