"Fossies" - the Fresh Open Source Software Archive

Member "netcdf-cxx4-4.3.1/cxx4/ncGroup.cpp" (11 Sep 2019, 53628 Bytes) of package /linux/misc/netcdf-cxx4-4.3.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ncGroup.cpp" see the Fossies "Dox" file reference documentation.

    1 #include "ncGroup.h"
    2 #include "ncVar.h"
    3 #include "ncDim.h"
    4 #include "ncVlenType.h"
    5 #include "ncCompoundType.h"
    6 #include "ncOpaqueType.h"
    7 #include "ncGroupAtt.h"
    8 #include "ncByte.h"
    9 #include "ncUbyte.h"
   10 #include "ncChar.h"
   11 #include "ncShort.h"
   12 #include "ncUshort.h"
   13 #include "ncInt.h"
   14 #include "ncUint.h"
   15 #include "ncInt64.h"
   16 #include "ncUint64.h"
   17 #include "ncFloat.h"
   18 #include "ncDouble.h"
   19 #include "ncString.h"
   20 #include <ncException.h>
   21 #include "ncCheck.h"
   22 using namespace std;
   23 using namespace netCDF::exceptions;
   24 
   25 namespace netCDF {
   26   //  Global comparator operator ==============
   27   // comparator operator
   28   bool operator<(const NcGroup& lhs,const NcGroup& rhs)
   29   {
   30     return false;
   31   }
   32 
   33   // comparator operator
   34   bool operator>(const NcGroup& lhs,const NcGroup& rhs)
   35   {
   36     return true;
   37   }
   38 }
   39 
   40 using namespace netCDF;
   41 
   42 /////////////////////////////////////////////
   43 
   44 NcGroup::~NcGroup()
   45 {
   46 }
   47 
   48 // Constructor generates a null object.
   49 NcGroup::NcGroup() :
   50   nullObject(true),
   51   myId(-1)
   52 {}
   53 
   54 
   55 // constructor
   56 NcGroup::NcGroup(const int groupId) :
   57   nullObject(false),
   58   myId(groupId)
   59 { }
   60 
   61 // assignment operator
   62 NcGroup& NcGroup::operator=(const NcGroup & rhs)
   63 {
   64   nullObject = rhs.nullObject;
   65   myId = rhs.myId;
   66   return *this;
   67 }
   68 
   69 // The copy constructor.
   70 NcGroup::NcGroup(const NcGroup& rhs):
   71   nullObject(rhs.nullObject),
   72   myId(rhs.myId)
   73 {}
   74 
   75 
   76 // equivalence operator
   77 bool NcGroup::operator==(const NcGroup & rhs) const
   78 {
   79   if(nullObject)
   80     return nullObject == rhs.nullObject;
   81   else
   82     return myId == rhs.myId;
   83 }
   84 
   85 //  !=  operator
   86 bool NcGroup::operator!=(const NcGroup & rhs) const
   87 {
   88   return !(*this == rhs);
   89 }
   90 
   91 
   92 // /////////////
   93 // NcGroup-related methods
   94 // /////////////
   95 
   96 // Get the group name.
   97 string NcGroup::getName(bool fullName) const {
   98   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getName on a Null group",__FILE__,__LINE__);
   99   string groupName;
  100   if(fullName){
  101     // return full name of group with foward "/" separarating sub-groups.
  102     size_t lenp;
  103     ncCheck(nc_inq_grpname_len(myId,&lenp),__FILE__,__LINE__);
  104     char* charName= new char[lenp+1];
  105     ncCheck(nc_inq_grpname_full(myId,&lenp,charName),__FILE__,__LINE__);
  106     groupName = charName;
  107     delete charName;
  108   }
  109   else {
  110     // return the (local) name of this group.
  111     char charName[NC_MAX_NAME+1];
  112     ncCheck(nc_inq_grpname(myId,charName),__FILE__,__LINE__);
  113     groupName = charName;
  114   }
  115   return groupName;
  116 }
  117 
  118 // returns true if this is the root group.
  119 bool NcGroup::isRootGroup()  const{
  120   bool result = getName() == "/";
  121   return result;
  122 }
  123 
  124 // Get the parent group.
  125 NcGroup NcGroup::getParentGroup() const {
  126   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getParentGroup on a Null group",__FILE__,__LINE__);
  127   try {
  128     int parentId;
  129     ncCheck(nc_inq_grp_parent(myId,&parentId),__FILE__,__LINE__);
  130     NcGroup ncGroupParent(parentId);
  131     return ncGroupParent;
  132   }
  133   catch (NcEnoGrp& e) {
  134     // no group found, so return null group
  135     return NcGroup();
  136   }
  137 }
  138 
  139 
  140 // Get the group id.
  141 int  NcGroup::getId() const {
  142   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getId on a Null group",__FILE__,__LINE__);
  143   return myId;
  144 }
  145 
  146 // Get the number of NcGroup objects.
  147 int NcGroup::getGroupCount(NcGroup::GroupLocation location) const {
  148   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getGroupCount on a Null group",__FILE__,__LINE__);
  149   // initialize group counter
  150   int ngroups=0;
  151 
  152   // record this group
  153   if(location == ParentsAndCurrentGrps || location == AllGrps) {
  154     ngroups ++;
  155   }
  156 
  157   // number of children in current group
  158   if(location == ChildrenGrps || location == AllChildrenGrps || location == AllGrps ) {
  159     int numgrps;
  160     int* ncids=NULL;
  161     ncCheck(nc_inq_grps(getId(), &numgrps,ncids),__FILE__,__LINE__);
  162     ngroups += numgrps;
  163   }
  164 
  165   // search in parent groups
  166   if(location == ParentsGrps || location == ParentsAndCurrentGrps || location == AllGrps ) {
  167     multimap<string,NcGroup> groups(getGroups(ParentsGrps));
  168     ngroups += groups.size();
  169   }
  170 
  171 
  172   // get the number of all children that are childreof children
  173   if(location == ChildrenOfChildrenGrps || location == AllChildrenGrps || location == AllGrps ) {
  174     multimap<string,NcGroup> groups(getGroups(ChildrenOfChildrenGrps));
  175     ngroups += groups.size();
  176   }
  177 
  178   return ngroups;
  179 }
  180 
  181 
  182 // Get the set of child NcGroup objects.
  183 multimap<std::string,NcGroup> NcGroup::getGroups(NcGroup::GroupLocation location) const {
  184   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getGroups on a Null group",__FILE__,__LINE__);
  185   // create a container to hold the NcGroup's.
  186   multimap<string,NcGroup> ncGroups;
  187 
  188   // record this group
  189   if(location == ParentsAndCurrentGrps || location == AllGrps) {
  190     ncGroups.insert(pair<const string,NcGroup>(getName(),*this));
  191   }
  192 
  193   // the child groups of the current group
  194   if(location == ChildrenGrps || location == AllChildrenGrps || location == AllGrps ) {
  195     // get the number of groups
  196     int groupCount = getGroupCount();
  197     if (groupCount){
  198       vector<int> ncids(groupCount);
  199       int* numgrps=NULL;
  200       // now get the id of each NcGroup and populate the ncGroups container.
  201       ncCheck(nc_inq_grps(myId, numgrps,&ncids[0]),__FILE__,__LINE__);
  202       for(int i=0; i<groupCount;i++){
  203         NcGroup tmpGroup(ncids[i]);
  204         ncGroups.insert(pair<const string,NcGroup>(tmpGroup.getName(),tmpGroup));
  205       }
  206     }
  207   }
  208 
  209   // search in parent groups.
  210   if(location == ParentsGrps || location == ParentsAndCurrentGrps || location == AllGrps ) {
  211     NcGroup tmpGroup(*this);
  212     if(!tmpGroup.isRootGroup()) {
  213       while(1) {
  214     const NcGroup parentGroup(tmpGroup.getParentGroup());
  215     if(parentGroup.isNull()) break;
  216     ncGroups.insert(pair<const string,NcGroup>(parentGroup.getName(),parentGroup));
  217     tmpGroup=parentGroup;
  218       }
  219     }
  220   }
  221 
  222   // search in child groups of the children
  223   if(location == ChildrenOfChildrenGrps || location == AllChildrenGrps || location == AllGrps ) {
  224     multimap<string,NcGroup>::iterator it;
  225     multimap<string,NcGroup> groups(getGroups(ChildrenGrps));
  226     for (it=groups.begin();it!=groups.end();it++) {
  227       multimap<string,NcGroup> childGroups(it->second.getGroups(AllChildrenGrps));
  228       ncGroups.insert(childGroups.begin(),childGroups.end());
  229     }
  230   }
  231 
  232   return ncGroups;
  233 }
  234 
  235 // Get the named child NcGroup object.
  236 NcGroup NcGroup::getGroup(const string& name,NcGroup::GroupLocation location) const{
  237   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getGroup on a Null group",__FILE__,__LINE__);
  238   multimap<string,NcGroup> ncGroups(getGroups(location));
  239   pair<multimap<string,NcGroup>::iterator,multimap<string,NcGroup>::iterator> ret;
  240   ret = ncGroups.equal_range(name);
  241   if(ret.first == ret.second)
  242     return NcGroup();  // null group is returned
  243   else
  244     return ret.first->second;
  245 }
  246 
  247 
  248 
  249 // Get all NcGroup objects with a given name.
  250 set<NcGroup> NcGroup::getGroups(const std::string& name,NcGroup::GroupLocation location) const {
  251   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getGroups on a Null group",__FILE__,__LINE__);
  252   // get the set of ncGroups in this group and above.
  253   multimap<std::string,NcGroup> ncGroups(getGroups(location));
  254   pair<multimap<string,NcGroup>::iterator,multimap<string,NcGroup>::iterator> ret;
  255   multimap<string,NcGroup>::iterator it;
  256   ret = ncGroups.equal_range(name);
  257   set<NcGroup> tmpGroup;
  258   for (it=ret.first; it!=ret.second; ++it) {
  259     tmpGroup.insert(it->second);
  260   }
  261   return tmpGroup;
  262 }
  263 
  264 // Add a new child NcGroup object.
  265 NcGroup NcGroup::addGroup(const string& name) const {
  266   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::addGroup on a Null group",__FILE__,__LINE__);
  267   int new_ncid;
  268   ncCheck(nc_def_grp(myId,const_cast<char*> (name.c_str()),&new_ncid),__FILE__,__LINE__);
  269   return NcGroup(new_ncid);
  270 }
  271 
  272 
  273 
  274 // /////////////
  275 // NcVar-related accessors
  276 // /////////////
  277 
  278 // Get the number of NcVar objects in this group.
  279 int NcGroup::getVarCount(NcGroup::Location location) const {
  280 
  281   // search in current group.
  282   NcGroup tmpGroup(*this);
  283   int nvars=0;
  284   // search in current group
  285   if((location == ParentsAndCurrent || location == ChildrenAndCurrent || location == Current || location ==All) && !tmpGroup.isNull()) {
  286     ncCheck(nc_inq_nvars(tmpGroup.getId(), &nvars),__FILE__,__LINE__);
  287   }
  288 
  289   // search recursively in all parent groups.
  290   if(location == Parents || location == ParentsAndCurrent || location ==All) {
  291     tmpGroup=getParentGroup();
  292     while(!tmpGroup.isNull()) {
  293       int nvarsp;
  294       ncCheck(nc_inq_nvars(tmpGroup.getId(), &nvarsp),__FILE__,__LINE__);
  295       nvars += nvarsp;
  296       // continue loop with the parent.
  297       tmpGroup=tmpGroup.getParentGroup();
  298     }
  299   }
  300 
  301   // search recursively in all child groups
  302   if(location == ChildrenAndCurrent || location == Children || location == All) {
  303     multimap<string,NcGroup>::iterator it;
  304     multimap<string,NcGroup> groups(getGroups());
  305     for (it=groups.begin();it!=groups.end();it++) {
  306       nvars += it->second.getVarCount(ChildrenAndCurrent);
  307     }
  308   }
  309   return nvars;
  310 }
  311 
  312 // Get the collection of NcVar objects.
  313 multimap<std::string,NcVar> NcGroup::getVars(NcGroup::Location location) const {
  314 
  315   // create a container to hold the NcVar's.
  316   multimap<string,NcVar> ncVars;
  317 
  318   // search in current group.
  319   NcGroup tmpGroup(*this);
  320   if((location == ParentsAndCurrent || location == ChildrenAndCurrent || location == Current || location ==All) && !tmpGroup.isNull()) {
  321     // get the number of variables.
  322     int varCount = getVarCount();
  323     if (varCount){
  324       // now get the name of each NcVar object and populate the ncVars container.
  325       int* nvars=NULL;
  326       vector<int> varids(varCount);
  327       ncCheck(nc_inq_varids(myId, nvars,&varids[0]),__FILE__,__LINE__);
  328       for(int i=0; i<varCount;i++){
  329         NcVar tmpVar(*this,varids[i]);
  330         ncVars.insert(pair<const string,NcVar>(tmpVar.getName(),tmpVar));
  331       }
  332     }
  333   }
  334 
  335 
  336   // search recursively in all parent groups.
  337   if(location == Parents || location == ParentsAndCurrent || location ==All) {
  338     tmpGroup=getParentGroup();
  339     while(!tmpGroup.isNull()) {
  340       // get the number of variables
  341       int varCount = tmpGroup.getVarCount();
  342       if (varCount){
  343         // now get the name of each NcVar object and populate the ncVars container.
  344         int* nvars=NULL;
  345         vector<int> varids(varCount);
  346         ncCheck(nc_inq_varids(tmpGroup.getId(), nvars,&varids[0]),__FILE__,__LINE__);
  347         for(int i=0; i<varCount;i++){
  348           NcVar tmpVar(tmpGroup,varids[i]);
  349           ncVars.insert(pair<const string,NcVar>(tmpVar.getName(),tmpVar));
  350         }
  351       }
  352       // continue loop with the parent.
  353       tmpGroup=tmpGroup.getParentGroup();
  354     }
  355   }
  356 
  357   // search recusively in all child groups.
  358   if(location == ChildrenAndCurrent || location == Children  || location == All ) {
  359     multimap<string,NcGroup>::iterator it;
  360     multimap<string,NcGroup> groups(getGroups());
  361     for (it=groups.begin();it!=groups.end();it++) {
  362       multimap<string,NcVar> vars=it->second.getVars(ChildrenAndCurrent);
  363       ncVars.insert(vars.begin(),vars.end());
  364     }
  365   }
  366 
  367   return ncVars;
  368 }
  369 
  370 
  371 // Get all NcVar objects with a given name.
  372 set<NcVar> NcGroup::getVars(const string& name,NcGroup::Location location) const {
  373   // get the set of ncVars in this group and above.
  374   multimap<std::string,NcVar> ncVars(getVars(location));
  375   pair<multimap<string,NcVar>::iterator,multimap<string,NcVar>::iterator> ret;
  376   multimap<string,NcVar>::iterator it;
  377   ret = ncVars.equal_range(name);
  378   set<NcVar> tmpVar;
  379   for (it=ret.first; it!=ret.second; ++it) {
  380     tmpVar.insert(it->second);
  381   }
  382   return tmpVar;
  383 }
  384 
  385 
  386 
  387 // Get the named NcVar object.
  388 NcVar NcGroup::getVar(const string& name,NcGroup::Location location) const {
  389   multimap<std::string,NcVar> ncVars(getVars(location));
  390   pair<multimap<string,NcVar>::iterator,multimap<string,NcVar>::iterator> ret;
  391   ret = ncVars.equal_range(name);
  392   if(ret.first == ret.second)
  393     // no matching netCDF variable found so return null object.
  394     return NcVar();
  395   else
  396     return ret.first->second;
  397 }
  398 
  399 // Adds a new netCDF scalar variable.
  400 NcVar NcGroup::addVar(const std::string& name, const NcType& ncType) const {
  401   return NcGroup::addVar(name, ncType, std::vector<NcDim>());
  402 }
  403 
  404 // Add a new netCDF variable.
  405 NcVar NcGroup::addVar(const string& name, const string& typeName, const string& dimName) const {
  406   ncCheckDefineMode(myId);
  407 
  408   // get an NcType object with the given type name.
  409   NcType tmpType(getType(typeName,NcGroup::ParentsAndCurrent));
  410   if(tmpType.isNull()) throw NcNullType("Attempt to invoke NcGroup::addVar failed: typeName must be defined in either the current group or a parent group",__FILE__,__LINE__);
  411 
  412   // get a NcDim object with the given dimension name
  413   NcDim tmpDim(getDim(dimName,NcGroup::ParentsAndCurrent));
  414   if(tmpDim.isNull()) throw NcNullDim("Attempt to invoke NcGroup::addVar failed: dimName must be defined in either the current group or a parent group",__FILE__,__LINE__);
  415 
  416   // finally define a new netCDF  variable
  417   int varId;
  418   int dimId(tmpDim.getId());
  419   ncCheck(nc_def_var(myId,name.c_str(),tmpType.getId(),1,&dimId,&varId),__FILE__,__LINE__);
  420   // return an NcVar object for this new variable
  421   return NcVar(*this,varId);
  422 }
  423 
  424 
  425 // Add a new netCDF variable.
  426 NcVar NcGroup::addVar(const string& name, const NcType& ncType, const NcDim& ncDim) const {
  427   ncCheckDefineMode(myId);
  428 
  429   // check NcType object is valid
  430   if(ncType.isNull()) throw NcNullType("Attempt to invoke NcGroup::addVar with a Null NcType object",__FILE__,__LINE__);
  431   NcType tmpType(getType(ncType.getName(),NcGroup::ParentsAndCurrent));
  432   if(tmpType.isNull()) throw NcNullType("Attempt to invoke NcGroup::addVar failed: NcType must be defined in either the current group or a parent group",__FILE__,__LINE__);
  433 
  434   // check NcDim object is valid
  435   if(ncDim.isNull()) throw NcNullDim("Attempt to invoke NcGroup::addVar with a Null NcDim object",__FILE__,__LINE__);
  436   NcDim tmpDim(getDim(ncDim.getName(),NcGroup::ParentsAndCurrent));
  437   if(tmpDim.isNull()) throw NcNullDim("Attempt to invoke NcGroup::addVar failed: NcDim must be defined in either the current group or a parent group",__FILE__,__LINE__);
  438 
  439   // finally define a new netCDF variable
  440   int varId;
  441   int dimId(tmpDim.getId());
  442   ncCheck(nc_def_var(myId,name.c_str(),tmpType.getId(),1,&dimId,&varId),__FILE__,__LINE__);
  443   // return an NcVar object for this new variable
  444   return NcVar(*this,varId);
  445 }
  446 
  447 
  448 // Add a new netCDF multi-dimensional variable.
  449 NcVar NcGroup::addVar(const string& name, const string& typeName, const vector<string>& dimNames) const {
  450   ncCheckDefineMode(myId);
  451 
  452   // get an NcType object with the given name.
  453   NcType tmpType(getType(typeName,NcGroup::ParentsAndCurrent));
  454   if(tmpType.isNull()) throw NcNullType("Attempt to invoke NcGroup::addVar failed: typeName must be defined in either the current group or a parent group",__FILE__,__LINE__);
  455 
  456   // get a set of NcDim objects corresponding to the given dimension names.
  457   vector<int> dimIds;
  458   dimIds.reserve(dimNames.size());
  459   for (size_t i=0; i<dimNames.size();i++){
  460     NcDim tmpDim(getDim(dimNames[i],NcGroup::ParentsAndCurrent));
  461     if(tmpDim.isNull()) throw NcNullDim("Attempt to invoke NcGroup::addVar failed: dimNames must be defined in either the current group or a parent group",__FILE__,__LINE__);
  462     dimIds.push_back(tmpDim.getId());
  463   }
  464 
  465   // finally define a new netCDF variable
  466   int varId;
  467   int *dimIdsPtr = dimIds.empty() ? 0 : &dimIds[0];
  468   ncCheck(nc_def_var(myId,name.c_str(),tmpType.getId(),dimIds.size(), dimIdsPtr,&varId),__FILE__,__LINE__);
  469   // return an NcVar object for this new variable
  470   return NcVar(*this,varId);
  471 }
  472 
  473 // Add a new netCDF multi-dimensional variable.
  474 NcVar NcGroup::addVar(const string& name, const NcType& ncType, const vector<NcDim>& ncDimVector) const {
  475   ncCheckDefineMode(myId);
  476 
  477   // check NcType object is valid
  478   if(ncType.isNull()) throw NcNullType("Attempt to invoke NcGroup::addVar with a Null NcType object",__FILE__,__LINE__);
  479   NcType tmpType(getType(ncType.getName(),NcGroup::ParentsAndCurrent));
  480   if(tmpType.isNull()) throw NcNullType("Attempt to invoke NcGroup::addVar failed: NcType must be defined in either the current group or a parent group",__FILE__,__LINE__);
  481 
  482   // check NcDim objects are valid
  483   vector<NcDim>::const_iterator iter;
  484   vector<int> dimIds;
  485   dimIds.reserve(ncDimVector.size());
  486   for (iter=ncDimVector.begin();iter < ncDimVector.end(); iter++) {
  487     if(iter->isNull()) throw NcNullDim("Attempt to invoke NcGroup::addVar with a Null NcDim object",__FILE__,__LINE__);
  488     NcDim tmpDim(getDim(iter->getName(),NcGroup::ParentsAndCurrent));
  489     if(tmpDim.isNull()) throw NcNullDim("Attempt to invoke NcGroup::addVar failed: NcDim must be defined in either the current group or a parent group",__FILE__,__LINE__);
  490     dimIds.push_back(tmpDim.getId());
  491   }
  492 
  493   // finally define a new netCDF variable
  494   int varId;
  495   int *dimIdsPtr = dimIds.empty() ? 0 : &dimIds[0];
  496   ncCheck(nc_def_var(myId,name.c_str(),tmpType.getId(),dimIds.size(), dimIdsPtr,&varId),__FILE__,__LINE__);
  497   // return an NcVar object for this new variable
  498   return NcVar(*this,varId);
  499 }
  500 
  501 
  502 // /////////////
  503 // NcAtt-related methods
  504 // /////////////
  505 
  506 // Get the number of group attributes.
  507 int NcGroup::getAttCount(NcGroup::Location location) const {
  508 
  509   // search in current group.
  510   NcGroup tmpGroup(*this);
  511   int ngatts=0;
  512   // search in current group
  513   if((location == ParentsAndCurrent || location == ChildrenAndCurrent || location == Current || location ==All) && !tmpGroup.isNull()) {
  514     ncCheck(nc_inq_natts(tmpGroup.getId(), &ngatts),__FILE__,__LINE__);
  515   }
  516 
  517   // search recursively in all parent groups.
  518   if(location == Parents || location == ParentsAndCurrent || location ==All) {
  519     tmpGroup=getParentGroup();
  520     while(!tmpGroup.isNull()) {
  521       int ngattsp;
  522       ncCheck(nc_inq_natts(tmpGroup.getId(), &ngattsp),__FILE__,__LINE__);
  523       ngatts += ngattsp;
  524       // continue loop with the parent.
  525       tmpGroup=tmpGroup.getParentGroup();
  526     }
  527   }
  528 
  529   // search recursively in all child groups
  530   if(location == ChildrenAndCurrent || location == Children || location == All) {
  531     multimap<string,NcGroup>::iterator it;
  532     multimap<string,NcGroup> groups(getGroups());
  533     for (it=groups.begin();it!=groups.end();it++) {
  534       ngatts += it->second.getAttCount(ChildrenAndCurrent);
  535     }
  536   }
  537 
  538   return ngatts;
  539 }
  540 
  541 // Get the collection of NcGroupAtt objects.
  542 multimap<std::string,NcGroupAtt> NcGroup::getAtts(NcGroup::Location location) const {
  543 
  544   // create a container to hold the NcAtt's.
  545   multimap<string,NcGroupAtt> ncAtts;
  546 
  547   // search in current group.
  548   NcGroup tmpGroup(*this);
  549   if((location == ParentsAndCurrent || location == ChildrenAndCurrent || location == Current || location ==All) && !tmpGroup.isNull()) {
  550     // get the number of attributes
  551     int attCount = tmpGroup.getAttCount();
  552     // now get the name of each NcAtt and populate the ncAtts container.
  553     for(int i=0; i<attCount;i++){
  554       char charName[NC_MAX_NAME+1];
  555       ncCheck(nc_inq_attname(tmpGroup.getId(),NC_GLOBAL,i,charName),__FILE__,__LINE__);
  556       NcGroupAtt tmpAtt(tmpGroup.getId(),i);
  557       ncAtts.insert(pair<const string,NcGroupAtt>(string(charName),tmpAtt));
  558     }
  559   }
  560 
  561   // search recursively in all parent groups.
  562   if(location == Parents || location == ParentsAndCurrent || location ==All) {
  563     tmpGroup=getParentGroup();
  564     while(!tmpGroup.isNull()) {
  565       // get the number of attributes
  566       int attCount = tmpGroup.getAttCount();
  567       // now get the name of each NcAtt and populate the ncAtts container.
  568       for(int i=0; i<attCount;i++){
  569         char charName[NC_MAX_NAME+1];
  570         ncCheck(nc_inq_attname(tmpGroup.getId(),NC_GLOBAL,i,charName),__FILE__,__LINE__);
  571         NcGroupAtt tmpAtt(tmpGroup.getId(),i);
  572         ncAtts.insert(pair<const string,NcGroupAtt>(string(charName),tmpAtt));
  573       }
  574       // continue loop with the parent.
  575       tmpGroup=tmpGroup.getParentGroup();
  576     }
  577   }
  578 
  579   // search recusively in all child groups.
  580   if(location == ChildrenAndCurrent || location == Children  || location == All ) {
  581     multimap<string,NcGroup>::iterator it;
  582     multimap<string,NcGroup> groups(getGroups());
  583     for (it=groups.begin();it!=groups.end();it++) {
  584       multimap<string,NcGroupAtt> atts=it->second.getAtts(ChildrenAndCurrent);
  585       ncAtts.insert(atts.begin(),atts.end());
  586     }
  587   }
  588 
  589   return ncAtts;
  590 }
  591 
  592 // Get the named NcGroupAtt object.
  593 NcGroupAtt NcGroup::getAtt(const std::string& name,NcGroup::Location location) const {
  594   multimap<std::string,NcGroupAtt> ncAtts(getAtts(location));
  595   pair<multimap<string,NcGroupAtt>::iterator,multimap<string,NcGroupAtt>::iterator> ret;
  596   ret = ncAtts.equal_range(name);
  597   if(ret.first == ret.second)
  598     // no matching groupAttribute so return null object.
  599     return NcGroupAtt();
  600   else
  601     return ret.first->second;
  602 }
  603 
  604 // Get all NcGroupAtt objects with a given name.
  605 set<NcGroupAtt> NcGroup::getAtts(const string& name,NcGroup::Location location) const {
  606   // get the set of ncGroupAtts in this group and above.
  607   multimap<std::string,NcGroupAtt> ncAtts(getAtts(location));
  608   pair<multimap<string,NcGroupAtt>::iterator,multimap<string,NcGroupAtt>::iterator> ret;
  609   multimap<string,NcGroupAtt>::iterator it;
  610   ret = ncAtts.equal_range(name);
  611   set<NcGroupAtt> tmpAtt;
  612   for (it=ret.first; it!=ret.second; ++it) {
  613     tmpAtt.insert(it->second);
  614   }
  615   return tmpAtt;
  616 }
  617 
  618 
  619 
  620 
  621 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  622 NcGroupAtt NcGroup::putAtt(const string& name, const string& dataValues) const {
  623   ncCheckDefineMode(myId);
  624   ncCheck(nc_put_att_text(myId,NC_GLOBAL,name.c_str(),dataValues.size(),dataValues.c_str()),__FILE__,__LINE__);
  625   // finally instantiate this attribute and return
  626   return getAtt(name);
  627 }
  628 
  629 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  630 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, size_t len, const unsigned char* dataValues) const {
  631   ncCheckDefineMode(myId);
  632   NcType::ncType typeClass(type.getTypeClass());
  633   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  634     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  635   else
  636     ncCheck(nc_put_att_uchar(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  637   // finally instantiate this attribute and return
  638   return getAtt(name);
  639 }
  640 
  641 
  642 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  643 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, size_t len, const signed char* dataValues) const {
  644   ncCheckDefineMode(myId);
  645   NcType::ncType typeClass(type.getTypeClass());
  646   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  647     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  648   else
  649     ncCheck(nc_put_att_schar(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  650   // finally instantiate this attribute and return
  651   return getAtt(name);
  652 }
  653 
  654 
  655 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  656 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, short datumValue) const {
  657   ncCheckDefineMode(myId);
  658   NcType::ncType typeClass(type.getTypeClass());
  659   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  660     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  661   else
  662     ncCheck(nc_put_att_short(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  663   // finally instantiate this attribute and return
  664   return getAtt(name);
  665 }
  666 
  667 
  668 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  669 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, int datumValue) const {
  670   ncCheckDefineMode(myId);
  671   NcType::ncType typeClass(type.getTypeClass());
  672   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  673     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  674   else
  675     ncCheck(nc_put_att_int(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  676   // finally instantiate this attribute and return
  677   return getAtt(name);
  678 }
  679 
  680 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  681 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, long datumValue) const {
  682   ncCheckDefineMode(myId);
  683   NcType::ncType typeClass(type.getTypeClass());
  684   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  685     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  686   else
  687     ncCheck(nc_put_att_long(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  688   // finally instantiate this attribute and return
  689   return getAtt(name);
  690 }
  691 
  692 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  693 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, float datumValue) const {
  694   ncCheckDefineMode(myId);
  695   NcType::ncType typeClass(type.getTypeClass());
  696   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  697     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  698   else
  699     ncCheck(nc_put_att_float(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  700   // finally instantiate this attribute and return
  701   return getAtt(name);
  702 }
  703 
  704 
  705 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  706 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, double datumValue) const {
  707   ncCheckDefineMode(myId);
  708   NcType::ncType typeClass(type.getTypeClass());
  709   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  710     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  711   else
  712     ncCheck(nc_put_att_double(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  713   // finally instantiate this attribute and return
  714   return getAtt(name);
  715 }
  716 
  717 
  718 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  719 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, unsigned short datumValue) const {
  720   ncCheckDefineMode(myId);
  721   NcType::ncType typeClass(type.getTypeClass());
  722   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  723     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  724   else
  725     ncCheck(nc_put_att_ushort(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  726   // finally instantiate this attribute and return
  727   return getAtt(name);
  728 }
  729 
  730 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  731 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, unsigned int datumValue) const {
  732   ncCheckDefineMode(myId);
  733   NcType::ncType typeClass(type.getTypeClass());
  734   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  735     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  736   else
  737     ncCheck(nc_put_att_uint(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  738   // finally instantiate this attribute and return
  739   return getAtt(name);
  740 }
  741 
  742 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  743 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, long long datumValue) const {
  744   ncCheckDefineMode(myId);
  745   NcType::ncType typeClass(type.getTypeClass());
  746   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  747     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  748   else
  749     ncCheck(nc_put_att_longlong(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  750   // finally instantiate this attribute and return
  751   return getAtt(name);
  752 }
  753 
  754 
  755 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  756 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, unsigned long long datumValue) const {
  757   ncCheckDefineMode(myId);
  758   NcType::ncType typeClass(type.getTypeClass());
  759   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  760     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  761   else
  762     ncCheck(nc_put_att_ulonglong(myId,NC_GLOBAL,name.c_str(),type.getId(),1,&datumValue),__FILE__,__LINE__);
  763   // finally instantiate this attribute and return
  764   return getAtt(name);
  765 }
  766 
  767 
  768 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  769 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, size_t len, const short* dataValues) const {
  770   ncCheckDefineMode(myId);
  771   NcType::ncType typeClass(type.getTypeClass());
  772   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  773     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  774   else
  775     ncCheck(nc_put_att_short(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  776   // finally instantiate this attribute and return
  777   return getAtt(name);
  778 }
  779 
  780 
  781 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  782 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, size_t len, const int* dataValues) const {
  783   ncCheckDefineMode(myId);
  784   NcType::ncType typeClass(type.getTypeClass());
  785   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  786     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  787   else
  788     ncCheck(nc_put_att_int(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  789   // finally instantiate this attribute and return
  790   return getAtt(name);
  791 }
  792 
  793 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  794 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, size_t len, const long* dataValues) const {
  795   ncCheckDefineMode(myId);
  796   NcType::ncType typeClass(type.getTypeClass());
  797   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  798     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  799   else
  800     ncCheck(nc_put_att_long(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  801   // finally instantiate this attribute and return
  802   return getAtt(name);
  803 }
  804 
  805 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  806 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, size_t len, const float* dataValues) const {
  807   ncCheckDefineMode(myId);
  808   NcType::ncType typeClass(type.getTypeClass());
  809   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  810     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  811   else
  812     ncCheck(nc_put_att_float(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  813   // finally instantiate this attribute and return
  814   return getAtt(name);
  815 }
  816 
  817 
  818 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  819 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, size_t len, const double* dataValues) const {
  820   ncCheckDefineMode(myId);
  821   NcType::ncType typeClass(type.getTypeClass());
  822   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  823     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  824   else
  825     ncCheck(nc_put_att_double(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  826   // finally instantiate this attribute and return
  827   return getAtt(name);
  828 }
  829 
  830 
  831 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  832 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, size_t len, const unsigned short* dataValues) const {
  833   ncCheckDefineMode(myId);
  834   NcType::ncType typeClass(type.getTypeClass());
  835   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  836     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  837   else
  838     ncCheck(nc_put_att_ushort(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  839   // finally instantiate this attribute and return
  840   return getAtt(name);
  841 }
  842 
  843 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  844 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, size_t len, const unsigned int* dataValues) const {
  845   ncCheckDefineMode(myId);
  846   NcType::ncType typeClass(type.getTypeClass());
  847   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  848     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  849   else
  850     ncCheck(nc_put_att_uint(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  851   // finally instantiate this attribute and return
  852   return getAtt(name);
  853 }
  854 
  855 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  856 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, size_t len, const long long* dataValues) const {
  857   ncCheckDefineMode(myId);
  858   NcType::ncType typeClass(type.getTypeClass());
  859   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  860     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  861   else
  862     ncCheck(nc_put_att_longlong(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  863   // finally instantiate this attribute and return
  864   return getAtt(name);
  865 }
  866 
  867 
  868 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  869 NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, size_t len, const unsigned long long* dataValues) const {
  870   ncCheckDefineMode(myId);
  871   NcType::ncType typeClass(type.getTypeClass());
  872   if(typeClass == NcType::nc_VLEN || typeClass == NcType::nc_OPAQUE || typeClass == NcType::nc_ENUM || typeClass == NcType::nc_COMPOUND)
  873     ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  874   else
  875     ncCheck(nc_put_att_ulonglong(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  876   // finally instantiate this attribute and return
  877   return getAtt(name);
  878 }
  879 
  880 
  881 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  882 NcGroupAtt NcGroup::putAtt(const string& name, size_t len, const char** dataValues) const {
  883   ncCheckDefineMode(myId);
  884   ncCheck(nc_put_att_string(myId,NC_GLOBAL,name.c_str(),len,dataValues),__FILE__,__LINE__);
  885   // finally instantiate this attribute and return
  886   return getAtt(name);
  887 }
  888 
  889 //  Creates a new NetCDF group attribute or if already exisiting replaces it.
  890  NcGroupAtt NcGroup::putAtt(const string& name, const NcType& type, size_t len, const void* dataValues) const {
  891   ncCheckDefineMode(myId);
  892   ncCheck(nc_put_att(myId,NC_GLOBAL,name.c_str(),type.getId(),len,dataValues),__FILE__,__LINE__);
  893   // finally instantiate this attribute and return
  894   return getAtt(name);
  895 }
  896 
  897 
  898 
  899 // /////////////
  900 // NcDim-related methods
  901 // /////////////
  902 
  903 // Get the number of NcDim objects.
  904 int NcGroup::getDimCount(NcGroup::Location location) const {
  905   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getDimCount on a Null group",__FILE__,__LINE__);
  906 
  907   // intialize counter
  908   int ndims=0;
  909 
  910   // search in current group
  911   if(location == Current || location == ParentsAndCurrent || location == ChildrenAndCurrent || location == All ) {
  912     int ndimsp;
  913     ncCheck(nc_inq_ndims(getId(), &ndimsp),__FILE__,__LINE__);
  914     ndims += ndimsp;
  915   }
  916 
  917   // search in parent groups.
  918   if(location == Parents || location == ParentsAndCurrent || location == All ) {
  919     multimap<string,NcGroup>::iterator it;
  920     multimap<string,NcGroup> groups(getGroups(ParentsGrps));
  921     for (it=groups.begin();it!=groups.end();it++) {
  922       ndims += it->second.getDimCount();
  923     }
  924   }
  925 
  926   // search in child groups.
  927   if(location == Children || location == ChildrenAndCurrent || location == All ) {
  928     multimap<string,NcGroup>::iterator it;
  929     multimap<string,NcGroup> groups(getGroups(AllChildrenGrps));
  930     for (it=groups.begin();it!=groups.end();it++) {
  931       ndims += it->second.getDimCount();
  932     }
  933   }
  934   return ndims;
  935 }
  936 
  937 
  938 // Get the set of NcDim objects.
  939 multimap<string,NcDim> NcGroup::getDims(NcGroup::Location location) const {
  940   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getDims on a Null group",__FILE__,__LINE__);
  941   // create a container to hold the NcDim's.
  942   multimap<string,NcDim> ncDims;
  943 
  944   // search in current group
  945   if(location == Current || location == ParentsAndCurrent || location == ChildrenAndCurrent || location == All ) {
  946     int dimCount = getDimCount();
  947     if (dimCount){
  948       vector<int> dimids(dimCount);
  949       ncCheck(nc_inq_dimids(getId(), &dimCount, &dimids[0], 0),__FILE__,__LINE__);
  950       // now get the name of each NcDim and populate the nDims container.
  951       for(int i=0; i<dimCount;i++){
  952         NcDim tmpDim(*this,dimids[i]);
  953         ncDims.insert(pair<const string,NcDim>(tmpDim.getName(),tmpDim));
  954       }
  955     }
  956   }
  957 
  958   // search in parent groups.
  959   if(location == Parents || location == ParentsAndCurrent || location == All ) {
  960     multimap<string,NcGroup>::iterator it;
  961     multimap<string,NcGroup> groups(getGroups(ParentsGrps));
  962     for (it=groups.begin();it!=groups.end();it++) {
  963       multimap<string,NcDim> dimTmp(it->second.getDims());
  964       ncDims.insert(dimTmp.begin(),dimTmp.end());
  965     }
  966   }
  967 
  968   // search in child groups (makes recursive calls).
  969   if(location == Children || location == ChildrenAndCurrent || location == All ) {
  970     multimap<string,NcGroup>::iterator it;
  971     multimap<string,NcGroup> groups(getGroups(AllChildrenGrps));
  972     for (it=groups.begin();it!=groups.end();it++) {
  973       multimap<string,NcDim> dimTmp(it->second.getDims());
  974       ncDims.insert(dimTmp.begin(),dimTmp.end());
  975     }
  976   }
  977 
  978   return ncDims;
  979 }
  980 
  981 
  982 
  983 // Get the named NcDim object.
  984 NcDim NcGroup::getDim(const string& name,NcGroup::Location location) const {
  985   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getDim on a Null group",__FILE__,__LINE__);
  986   multimap<string,NcDim> ncDims(getDims(location));
  987   pair<multimap<string,NcDim>::iterator,multimap<string,NcDim>::iterator> ret;
  988   ret = ncDims.equal_range(name);
  989   if(ret.first == ret.second)
  990     return NcDim(); // null group is returned
  991   else
  992     return ret.first->second;
  993 }
  994 
  995 
  996 // Get all NcDim objects with a given name.
  997 set<NcDim> NcGroup::getDims(const string& name,NcGroup::Location location) const {
  998   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getDims on a Null group",__FILE__,__LINE__);
  999   // get the set of ncDims in this group and above.
 1000   multimap<string,NcDim> ncDims(getDims(location));
 1001   pair<multimap<string,NcDim>::iterator,multimap<string,NcDim>::iterator> ret;
 1002   multimap<string,NcDim>::iterator it;
 1003   ret = ncDims.equal_range(name);
 1004   set<NcDim> tmpDim;
 1005   for (it=ret.first; it!=ret.second; ++it) {
 1006     tmpDim.insert(it->second);
 1007   }
 1008   return tmpDim;
 1009 }
 1010 
 1011 // Add a new NcDim object.
 1012 NcDim NcGroup::addDim(const string& name, size_t dimSize) const {
 1013   ncCheckDefineMode(myId);
 1014   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::addDim on a Null group",__FILE__,__LINE__);
 1015   int dimId;
 1016   ncCheck(nc_def_dim(myId,name.c_str(),dimSize,&dimId),__FILE__,__LINE__);
 1017   // finally return NcDim object for this new variable
 1018   return NcDim(*this,dimId);
 1019 }
 1020 
 1021 // Add a new NcDim object with unlimited size..
 1022 NcDim NcGroup::addDim(const string& name) const {
 1023   ncCheckDefineMode(myId);
 1024   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::addDim on a Null group",__FILE__,__LINE__);
 1025   int dimId;
 1026   ncCheck(nc_def_dim(myId,name.c_str(),NC_UNLIMITED,&dimId),__FILE__,__LINE__);
 1027   // finally return NcDim object for this new variable
 1028   return NcDim(*this,dimId);
 1029 }
 1030 
 1031 
 1032 
 1033 
 1034 
 1035 // /////////////
 1036 // type-object related methods
 1037 // /////////////
 1038 
 1039 // Gets the number of type objects.
 1040 int NcGroup::getTypeCount(NcGroup::Location location) const {
 1041 
 1042   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getTypeCount on a Null group",__FILE__,__LINE__);
 1043 
 1044   // intialize counter
 1045   int ntypes=0;
 1046 
 1047   // search in current group
 1048   if(location == Current || location == ParentsAndCurrent || location == ChildrenAndCurrent || location == All ) {
 1049     int ntypesp;
 1050     int* typeidsp=NULL;
 1051     ncCheck(nc_inq_typeids(getId(), &ntypesp,typeidsp),__FILE__,__LINE__);
 1052     ntypes+= ntypesp;
 1053   }
 1054 
 1055   // search in parent groups.
 1056   if(location == Parents || location == ParentsAndCurrent || location == All ) {
 1057     multimap<string,NcGroup>::iterator it;
 1058     multimap<string,NcGroup> groups(getGroups(ParentsGrps));
 1059     for (it=groups.begin();it!=groups.end();it++) {
 1060       ntypes += it->second.getTypeCount();
 1061     }
 1062   }
 1063 
 1064   // search in child groups.
 1065   if(location == Children || location == ChildrenAndCurrent || location == All ) {
 1066     multimap<string,NcGroup>::iterator it;
 1067     multimap<string,NcGroup> groups(getGroups(AllChildrenGrps));
 1068     for (it=groups.begin();it!=groups.end();it++) {
 1069       ntypes += it->second.getTypeCount();
 1070     }
 1071   }
 1072   return ntypes;
 1073 }
 1074 
 1075 
 1076 
 1077 // Gets the number of type objects with a given enumeration type.
 1078 int NcGroup::getTypeCount(NcType::ncType enumType, NcGroup::Location location) const {
 1079 
 1080   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getTypeCount on a Null group",__FILE__,__LINE__);
 1081 
 1082   // intialize counter
 1083   int ntypes=0;
 1084 
 1085   // search in current group
 1086   if(location == Current || location == ParentsAndCurrent || location == ChildrenAndCurrent || location == All ) {
 1087     int ntypesp;
 1088     int* typeidsp=NULL;
 1089     ncCheck(nc_inq_typeids(getId(), &ntypesp,typeidsp),__FILE__,__LINE__);
 1090     if (ntypesp){
 1091       vector<int> typeids(ntypesp);
 1092       ncCheck(nc_inq_typeids(getId(), &ntypesp,&typeids[0]),__FILE__,__LINE__);
 1093       for (int i=0; i<ntypesp;i++){
 1094         NcType tmpType(*this,typeids[i]);
 1095         if(tmpType.getTypeClass() == enumType) ntypes++;
 1096       }
 1097     }
 1098   }
 1099 
 1100   // search in parent groups.
 1101   if(location == Parents || location == ParentsAndCurrent || location == All ) {
 1102     multimap<string,NcGroup>::iterator it;
 1103     multimap<string,NcGroup> groups(getGroups(ParentsGrps));
 1104     for (it=groups.begin();it!=groups.end();it++) {
 1105       ntypes += it->second.getTypeCount(enumType);
 1106     }
 1107   }
 1108 
 1109   // search in child groups.
 1110   if(location == Children || location == ChildrenAndCurrent || location == All ) {
 1111     multimap<string,NcGroup>::iterator it;
 1112     multimap<string,NcGroup> groups(getGroups(AllChildrenGrps));
 1113     for (it=groups.begin();it!=groups.end();it++) {
 1114       ntypes += it->second.getTypeCount(enumType);
 1115     }
 1116   }
 1117   return ntypes;
 1118 }
 1119 
 1120 
 1121 // Gets the collection of NcType objects.
 1122 multimap<string,NcType> NcGroup::getTypes(NcGroup::Location location) const {
 1123   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getTypes on a Null group",__FILE__,__LINE__);
 1124   // create a container to hold the NcType's.
 1125   multimap<string,NcType> ncTypes;
 1126 
 1127   // search in current group
 1128   if(location == Current || location == ParentsAndCurrent || location == ChildrenAndCurrent || location == All ) {
 1129     int typeCount = getTypeCount();
 1130     if (typeCount){
 1131       vector<int> typeids(typeCount);
 1132       ncCheck(nc_inq_typeids(getId(), &typeCount,&typeids[0]),__FILE__,__LINE__);
 1133       // now get the name of each NcType and populate the nTypes container.
 1134       for(int i=0; i<typeCount;i++){
 1135         NcType tmpType(*this,typeids[i]);
 1136         ncTypes.insert(pair<const string,NcType>(tmpType.getName(),tmpType));
 1137       }
 1138     }
 1139   }
 1140 
 1141   // search in parent groups.
 1142   if(location == Parents || location == ParentsAndCurrent || location == All ) {
 1143     multimap<string,NcGroup>::iterator it;
 1144     multimap<string,NcGroup> groups(getGroups(ParentsGrps));
 1145     for (it=groups.begin();it!=groups.end();it++) {
 1146       multimap<string,NcType> typeTmp(it->second.getTypes());
 1147       ncTypes.insert(typeTmp.begin(),typeTmp.end());
 1148     }
 1149   }
 1150 
 1151   // search in child groups (makes recursive calls).
 1152   if(location == Children || location == ChildrenAndCurrent || location == All ) {
 1153     multimap<string,NcGroup>::iterator it;
 1154     multimap<string,NcGroup> groups(getGroups(AllChildrenGrps));
 1155     for (it=groups.begin();it!=groups.end();it++) {
 1156       multimap<string,NcType> typeTmp(it->second.getTypes());
 1157       ncTypes.insert(typeTmp.begin(),typeTmp.end());
 1158     }
 1159   }
 1160 
 1161   return ncTypes;
 1162 }
 1163 
 1164 
 1165 // Gets the collection of NcType objects with a given name.
 1166 set<NcType> NcGroup::getTypes(const string& name, NcGroup::Location location) const {
 1167   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getTypes on a Null group",__FILE__,__LINE__);
 1168   // iterator for the multimap container.
 1169   multimap<string,NcType>::iterator it;
 1170   // return argument of equal_range: iterators to lower and upper bounds of the range.
 1171   pair<multimap<string,NcType>::iterator,multimap<string,NcType>::iterator> ret;
 1172   // get the entire collection of types.
 1173   multimap<string,NcType> types(getTypes(location));
 1174   // define STL set object to hold the result
 1175   set<NcType> tmpType;
 1176   // get the set of NcType objects with a given name
 1177   ret=types.equal_range(name);
 1178   for (it=ret.first;it!=ret.second;it++) {
 1179     tmpType.insert(it->second);
 1180   }
 1181   return tmpType;
 1182 }
 1183 
 1184 
 1185 // Gets the collection of NcType objects with a given data type.
 1186 set<NcType> NcGroup::getTypes(NcType::ncType enumType, NcGroup::Location location) const {
 1187   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getTypes on a Null group",__FILE__,__LINE__);
 1188   // iterator for the multimap container.
 1189   multimap<string,NcType>::iterator it;
 1190   // get the entire collection of types.
 1191   multimap<string,NcType> types(getTypes(location));
 1192   // define STL set object to hold the result
 1193   set<NcType> tmpType;
 1194   // get the set of NcType objects with a given data type
 1195   for (it=types.begin();it!=types.end();it++) {
 1196     if(it->second.getTypeClass() == enumType) {
 1197       tmpType.insert(it->second);
 1198     }
 1199   }
 1200   return(tmpType);
 1201 }
 1202 
 1203 
 1204 // Gets the collection of NcType objects with a given name and data type.
 1205 set<NcType> NcGroup::getTypes(const string& name, NcType::ncType enumType, NcGroup::Location location) const {
 1206   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getTypes on a Null group",__FILE__,__LINE__);
 1207   // iterator for the multimap container.
 1208   multimap<string,NcType>::iterator it;
 1209   // return argument of equal_range: iterators to lower and upper bounds of the range.
 1210   pair<multimap<string,NcType>::iterator,multimap<string,NcType>::iterator> ret;
 1211   // get the entire collection of types.
 1212   multimap<string,NcType> types(getTypes(location));
 1213   // define STL set object to hold the result
 1214   set<NcType> tmpType;
 1215   // get the set of NcType objects with a given name
 1216   ret=types.equal_range(name);
 1217   for (it=ret.first;it!=ret.second;it++) {
 1218     if((*it).second.getTypeClass() == enumType) {
 1219       tmpType.insert(it->second);
 1220     }
 1221   }
 1222   return(tmpType);
 1223 }
 1224 
 1225 
 1226 // Gets the NcType object with a given name.
 1227 NcType NcGroup::getType(const string& name, NcGroup::Location location) const {
 1228   if(isNull()) throw NcNullGrp("Attempt to invoke NcGroup::getType on a Null group",__FILE__,__LINE__);
 1229   if(name ==  "byte"    ) return ncByte;
 1230   if(name ==  "ubyte"   ) return ncUbyte;
 1231   if(name ==  "char"    ) return ncChar;
 1232   if(name ==  "short"   ) return ncShort;
 1233   if(name ==  "ushort"  ) return ncUshort;
 1234   if(name ==  "int"     ) return ncInt;
 1235   if(name ==  "uint"    ) return ncUint;
 1236   if(name ==  "int64"   ) return ncInt64;
 1237   if(name ==  "uint64"  ) return ncUint64;
 1238   if(name ==  "float"   ) return ncFloat;
 1239   if(name ==  "double"  ) return ncDouble;
 1240   if(name ==  "string"  ) return ncString;
 1241 
 1242   // this is a user defined type
 1243   // iterator for the multimap container.
 1244   multimap<string,NcType>::iterator it;
 1245   // return argument of equal_range: iterators to lower and upper bounds of the range.
 1246   pair<multimap<string,NcType>::iterator,multimap<string,NcType>::iterator> ret;
 1247   // get the entire collection of types.
 1248   multimap<string,NcType> types(getTypes(location));
 1249   // define STL set object to hold the result
 1250   set<NcType> tmpType;
 1251     // get the set of NcType objects with a given name
 1252   ret=types.equal_range(name);
 1253   if(ret.first == ret.second)
 1254     return NcType();
 1255   else
 1256     return ret.first->second;
 1257 }
 1258 
 1259 
 1260 // Adds a new netCDF Enum type.
 1261 NcEnumType NcGroup::addEnumType(const string& name,NcEnumType::ncEnumType baseType) const {
 1262   ncCheckDefineMode(myId);
 1263   nc_type typeId;
 1264   ncCheck(nc_def_enum(myId, baseType, name.c_str(), &typeId),__FILE__,__LINE__);
 1265   NcEnumType ncTypeTmp(*this,name);
 1266   return ncTypeTmp;
 1267 }
 1268 
 1269 
 1270 // Adds a new netCDF Vlen type.
 1271 NcVlenType NcGroup::addVlenType(const string& name,NcType& baseType) const {
 1272   ncCheckDefineMode(myId);
 1273   nc_type typeId;
 1274   ncCheck(nc_def_vlen(myId,  const_cast<char*>(name.c_str()),baseType.getId(),&typeId),__FILE__,__LINE__);
 1275   NcVlenType ncTypeTmp(*this,name);
 1276   return ncTypeTmp;
 1277 }
 1278 
 1279 
 1280 // Adds a new netCDF Opaque type.
 1281 NcOpaqueType NcGroup::addOpaqueType(const string& name, size_t size) const {
 1282   ncCheckDefineMode(myId);
 1283   nc_type typeId;
 1284   ncCheck(nc_def_opaque(myId, size,const_cast<char*>(name.c_str()), &typeId),__FILE__,__LINE__);
 1285   NcOpaqueType ncTypeTmp(*this,name);
 1286   return ncTypeTmp;
 1287 }
 1288 
 1289 // Adds a new netCDF UserDefined type.
 1290 NcCompoundType NcGroup::addCompoundType(const string& name, size_t size) const {
 1291   ncCheckDefineMode(myId);
 1292   nc_type typeId;
 1293   ncCheck(nc_def_compound(myId, size,const_cast<char*>(name.c_str()),&typeId),__FILE__,__LINE__);
 1294   NcCompoundType ncTypeTmp(*this,name);
 1295   return ncTypeTmp;
 1296 }
 1297 
 1298 
 1299 // Get the collection of coordinate variables.
 1300 map<string,NcGroup> NcGroup::getCoordVars(NcGroup::Location location) const {
 1301   map<string,NcGroup> coordVars;
 1302 
 1303   // search in current group and parent groups.
 1304   NcGroup tmpGroup(*this);
 1305   multimap<string,NcDim>::iterator itD;
 1306   multimap<string,NcVar>::iterator itV;
 1307   while(1) {
 1308     // get the collection of NcDim objects defined in this group.
 1309     multimap<string,NcDim> dimTmp(tmpGroup.getDims());
 1310     multimap<string,NcVar> varTmp(tmpGroup.getVars());
 1311     for (itD=dimTmp.begin();itD!=dimTmp.end();itD++) {
 1312       string coordName(itD->first);
 1313       itV = varTmp.find(coordName);
 1314       if(itV != varTmp.end()) {
 1315     coordVars.insert(pair<const string,NcGroup>(string(coordName),tmpGroup));
 1316       }
 1317     }
 1318     if(location != ParentsAndCurrent || location != All || tmpGroup.isRootGroup()) {
 1319       break;
 1320     }
 1321     // continue loop with the parent.
 1322     tmpGroup=tmpGroup.getParentGroup();
 1323   }
 1324 
 1325   // search in child groups (makes recursive calls).
 1326   if(location == ChildrenAndCurrent || location == All ) {
 1327     multimap<string,NcGroup>::iterator it;
 1328     multimap<string,NcGroup> groups(getGroups());
 1329     for (it=groups.begin();it!=groups.end();it++) {
 1330       map<string,NcGroup> coordVarsTmp=getCoordVars(ChildrenAndCurrent);
 1331       coordVars.insert(coordVarsTmp.begin(),coordVarsTmp.end());
 1332     }
 1333   }
 1334 
 1335   return coordVars;
 1336 }
 1337 
 1338 // Get the NcDim and NcVar object pair for a named coordinate variables.
 1339 void NcGroup::getCoordVar(string& coordVarName, NcDim& ncDim, NcVar& ncVar, NcGroup::Location location) const {
 1340 
 1341   // search in current group and parent groups.
 1342   multimap<string,NcDim>::iterator itD;
 1343   NcGroup tmpGroup(*this);
 1344   multimap<string,NcVar>::iterator itV;
 1345   while(1) {
 1346     // get the collection of NcDim objects defined in this group.
 1347     multimap<string,NcDim> dimTmp(tmpGroup.getDims());
 1348     multimap<string,NcVar> varTmp(tmpGroup.getVars());
 1349     itD=dimTmp.find(coordVarName);
 1350     itV=varTmp.find(coordVarName);
 1351     if(itD != dimTmp.end() && itV != varTmp.end()) {
 1352       ncDim=itD->second;
 1353       ncVar=itV->second;
 1354       return;
 1355     }
 1356     if(location != ParentsAndCurrent || location != All || tmpGroup.isRootGroup()) {
 1357       break;
 1358     }
 1359     // continue loop with the parent.
 1360     tmpGroup=tmpGroup.getParentGroup();
 1361   }
 1362 
 1363   // search in child groups (makes recursive calls).
 1364   if(location == ChildrenAndCurrent || location == All ) {
 1365     multimap<string,NcGroup>::iterator it;
 1366     multimap<string,NcGroup> groups(getGroups());
 1367     for (it=groups.begin();it!=groups.end();it++) {
 1368       getCoordVar(coordVarName,ncDim,ncVar,ChildrenAndCurrent);
 1369       if(!ncDim.isNull()) break;
 1370     }
 1371   }
 1372 
 1373   if(ncDim.isNull()) {
 1374     // return null objects as no coordinates variables were obtained.
 1375     NcDim dimTmp;
 1376     NcVar varTmp;
 1377     ncDim=dimTmp;
 1378     ncVar=varTmp;
 1379     return;
 1380   }
 1381 
 1382 }