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

Generated by: LCOV version 1.14