LCOV - code coverage report
Current view: top level - frmts/netcdf - netcdfvirtual.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 70 98 71.4 %
Date: 2024-11-21 22:18:42 Functions: 30 62 48.4 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  netCDF read/write Driver
       4             :  * Purpose:  GDAL bindings over netCDF library.
       5             :  * Author:   Winor Chen <wchen329 at wisc.edu>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2019, Winor Chen <wchen329 at wisc.edu>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : #ifndef __NETCDFVIRTUAL_H__
      13             : #define __NETCDFVIRTUAL_H__
      14             : #include <map>
      15             : #include <memory>
      16             : #include <string>
      17             : #include <vector>
      18             : #include "netcdfsg.h"
      19             : #include "netcdf.h"
      20             : 
      21             : class netCDFDataset;
      22             : 
      23             : // netCDF Virtual
      24             : // Provides a layer of "virtual ncID"
      25             : // that can be mapped to a real netCDF ID
      26             : namespace nccfdriver
      27             : {
      28             : // Exceptions
      29             : class SG_Exception_NVOOB : public SG_Exception
      30             : {
      31             :     std::string err_msg;
      32             : 
      33             :   public:
      34           0 :     explicit SG_Exception_NVOOB(const char *dsname)
      35           0 :         : err_msg(std::string("An attempt to read an undefined ID from ") +
      36           0 :                   std::string(dsname) + std::string(" was made"))
      37             :     {
      38           0 :     }
      39             : 
      40           0 :     const char *get_err_msg() override
      41             :     {
      42           0 :         return this->err_msg.c_str();
      43             :     }
      44             : };
      45             : 
      46             : class SG_Exception_DupName : public SG_Exception
      47             : {
      48             :     std::string err_msg;
      49             : 
      50             :   public:
      51           0 :     SG_Exception_DupName(const char *keyn, const char *dsname)
      52           0 :         : err_msg(std::string("The key ") + std::string(keyn) +
      53           0 :                   std::string(" already exists in") + std::string(dsname))
      54             :     {
      55           0 :     }
      56             : 
      57           0 :     const char *get_err_msg() override
      58             :     {
      59           0 :         return this->err_msg.c_str();
      60             :     }
      61             : };
      62             : 
      63             : class SG_Exception_BadMapping : public SG_Exception
      64             : {
      65             :     std::string err_msg;
      66             : 
      67             :   public:
      68           0 :     SG_Exception_BadMapping(const char *key, const char *where)
      69           0 :         : err_msg(std::string(key) + std::string(" not found in ") +
      70           0 :                   std::string(where))
      71             :     {
      72           0 :     }
      73             : 
      74           0 :     const char *get_err_msg() override
      75             :     {
      76           0 :         return this->err_msg.c_str();
      77             :     }
      78             : };
      79             : 
      80             : class SG_Exception_VWrite_Failure : public SG_Exception
      81             : {
      82             :     std::string err_msg;
      83             : 
      84             :   public:
      85           0 :     SG_Exception_VWrite_Failure(const char *where, const char *type)
      86           0 :         : err_msg(std::string("Failed to write ") + std::string(type) +
      87           0 :                   std::string(" to ") + std::string(where))
      88             :     {
      89           0 :     }
      90             : 
      91           0 :     const char *get_err_msg() override
      92             :     {
      93           0 :         return this->err_msg.c_str();
      94             :     }
      95             : };
      96             : 
      97             : /* netCDFVAttribute
      98             :  * -
      99             :  * Contains attribute name and data.
     100             :  * Central to derived types are reimplementations of vsync
     101             :  */
     102             : class netCDFVAttribute
     103             : {
     104             :   public:
     105             :     /* vsync(...)
     106             :      * Implementation: Given the REAL ncID and REAL variable ID
     107             :      * Write the attribute to the variable
     108             :      */
     109             :     virtual void vsync(int realncid, int realvarid) = 0;
     110             : 
     111             :     /*  ~netCDFVAttribute()
     112             :      * Virtual destructor
     113             :      */
     114         749 :     virtual ~netCDFVAttribute()
     115         749 :     {
     116         749 :     }
     117             : };
     118             : 
     119             : template <class VClass, nc_type ntype>
     120             : class netCDFVGeneralAttribute : public netCDFVAttribute
     121             : {
     122             :     std::string name;
     123             :     VClass value;
     124             : 
     125             :   public:
     126          51 :     netCDFVGeneralAttribute(const char *a_name, const VClass *a_value)
     127          51 :         : name(a_name), value(*a_value)
     128             :     {
     129          51 :     }
     130             : 
     131          51 :     void vsync(int realncid, int realvarid) override
     132             :     {
     133          51 :         if (nc_put_att(realncid, realvarid, name.c_str(), ntype, 1, &value) !=
     134             :             NC_NOERR)
     135             :         {
     136           0 :             throw SG_Exception_VWrite_Failure("variable", "attribute");
     137             :         }
     138          51 :     }
     139             : };
     140             : 
     141             : /* netCDFVTextAttribute
     142             :  * -
     143             :  * Attribute that has a text string value
     144             :  */
     145             : class netCDFVTextAttribute : public netCDFVAttribute
     146             : {
     147             :     std::string name;
     148             :     std::string value;
     149             : 
     150             :   public:
     151         698 :     netCDFVTextAttribute(const char *a_name, const char *a_value)
     152         698 :         : name(a_name), value(a_value)
     153             :     {
     154         698 :     }
     155             : 
     156             :     void vsync(int realncid, int realvarid) override;
     157             : };
     158             : 
     159             : typedef netCDFVGeneralAttribute<signed char, NC_BYTE> netCDFVByteAttribute;
     160             : typedef netCDFVGeneralAttribute<int, NC_INT> netCDFVIntAttribute;
     161             : typedef netCDFVGeneralAttribute<double, NC_DOUBLE> netCDFVDoubleAttribute;
     162             : typedef netCDFVGeneralAttribute<float, NC_FLOAT> netCDFVFloatAttribute;
     163             : 
     164             : /* netCDFVDimension
     165             :  * -
     166             :  * Contains the real dim id, real dimension name, and dimension length
     167             :  */
     168             : class netCDFVDimension
     169             : {
     170             :     friend class netCDFVID;
     171             : 
     172             :     std::string real_dim_name;
     173             :     int r_did = INVALID_DIM_ID;
     174             :     int v_did;
     175             :     size_t dim_len;
     176             :     bool valid = true;
     177             : 
     178             :   protected:
     179         145 :     void setRealID(int realID)
     180             :     {
     181         145 :         this->r_did = realID;
     182         145 :     }
     183             : 
     184             :     void invalidate();
     185             : 
     186         136 :     void setLen(size_t len)
     187             :     {
     188         136 :         this->dim_len = len;
     189         136 :     }
     190             : 
     191             :   public:
     192         149 :     netCDFVDimension(const char *name, size_t len, int dimid)
     193         149 :         : real_dim_name(name), v_did(dimid), dim_len(len)
     194             :     {
     195         149 :     }
     196             : 
     197         149 :     std::string &getName()
     198             :     {
     199         149 :         return this->real_dim_name;
     200             :     }
     201             : 
     202        1029 :     size_t getLen()
     203             :     {
     204        1029 :         return this->dim_len;
     205             :     }
     206             : 
     207         423 :     int getRealID()
     208             :     {
     209         423 :         return this->r_did;
     210             :     }
     211             : 
     212             :     int getVirtualID()
     213             :     {
     214             :         return this->v_did;
     215             :     }
     216             : 
     217         149 :     bool isValid()
     218             :     {
     219         149 :         return this->valid;
     220             :     }
     221             : };
     222             : 
     223             : /* netCDFVVariable
     224             :  * -
     225             :  * Contains the variable name, variable type, etc.
     226             :  */
     227             : class netCDFVVariable
     228             : {
     229             :     friend class netCDFVID;
     230             : 
     231             :     std::string real_var_name;
     232             :     nc_type ntype;
     233             :     int r_vid = INVALID_VAR_ID;
     234             :     int ndimc;
     235             :     std::unique_ptr<int, std::default_delete<int[]>> dimid;
     236             :     std::vector<std::shared_ptr<netCDFVAttribute>> attribs;
     237             :     bool valid = true;
     238             : 
     239             :   protected:
     240        2725 :     std::vector<std::shared_ptr<netCDFVAttribute>> &getAttributes()
     241             :     {
     242        2725 :         return attribs;
     243             :     }
     244             : 
     245             :     void invalidate();
     246             : 
     247         239 :     void setRealID(int realID)
     248             :     {
     249         239 :         this->r_vid = realID;
     250         239 :     }
     251             : 
     252             :   public:
     253             :     netCDFVVariable(const char *name, nc_type xtype, int ndims,
     254             :                     const int *dimidsp);
     255             : 
     256         260 :     std::string &getName()
     257             :     {
     258         260 :         return real_var_name;
     259             :     }
     260             : 
     261       24349 :     int getRealID()
     262             :     {
     263       24349 :         return r_vid;
     264             :     }
     265             : 
     266         239 :     nc_type getType()
     267             :     {
     268         239 :         return ntype;
     269             :     }
     270             : 
     271        1004 :     int getDimCount()
     272             :     {
     273        1004 :         return this->ndimc;
     274             :     }
     275             : 
     276         287 :     const int *getDimIds()
     277             :     {
     278         287 :         return this->dimid.get();
     279             :     }
     280             : 
     281         260 :     bool isValid()
     282             :     {
     283         260 :         return this->valid;
     284             :     }
     285             : };
     286             : 
     287             : /* netCDFVID
     288             :  * -
     289             :  * A netCDF ID that sits on top of an actual netCDF ID
     290             :  * And manages actual interaction with the real netCDF file
     291             :  *
     292             :  * A bit difference is that netCDFVID
     293             :  * doesn't have fixed dim sizes, until defines are committed
     294             :  *
     295             :  * Also, virtual attributes only exist until the variable is committed. Use
     296             :  * "real" attributes and "real" IDs for a variable after its been committed.
     297             :  *
     298             :  * ** Do not mix netCDF virtual dim and variable IDs with regular netCDF dim
     299             :  * (a.k.a. "real") ids and variable ids. They are NOT necessarily compatible,
     300             :  * and must be translated first, to be used in this manner **
     301             :  *
     302             :  * The netCDFVID can also be used in what is called "direct mode" and the
     303             :  * netCDFVID will just act as a wrapper to the netCDF Library. In such a case
     304             :  * netCDFVID should take real IDs, not real ones. However, the big advantages of
     305             :  * using netCDFVID (such as quick dim resizing) are no longer are available.
     306             :  */
     307             : class netCDFVID
     308             : {
     309             :     netCDFDataset *m_poDS = nullptr;
     310             :     int &ncid;  // ncid REF. which tracks ncID changes that may be made upstream
     311             :     int dimTicket = 0;
     312             :     int varTicket = 0;
     313             :     bool directMode = true;
     314             : 
     315             :     std::vector<netCDFVVariable> varList;
     316             :     std::vector<netCDFVDimension> dimList;
     317             : 
     318             :     std::map<std::string, int> nameDimTable;
     319             :     std::map<std::string, int> nameVarTable;
     320             : 
     321             :   public:
     322             :     // Each of these returns an ID, NOT an error code
     323             : 
     324             :     /* nc_def_vdim(...)
     325             :      * Defines a virtual dim given the parameters NAME and LENGTH.
     326             :      * Returns: virtual dimID
     327             :      */
     328             :     int nc_def_vdim(
     329             :         const char *name,
     330             :         size_t dimlen);  // for dims that don't already exist in netCDF file
     331             : 
     332             :     /* nc_def_vvar(...)
     333             :      * Defines a virtual var given the parameters NAME, NC TYPE, NUMBER OF DIMS,
     334             :      * and DIM IDS The dim IDs in dimidsp given are to be virtual dim IDs, using
     335             :      * real dim IDs is undefined
     336             :      */
     337             :     int nc_def_vvar(const char *name, nc_type xtype, int ndims,
     338             :                     const int *dimidsp);
     339             : 
     340             :     /* nc_del_vdim(...)
     341             :      * Delete a virtual dimension
     342             :      * NOTES:
     343             :      *     This doesn't work on committed IDs.
     344             :      *     Also the dimension (for now) will be only invalidated, doesn't
     345             :      * completely *delete* it in memory.
     346             :      */
     347             :     void nc_del_vdim(int dimid);
     348             : 
     349             :     /* nc_del_vvar(...)
     350             :      * Delete a virtual variable
     351             :      * NOTES:
     352             :      *     This doesn't work on committed IDs.
     353             :      *     Also the variable (for now) will be only invalidated, doesn't
     354             :      * completely *delete* it in memory.
     355             :      */
     356             :     void nc_del_vvar(int varid);
     357             : 
     358             :     /* nc_resize_vdim(...)
     359             :      * Change the size of a virtual dim to the given size.
     360             :      * NOTE: if the dim has committed using nc_vmap then this has no effect.
     361             :      */
     362             :     void nc_resize_vdim(
     363             :         int dimid,
     364             :         size_t dimlen);  // for dims that haven't been mapped to physical yet
     365             : 
     366             :     /* nc_set_define_mode()
     367             :      * Convenience function for setting the ncid to define mode
     368             :      */
     369             :     void nc_set_define_mode();
     370             : 
     371             :     /* nc_set_data_mode()
     372             :      * Convenience function for setting the ncid to data mode
     373             :      */
     374             :     void nc_set_data_mode();
     375             : 
     376             :     /* nc_vmap()
     377             :      * Maps virtual IDs to real physical ID if that mapping doesn't already
     378             :      * exist This is required before writing data to virtual IDs that do not
     379             :      * exist yet in the netCDF file
     380             :      */
     381             :     void nc_vmap();
     382             : 
     383             :     /* void enableFullVirtualMode
     384             :      * Enables full virtual mode (i.e. allows netCDFVID to use its full
     385             :      * capabilities).
     386             :      */
     387         104 :     void enableFullVirtualMode()
     388             :     {
     389         104 :         this->directMode = false;
     390         104 :     }
     391             : 
     392             :     // Attribute function(s)
     393             :     template <class attrC, class attrT>
     394         749 :     void nc_put_vatt_generic(int varid, const char *name, const attrT *value)
     395             :     {
     396             : 
     397         749 :         if (varid >= static_cast<int>(varList.size()) || varid < 0)
     398             :         {
     399           0 :             throw SG_Exception_NVOOB("virtual variable collection");
     400             :         }
     401             : 
     402         749 :         netCDFVVariable &v = virtualVIDToVar(varid);
     403        1498 :         v.getAttributes().push_back(
     404         749 :             std::shared_ptr<netCDFVAttribute>(new attrC(name, value)));
     405         749 :     }
     406             : 
     407             :     void nc_put_vatt_text(int varid, const char *name, const char *value);
     408             :     void nc_put_vatt_int(int varid, const char *name, const int *value);
     409             :     void nc_put_vatt_double(int varid, const char *name, const double *value);
     410             :     void nc_put_vatt_float(int varid, const char *name, const float *value);
     411             :     void nc_put_vatt_byte(int varid, const char *name,
     412             :                           const signed char *value);
     413             : 
     414             :     // Writing Functions
     415             :     template <class out_T>
     416       23250 :     void nc_put_vvar_generic(int varid, const size_t *index, const out_T *value)
     417             :     {
     418       23250 :         int rvarid = !directMode ? virtualVIDToVar(varid).getRealID() : varid;
     419             : 
     420       23250 :         if (rvarid == INVALID_VAR_ID)
     421          95 :             return;  // invalidated variable, specific condition that Scribe
     422             :                      // relies on
     423             : 
     424       23155 :         if (nc_put_var1(ncid, rvarid, index, value) != NC_NOERR)
     425             :         {
     426           0 :             throw SG_Exception_VWrite_Failure("variable", "datum");
     427             :         }
     428             :     }
     429             : 
     430             :     template <class outArr_T>
     431         201 :     void nc_put_vvara_generic(int varid, const size_t *index,
     432             :                               const size_t *count, const outArr_T *value)
     433             :     {
     434         201 :         int rvarid = !directMode ? virtualVIDToVar(varid).getRealID() : varid;
     435             : 
     436         201 :         if (rvarid == INVALID_VAR_ID)
     437          20 :             return;  // invalidated variable, specific condition that Scribe
     438             :                      // relies on
     439             : 
     440         181 :         if (nc_put_vara(ncid, rvarid, index, count, value) != NC_NOERR)
     441             :         {
     442           0 :             throw SG_Exception_VWrite_Failure("variable", "data array");
     443             :         }
     444             :     }
     445             : 
     446             :     void nc_put_vvar1_text(int varid, const size_t *index, const char *value);
     447             :     void nc_put_vvara_text(int varid, const size_t *start, const size_t *index,
     448             :                            const char *value);
     449             :     void nc_put_vvar1_string(int varid, const size_t *index,
     450             :                              const char **value);
     451             : 
     452             :     // Equivalent "enquiry" functions
     453             :     netCDFVVariable &
     454             :     virtualVIDToVar(int virtualID);  // converts a virtual var ID to a real ID
     455             :     netCDFVDimension &
     456             :     virtualDIDToDim(int virtualID);  // converts a virtual dim ID to a real ID
     457             :     int nameToVirtualVID(const std::string &name);
     458             :     int nameToVirtualDID(const std::string &name);
     459             : 
     460          77 :     bool virtualVarNameDefined(const std::string &nm)
     461             :     {
     462          77 :         return nameVarTable.count(nm) > 0;
     463             :     }
     464             : 
     465             :     // Constructor
     466        1036 :     explicit netCDFVID(netCDFDataset *poDS, int &ncid_in)
     467        1036 :         : m_poDS(poDS), ncid(ncid_in)
     468             :     {
     469        1036 :     }
     470             : };
     471             : 
     472             : }  // namespace nccfdriver
     473             : #endif

Generated by: LCOV version 1.14