LCOV - code coverage report
Current view: top level - frmts/netcdf - netcdfvirtual.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 68 88 77.3 %
Date: 2025-06-19 12:30:01 Functions: 30 58 51.7 %

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

Generated by: LCOV version 1.14