Line data Source code
1 : /******************************************************************************
2 : * $Id$
3 : *
4 : * Project: netCDF read/write Driver
5 : * Purpose: GDAL bindings over netCDF library.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2004, Frank Warmerdam
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #ifndef NETCDFDATASET_H_INCLUDED_
15 : #define NETCDFDATASET_H_INCLUDED_
16 :
17 : #include <array>
18 : #include <ctime>
19 : #include <cfloat>
20 : #include <cstdlib>
21 : #include <functional>
22 : #include <map>
23 : #include <memory>
24 : #include <utility>
25 : #include <vector>
26 :
27 : #include "cpl_mem_cache.h"
28 : #include "cpl_string.h"
29 : #include "gdal_frmts.h"
30 : #include "gdal_pam.h"
31 : #include "gdal_priv.h"
32 : #include "netcdf.h"
33 : #include "netcdfformatenum.h"
34 : #include "netcdfsg.h"
35 : #include "netcdfsgwriterutil.h"
36 : #include "ogr_spatialref.h"
37 : #include "ogrsf_frmts.h"
38 : #include "netcdfuffd.h"
39 : #include "netcdf_cf_constants.h"
40 :
41 : #if CPL_IS_LSB
42 : #define PLATFORM_HEADER 1
43 : #else
44 : #define PLATFORM_HEADER 0
45 : #endif
46 :
47 : /************************************************************************/
48 : /* ==================================================================== */
49 : /* defines */
50 : /* ==================================================================== */
51 : /************************************************************************/
52 :
53 : /* -------------------------------------------------------------------- */
54 : /* Creation and Configuration Options */
55 : /* -------------------------------------------------------------------- */
56 :
57 : /* Creation options
58 :
59 : FORMAT=NC/NC2/NC4/NC4C (COMPRESS=DEFLATE sets FORMAT=NC4C)
60 : COMPRESS=NONE/DEFLATE (default: NONE)
61 : ZLEVEL=[1-9] (default: 1)
62 : WRITE_BOTTOMUP=YES/NO (default: YES)
63 : WRITE_GDAL_TAGS=YES/NO (default: YES)
64 : WRITE_LONLAT=YES/NO/IF_NEEDED (default: YES for geographic, NO for projected)
65 : TYPE_LONLAT=float/double (default: double for geographic, float for
66 : projected) PIXELTYPE=DEFAULT/SIGNEDBYTE (use SIGNEDBYTE to get a signed Byte
67 : Band)
68 : */
69 :
70 : /* Config Options
71 :
72 : GDAL_NETCDF_BOTTOMUP=YES/NO overrides bottom-up value on import
73 : GDAL_NETCDF_VERIFY_DIMS=[YES/STRICT] : Try to guess which dimensions
74 : represent the latitude and longitude only by their attributes (STRICT) or
75 : also by guessing the name (YES), default is YES.
76 : GDAL_NETCDF_IGNORE_XY_AXIS_NAME_CHECKS=[YES/NO] Whether X/Y dimensions should
77 : be always considered as geospatial axis, even if the lack conventional
78 : attributes confirming it. Default is NO. GDAL_NETCDF_ASSUME_LONGLAT=[YES/NO]
79 : Whether when all else has failed for determining a CRS, a meaningful
80 : geotransform has been found, and is within the bounds -180,360 -90,90, if YES
81 : assume OGC:CRS84. Default is NO.
82 :
83 : // TODO: this unusued and a few others occur in the source that are not
84 : documented, flush out unused opts and document the rest mdsumner@gmail.com
85 : GDAL_NETCDF_CONVERT_LAT_180=YES/NO convert longitude values from ]180,360] to
86 : [-180,180]
87 : */
88 :
89 : /* -------------------------------------------------------------------- */
90 : /* Driver-specific defines */
91 : /* -------------------------------------------------------------------- */
92 :
93 : /* NETCDF driver defs */
94 : static const size_t NCDF_MAX_STR_LEN = 8192;
95 : #define NCDF_CONVENTIONS "Conventions"
96 : #define NCDF_CONVENTIONS_CF_V1_5 "CF-1.5"
97 : #define GDAL_DEFAULT_NCDF_CONVENTIONS NCDF_CONVENTIONS_CF_V1_5
98 : #define NCDF_CONVENTIONS_CF_V1_6 "CF-1.6"
99 : #define NCDF_CONVENTIONS_CF_V1_8 "CF-1.8"
100 : #define NCDF_GEOTRANSFORM "GeoTransform"
101 : #define NCDF_DIMNAME_X "x"
102 : #define NCDF_DIMNAME_Y "y"
103 : #define NCDF_DIMNAME_LON "lon"
104 : #define NCDF_DIMNAME_LAT "lat"
105 : #define NCDF_LONLAT "lon lat"
106 : #define NCDF_DIMNAME_RLON "rlon" // rotated longitude
107 : #define NCDF_DIMNAME_RLAT "rlat" // rotated latitude
108 :
109 : /* compression parameters */
110 : typedef enum
111 : {
112 : NCDF_COMPRESS_NONE = 0,
113 : /* TODO */
114 : /* http://www.unidata.ucar.edu/software/netcdf/docs/BestPractices.html#Packed%20Data%20Values
115 : */
116 : NCDF_COMPRESS_PACKED = 1,
117 : NCDF_COMPRESS_DEFLATE = 2,
118 : NCDF_COMPRESS_SZIP = 3 /* no support for writing */
119 : } NetCDFCompressEnum;
120 :
121 : static const int NCDF_DEFLATE_LEVEL = 1; /* best time/size ratio */
122 :
123 : /* helper for libnetcdf errors */
124 : #define NCDF_ERR(status) \
125 : do \
126 : { \
127 : int NCDF_ERR_status_ = (status); \
128 : if (NCDF_ERR_status_ != NC_NOERR) \
129 : { \
130 : CPLError(CE_Failure, CPLE_AppDefined, \
131 : "netcdf error #%d : %s .\nat (%s,%s,%d)\n", \
132 : NCDF_ERR_status_, nc_strerror(NCDF_ERR_status_), \
133 : __FILE__, __FUNCTION__, __LINE__); \
134 : } \
135 : } while (0)
136 :
137 : #define NCDF_ERR_RET(status) \
138 : do \
139 : { \
140 : int NCDF_ERR_RET_status_ = (status); \
141 : if (NCDF_ERR_RET_status_ != NC_NOERR) \
142 : { \
143 : NCDF_ERR(NCDF_ERR_RET_status_); \
144 : return CE_Failure; \
145 : } \
146 : } while (0)
147 :
148 : #define ERR_RET(eErr) \
149 : do \
150 : { \
151 : CPLErr ERR_RET_eErr_ = (eErr); \
152 : if (ERR_RET_eErr_ != CE_None) \
153 : return ERR_RET_eErr_; \
154 : } while (0)
155 :
156 : /* Check for NC2 support in case it was not enabled at compile time. */
157 : /* NC4 has to be detected at compile as it requires a special build of netcdf-4.
158 : */
159 : #ifndef NETCDF_HAS_NC2
160 : #ifdef NC_64BIT_OFFSET
161 : #define NETCDF_HAS_NC2 1
162 : #endif
163 : #endif
164 :
165 : /* Some additional metadata */
166 : #define OGR_SG_ORIGINAL_LAYERNAME "ogr_layer_name"
167 :
168 : /*
169 : * Starting `c26f7ea`, netcdf-c exposes the `NC_FillValue`[1] macro instead of
170 : * `_FillValue` to avoid collisions with C++ standard library[2]. However, the
171 : * previous macro, `_FillValue`, was fully removed causing netcdf-c consumers,
172 : * including GDAL, fail to build.
173 : *
174 : * It's unlikely that this naming change will be backported to the previous
175 : * netcdf-c releases, so we have to account for both macros variants. We do so
176 : * by introducing our own macro, `NCDF_FillValue`, and using that in places
177 : * where `_FillValue` was previously used. If `NC_FillValue` is defined by
178 : * `netcdf.h`, `NCDF_FillValue` expands to it and, if it's not, to `_FillValue`.
179 : *
180 : * References:
181 : * 1. https://github.com/Unidata/netcdf-c/commit/c26f7eabf4a1cd25353f22734f439505fe636a45
182 : * 2. https://github.com/Unidata/netcdf-c/issues/2858
183 : */
184 : #if defined(NC_FillValue)
185 : #define NCDF_FillValue NC_FillValue
186 : #elif defined(_FillValue)
187 : #define NCDF_FillValue _FillValue
188 : #endif
189 :
190 : /* -------------------------------------------------------------------- */
191 : /* CF-1 Coordinate Type Naming (Chapter 4. Coordinate Types ) */
192 : /* -------------------------------------------------------------------- */
193 : static const char *const papszCFLongitudeVarNames[] = {CF_LONGITUDE_VAR_NAME,
194 : "longitude", nullptr};
195 : static const char *const papszCFLongitudeAttribNames[] = {
196 : CF_UNITS, CF_UNITS, CF_UNITS, CF_STD_NAME, CF_AXIS, CF_LNG_NAME, nullptr};
197 : static const char *const papszCFLongitudeAttribValues[] = {
198 : CF_DEGREES_EAST,
199 : CF_DEGREE_EAST,
200 : CF_DEGREES_E,
201 : CF_LONGITUDE_STD_NAME,
202 : "X",
203 : CF_LONGITUDE_LNG_NAME,
204 : nullptr};
205 : static const char *const papszCFLatitudeVarNames[] = {CF_LATITUDE_VAR_NAME,
206 : "latitude", nullptr};
207 : static const char *const papszCFLatitudeAttribNames[] = {
208 : CF_UNITS, CF_UNITS, CF_UNITS, CF_STD_NAME, CF_AXIS, CF_LNG_NAME, nullptr};
209 : static const char *const papszCFLatitudeAttribValues[] = {CF_DEGREES_NORTH,
210 : CF_DEGREE_NORTH,
211 : CF_DEGREES_N,
212 : CF_LATITUDE_STD_NAME,
213 : "Y",
214 : CF_LATITUDE_LNG_NAME,
215 : nullptr};
216 :
217 : static const char *const papszCFProjectionXVarNames[] = {CF_PROJ_X_VAR_NAME,
218 : "xc", nullptr};
219 : static const char *const papszCFProjectionXAttribNames[] = {CF_STD_NAME,
220 : CF_AXIS, nullptr};
221 : static const char *const papszCFProjectionXAttribValues[] = {CF_PROJ_X_COORD,
222 : "X", nullptr};
223 : static const char *const papszCFProjectionYVarNames[] = {CF_PROJ_Y_VAR_NAME,
224 : "yc", nullptr};
225 : static const char *const papszCFProjectionYAttribNames[] = {CF_STD_NAME,
226 : CF_AXIS, nullptr};
227 : static const char *const papszCFProjectionYAttribValues[] = {CF_PROJ_Y_COORD,
228 : "Y", nullptr};
229 :
230 : static const char *const papszCFVerticalAttribNames[] = {CF_AXIS, "positive",
231 : "positive", nullptr};
232 : static const char *const papszCFVerticalAttribValues[] = {"Z", "up", "down",
233 : nullptr};
234 : static const char *const papszCFVerticalUnitsValues[] = {
235 : /* units of pressure */
236 : "bar", "bars", "millibar", "millibars", "decibar", "decibars", "atmosphere",
237 : "atmospheres", "atm", "pascal", "pascals", "Pa", "hPa",
238 : /* units of length */
239 : "meter", "meters", "m", "kilometer", "kilometers", "km",
240 : /* dimensionless vertical coordinates */
241 : "level", "layer", "sigma_level", nullptr};
242 : /* dimensionless vertical coordinates */
243 : static const char *const papszCFVerticalStandardNameValues[] = {
244 : "atmosphere_ln_pressure_coordinate",
245 : "atmosphere_sigma_coordinate",
246 : "atmosphere_hybrid_sigma_pressure_coordinate",
247 : "atmosphere_hybrid_height_coordinate",
248 : "atmosphere_sleve_coordinate",
249 : "ocean_sigma_coordinate",
250 : "ocean_s_coordinate",
251 : "ocean_sigma_z_coordinate",
252 : "ocean_double_sigma_coordinate",
253 : "atmosphere_ln_pressure_coordinate",
254 : "atmosphere_sigma_coordinate",
255 : "atmosphere_hybrid_sigma_pressure_coordinate",
256 : "atmosphere_hybrid_height_coordinate",
257 : "atmosphere_sleve_coordinate",
258 : "ocean_sigma_coordinate",
259 : "ocean_s_coordinate",
260 : "ocean_sigma_z_coordinate",
261 : "ocean_double_sigma_coordinate",
262 : nullptr};
263 :
264 : static const char *const papszCFTimeAttribNames[] = {CF_AXIS, CF_STD_NAME,
265 : nullptr};
266 : static const char *const papszCFTimeAttribValues[] = {"T", "time", nullptr};
267 : static const char *const papszCFTimeUnitsValues[] = {
268 : "days since", "day since", "d since", "hours since",
269 : "hour since", "h since", "hr since", "minutes since",
270 : "minute since", "min since", "seconds since", "second since",
271 : "sec since", "s since", nullptr};
272 :
273 : /************************************************************************/
274 : /* ==================================================================== */
275 : /* netCDFWriterConfig classes */
276 : /* ==================================================================== */
277 : /************************************************************************/
278 :
279 : class netCDFWriterConfigAttribute
280 : {
281 : public:
282 : CPLString m_osName;
283 : CPLString m_osType;
284 : CPLString m_osValue;
285 :
286 : bool Parse(CPLXMLNode *psNode);
287 : };
288 :
289 : class netCDFWriterConfigField
290 : {
291 : public:
292 : CPLString m_osName;
293 : CPLString m_osNetCDFName;
294 : CPLString m_osMainDim;
295 : std::vector<netCDFWriterConfigAttribute> m_aoAttributes;
296 :
297 : bool Parse(CPLXMLNode *psNode);
298 : };
299 :
300 : class netCDFWriterConfigLayer
301 : {
302 : public:
303 : CPLString m_osName;
304 : CPLString m_osNetCDFName;
305 : std::map<CPLString, CPLString> m_oLayerCreationOptions;
306 : std::vector<netCDFWriterConfigAttribute> m_aoAttributes;
307 : std::map<CPLString, netCDFWriterConfigField> m_oFields;
308 :
309 : bool Parse(CPLXMLNode *psNode);
310 : };
311 :
312 : class netCDFWriterConfiguration
313 : {
314 : public:
315 : bool m_bIsValid;
316 : std::map<CPLString, CPLString> m_oDatasetCreationOptions;
317 : std::map<CPLString, CPLString> m_oLayerCreationOptions;
318 : std::vector<netCDFWriterConfigAttribute> m_aoAttributes;
319 : std::map<CPLString, netCDFWriterConfigField> m_oFields;
320 : std::map<CPLString, netCDFWriterConfigLayer> m_oLayers;
321 :
322 966 : netCDFWriterConfiguration() : m_bIsValid(false)
323 : {
324 966 : }
325 :
326 : bool Parse(const char *pszFilename);
327 : static bool SetNameValue(CPLXMLNode *psNode,
328 : std::map<CPLString, CPLString> &oMap);
329 : };
330 :
331 : /************************************************************************/
332 : /* ==================================================================== */
333 : /* netCDFDataset */
334 : /* ==================================================================== */
335 : /************************************************************************/
336 :
337 : class netCDFRasterBand;
338 : class netCDFLayer;
339 :
340 : class netCDFDataset final : public GDALPamDataset
341 : {
342 : friend class netCDFRasterBand; // TMP
343 : friend class netCDFLayer;
344 : friend class netCDFVariable;
345 : friend class nccfdriver::netCDFVID;
346 :
347 : typedef enum
348 : {
349 : SINGLE_LAYER,
350 : SEPARATE_FILES,
351 : SEPARATE_GROUPS
352 : } MultipleLayerBehavior;
353 :
354 : /* basic dataset vars */
355 : CPLString osFilename;
356 : #ifdef ENABLE_NCDUMP
357 : bool bFileToDestroyAtClosing;
358 : #endif
359 : int cdfid;
360 : #ifdef ENABLE_UFFD
361 : cpl_uffd_context *pCtx = nullptr;
362 : #endif
363 : VSILFILE *fpVSIMEM = nullptr;
364 : int nSubDatasets;
365 : char **papszSubDatasets;
366 : char **papszMetadata;
367 :
368 : // Used to report metadata found in Sentinel 5
369 : std::map<std::string, CPLStringList> m_oMapDomainToJSon{};
370 :
371 : CPLStringList papszDimName;
372 : bool bBottomUp;
373 : NetCDFFormatEnum eFormat;
374 : bool bIsGdalFile; /* was this file created by GDAL? */
375 : bool bIsGdalCfFile; /* was this file created by the (new) CF-compliant
376 : driver? */
377 : char *pszCFProjection;
378 : const char *pszCFCoordinates;
379 : double nCFVersion;
380 : bool bSGSupport;
381 : MultipleLayerBehavior eMultipleLayerBehavior;
382 : std::vector<netCDFDataset *> apoVectorDatasets;
383 : std::string logHeader;
384 : int logCount;
385 : nccfdriver::netCDFVID vcdf;
386 : nccfdriver::OGR_NCScribe GeometryScribe;
387 : nccfdriver::OGR_NCScribe FieldScribe;
388 : nccfdriver::WBufferManager bufManager;
389 :
390 : bool bWriteGDALVersion = true;
391 : bool bWriteGDALHistory = true;
392 :
393 : /* projection/GT */
394 : double m_adfGeoTransform[6];
395 : OGRSpatialReference m_oSRS{};
396 : int nXDimID;
397 : int nYDimID;
398 : bool bIsProjected;
399 : bool bIsGeographic;
400 : bool bSwitchedXY = false;
401 :
402 : /* state vars */
403 : bool bDefineMode;
404 : bool m_bHasProjection = false;
405 : bool m_bHasGeoTransform = false;
406 : bool m_bAddedProjectionVarsDefs = false;
407 : bool m_bAddedProjectionVarsData = false;
408 : bool bAddedGridMappingRef;
409 :
410 : /* create vars */
411 : char **papszCreationOptions;
412 : NetCDFCompressEnum eCompress;
413 : int nZLevel;
414 : bool bChunking;
415 : int nCreateMode;
416 : bool bSignedData;
417 :
418 : // IDs of the dimensions of the variables
419 : std::vector<int> m_anDimIds{};
420 :
421 : // Extra dimension info (size of those arrays is m_anDimIds.size() - 2)
422 : std::vector<int> m_anExtraDimVarIds{};
423 : std::vector<int> m_anExtraDimGroupIds{};
424 :
425 : std::vector<std::shared_ptr<OGRLayer>> papoLayers;
426 :
427 : netCDFWriterConfiguration oWriterConfig;
428 :
429 : struct ChunkKey
430 : {
431 : size_t xChunk; // netCDF chunk number along X axis
432 : size_t yChunk; // netCDF chunk number along Y axis
433 : int nBand;
434 :
435 26 : ChunkKey(size_t xChunkIn, size_t yChunkIn, int nBandIn)
436 26 : : xChunk(xChunkIn), yChunk(yChunkIn), nBand(nBandIn)
437 : {
438 26 : }
439 :
440 28 : bool operator==(const ChunkKey &other) const
441 : {
442 48 : return xChunk == other.xChunk && yChunk == other.yChunk &&
443 48 : nBand == other.nBand;
444 : }
445 :
446 22 : bool operator!=(const ChunkKey &other) const
447 : {
448 22 : return !(operator==(other));
449 : }
450 : };
451 :
452 : struct KeyHasher
453 : {
454 45 : std::size_t operator()(const ChunkKey &k) const
455 : {
456 45 : return std::hash<size_t>{}(k.xChunk) ^
457 45 : (std::hash<size_t>{}(k.yChunk) << 1) ^
458 45 : (std::hash<size_t>{}(k.nBand) << 2);
459 : }
460 : };
461 :
462 : typedef lru11::Cache<
463 : ChunkKey, std::shared_ptr<std::vector<GByte>>, lru11::NullLock,
464 : std::unordered_map<
465 : ChunkKey,
466 : typename std::list<lru11::KeyValuePair<
467 : ChunkKey, std::shared_ptr<std::vector<GByte>>>>::iterator,
468 : KeyHasher>>
469 : ChunkCacheType;
470 :
471 : std::unique_ptr<ChunkCacheType> poChunkCache;
472 :
473 : static double rint(double);
474 :
475 : double FetchCopyParam(const char *pszGridMappingValue, const char *pszParam,
476 : double dfDefault, bool *pbFound = nullptr);
477 :
478 : std::vector<std::string>
479 : FetchStandardParallels(const char *pszGridMappingValue);
480 :
481 : const char *FetchAttr(const char *pszVarFullName, const char *pszAttr);
482 : const char *FetchAttr(int nGroupId, int nVarId, const char *pszAttr);
483 :
484 : void ProcessCreationOptions();
485 : int DefVarDeflate(int nVarId, bool bChunkingArg = true);
486 : CPLErr AddProjectionVars(bool bDefsOnly, GDALProgressFunc pfnProgress,
487 : void *pProgressData);
488 : bool AddGridMappingRef();
489 :
490 10 : bool GetDefineMode() const
491 : {
492 10 : return bDefineMode;
493 : }
494 :
495 : bool SetDefineMode(bool bNewDefineMode);
496 :
497 : CPLErr ReadAttributes(int, int);
498 :
499 : void CreateSubDatasetList(int nGroupId);
500 :
501 : void SetProjectionFromVar(int nGroupId, int nVarId, bool bReadSRSOnly,
502 : const char *pszGivenGM, std::string *,
503 : nccfdriver::SGeometry_Reader *,
504 : std::vector<std::string> *paosRemovedMDItems);
505 : void SetProjectionFromVar(int nGroupId, int nVarId, bool bReadSRSOnly);
506 :
507 : bool ProcessNASAL2OceanGeoLocation(int nGroupId, int nVarId);
508 :
509 : bool ProcessNASAEMITGeoLocation(int nGroupId, int nVarId);
510 :
511 : int ProcessCFGeolocation(int nGroupId, int nVarId,
512 : const std::string &osGeolocWKT,
513 : std::string &osGeolocXNameOut,
514 : std::string &osGeolocYNameOut);
515 : CPLErr Set1DGeolocation(int nGroupId, int nVarId, const char *szDimName);
516 : double *Get1DGeolocation(const char *szDimName, int &nVarLen);
517 :
518 : static bool CloneAttributes(int old_cdfid, int new_cdfid, int nSrcVarId,
519 : int nDstVarId);
520 : static bool CloneVariableContent(int old_cdfid, int new_cdfid,
521 : int nSrcVarId, int nDstVarId);
522 : static bool CloneGrp(int nOldGrpId, int nNewGrpId, bool bIsNC4,
523 : int nLayerId, int nDimIdToGrow, size_t nNewSize);
524 : bool GrowDim(int nLayerId, int nDimIdToGrow, size_t nNewSize);
525 :
526 : void ProcessSentinel3_SRAL_MWR();
527 :
528 : CPLErr
529 : FilterVars(int nCdfId, bool bKeepRasters, bool bKeepVectors,
530 : char **papszIgnoreVars, int *pnRasterVars, int *pnGroupId,
531 : int *pnVarId, int *pnIgnoredVars,
532 : // key is (dim1Id, dim2Id, nc_type varType)
533 : // value is (groupId, varId)
534 : std::map<std::array<int, 3>, std::vector<std::pair<int, int>>>
535 : &oMap2DDimsToGroupAndVar);
536 : CPLErr CreateGrpVectorLayers(int nCdfId, const CPLString &osFeatureType,
537 : const std::vector<int> &anPotentialVectorVarID,
538 : const std::map<int, int> &oMapDimIdToCount,
539 : int nVarXId, int nVarYId, int nVarZId,
540 : int nProfileDimId, int nParentIndexVarID,
541 : bool bKeepRasters);
542 :
543 : bool DetectAndFillSGLayers(int ncid);
544 : CPLErr LoadSGVarIntoLayer(int ncid, int nc_basevarId);
545 :
546 : static GDALDataset *OpenMultiDim(GDALOpenInfo *);
547 : std::shared_ptr<GDALGroup> m_poRootGroup{};
548 :
549 : void SetGeoTransformNoUpdate(double *);
550 : void SetSpatialRefNoUpdate(const OGRSpatialReference *);
551 :
552 : protected:
553 : OGRLayer *ICreateLayer(const char *pszName,
554 : const OGRGeomFieldDefn *poGeomFieldDefn,
555 : CSLConstList papszOptions) override;
556 :
557 : CPLErr Close() override;
558 :
559 : public:
560 : netCDFDataset();
561 : virtual ~netCDFDataset();
562 : bool SGCommitPendingTransaction();
563 : void SGLogPendingTransaction();
564 : static std::string generateLogName();
565 :
566 : /* Projection/GT */
567 : CPLErr GetGeoTransform(double *) override;
568 : CPLErr SetGeoTransform(double *) override;
569 : const OGRSpatialReference *GetSpatialRef() const override;
570 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
571 :
572 : virtual char **GetMetadataDomainList() override;
573 : char **GetMetadata(const char *) override;
574 :
575 : virtual CPLErr SetMetadataItem(const char *pszName, const char *pszValue,
576 : const char *pszDomain = "") override;
577 : virtual CPLErr SetMetadata(char **papszMD,
578 : const char *pszDomain = "") override;
579 :
580 : virtual int TestCapability(const char *pszCap) override;
581 :
582 1920 : virtual int GetLayerCount() override
583 : {
584 1920 : return static_cast<int>(this->papoLayers.size());
585 : }
586 :
587 : virtual OGRLayer *GetLayer(int nIdx) override;
588 :
589 : std::shared_ptr<GDALGroup> GetRootGroup() const override;
590 :
591 179 : int GetCDFID() const
592 : {
593 179 : return cdfid;
594 : }
595 :
596 2025 : inline bool HasInfiniteRecordDim()
597 : {
598 2025 : return !bSGSupport;
599 : }
600 :
601 : /* static functions */
602 : static GDALDataset *Open(GDALOpenInfo *);
603 :
604 : static netCDFDataset *CreateLL(const char *pszFilename, int nXSize,
605 : int nYSize, int nBands, char **papszOptions);
606 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
607 : int nBands, GDALDataType eType,
608 : char **papszOptions);
609 : static GDALDataset *CreateCopy(const char *pszFilename,
610 : GDALDataset *poSrcDS, int bStrict,
611 : char **papszOptions,
612 : GDALProgressFunc pfnProgress,
613 : void *pProgressData);
614 :
615 : static GDALDataset *
616 : CreateMultiDimensional(const char *pszFilename,
617 : CSLConstList papszRootGroupOptions,
618 : CSLConstList papzOptions);
619 : };
620 :
621 : class netCDFLayer final : public OGRLayer
622 : {
623 : typedef union
624 : {
625 : signed char chVal;
626 : unsigned char uchVal;
627 : short sVal;
628 : unsigned short usVal;
629 : int nVal;
630 : unsigned int unVal;
631 : GIntBig nVal64;
632 : GUIntBig unVal64;
633 : float fVal;
634 : double dfVal;
635 : } NCDFNoDataUnion;
636 :
637 : typedef struct
638 : {
639 : NCDFNoDataUnion uNoData;
640 : nc_type nType;
641 : int nVarId;
642 : int nDimCount;
643 : bool bHasWarnedAboutTruncation;
644 : int nMainDimId;
645 : int nSecDimId;
646 : bool bIsDays;
647 : } FieldDesc;
648 :
649 : netCDFDataset *m_poDS;
650 : int m_nLayerCDFId;
651 : OGRFeatureDefn *m_poFeatureDefn;
652 : CPLString m_osRecordDimName;
653 : int m_nRecordDimID;
654 : int m_nDefaultWidth;
655 : bool m_bAutoGrowStrings;
656 : int m_nDefaultMaxWidthDimId;
657 : int m_nXVarID;
658 : int m_nYVarID;
659 : int m_nZVarID;
660 : nc_type m_nXVarNCDFType;
661 : nc_type m_nYVarNCDFType;
662 : nc_type m_nZVarNCDFType;
663 : NCDFNoDataUnion m_uXVarNoData;
664 : NCDFNoDataUnion m_uYVarNoData;
665 : NCDFNoDataUnion m_uZVarNoData;
666 : CPLString m_osWKTVarName;
667 : int m_nWKTMaxWidth;
668 : int m_nWKTMaxWidthDimId;
669 : int m_nWKTVarID;
670 : nc_type m_nWKTNCDFType;
671 : CPLString m_osCoordinatesValue;
672 : std::vector<FieldDesc> m_aoFieldDesc;
673 : bool m_bLegacyCreateMode;
674 : int m_nCurFeatureId;
675 : CPLString m_osGridMapping;
676 : bool m_bWriteGDALTags;
677 : bool m_bUseStringInNC4;
678 : bool m_bNCDumpCompat;
679 :
680 : CPLString m_osProfileDimName;
681 : int m_nProfileDimID;
682 : CPLString m_osProfileVariables;
683 : int m_nProfileVarID;
684 : bool m_bProfileVarUnlimited;
685 : int m_nParentIndexVarID;
686 : std::shared_ptr<nccfdriver::SGeometry_Reader> m_simpleGeometryReader;
687 : std::unique_ptr<nccfdriver::netCDFVID>
688 : layerVID_alloc; // Allocation wrapper for group specific netCDFVID
689 : nccfdriver::netCDFVID &layerVID; // refers to the "correct" VID
690 : std::string m_sgCRSname;
691 : size_t m_SGeometryFeatInd;
692 :
693 : const netCDFWriterConfigLayer *m_poLayerConfig;
694 :
695 : nccfdriver::ncLayer_SG_Metadata m_layerSGDefn;
696 :
697 : OGRFeature *GetNextRawFeature();
698 : double Get1DVarAsDouble(int nVarId, nc_type nVarType, size_t nIndex,
699 : const NCDFNoDataUnion &noDataVal, bool *pbIsNoData);
700 : CPLErr GetFillValue(int nVarID, char **ppszValue);
701 : CPLErr GetFillValue(int nVarID, double *pdfValue);
702 : void GetNoDataValueForFloat(int nVarId, NCDFNoDataUnion *puNoData);
703 : void GetNoDataValueForDouble(int nVarId, NCDFNoDataUnion *puNoData);
704 : void GetNoDataValue(int nVarId, nc_type nVarType,
705 : NCDFNoDataUnion *puNoData);
706 : bool FillVarFromFeature(OGRFeature *poFeature, int nMainDimId,
707 : size_t nIndex);
708 : OGRFeature *buildSGeometryFeature(size_t featureInd);
709 : void netCDFWriteAttributesFromConf(
710 : int cdfid, int varid,
711 : const std::vector<netCDFWriterConfigAttribute> &aoAttributes);
712 :
713 : protected:
714 : bool FillFeatureFromVar(OGRFeature *poFeature, int nMainDimId,
715 : size_t nIndex);
716 :
717 : public:
718 : netCDFLayer(netCDFDataset *poDS, int nLayerCDFId, const char *pszName,
719 : OGRwkbGeometryType eGeomType, OGRSpatialReference *poSRS);
720 : virtual ~netCDFLayer();
721 :
722 : bool Create(char **papszOptions,
723 : const netCDFWriterConfigLayer *poLayerConfig);
724 : void SetRecordDimID(int nRecordDimID);
725 : void SetXYZVars(int nXVarId, int nYVarId, int nZVarId);
726 : void SetWKTGeometryField(const char *pszWKTVarName);
727 : void SetGridMapping(const char *pszGridMapping);
728 : void SetProfile(int nProfileDimID, int nParentIndexVarID);
729 :
730 66 : void EnableSGBypass()
731 : {
732 66 : this->m_bLegacyCreateMode = false;
733 66 : }
734 :
735 : bool AddField(int nVarId);
736 :
737 3 : int GetCDFID() const
738 : {
739 3 : return m_nLayerCDFId;
740 : }
741 :
742 14 : void SetCDFID(int nId)
743 : {
744 14 : m_nLayerCDFId = nId;
745 14 : }
746 :
747 66 : void SetSGeometryRepresentation(
748 : const std::shared_ptr<nccfdriver::SGeometry_Reader> &sg)
749 : {
750 66 : m_simpleGeometryReader = sg;
751 66 : }
752 :
753 45 : nccfdriver::ncLayer_SG_Metadata &getLayerSGMetadata()
754 : {
755 45 : return m_layerSGDefn;
756 : }
757 :
758 : virtual void ResetReading() override;
759 : virtual OGRFeature *GetNextFeature() override;
760 :
761 : virtual GIntBig GetFeatureCount(int bForce) override;
762 :
763 : virtual int TestCapability(const char *pszCap) override;
764 :
765 : virtual OGRFeatureDefn *GetLayerDefn() override;
766 :
767 : virtual OGRErr ICreateFeature(OGRFeature *poFeature) override;
768 : virtual OGRErr CreateField(const OGRFieldDefn *poFieldDefn,
769 : int bApproxOK) override;
770 :
771 : GDALDataset *GetDataset() override;
772 : };
773 :
774 : std::string NCDFGetProjectedCFUnit(const OGRSpatialReference *poSRS);
775 : void NCDFWriteLonLatVarsAttributes(nccfdriver::netCDFVID &vcdf, int nVarLonID,
776 : int nVarLatID);
777 : void NCDFWriteRLonRLatVarsAttributes(nccfdriver::netCDFVID &vcdf,
778 : int nVarRLonID, int nVarRLatID);
779 : void NCDFWriteXYVarsAttributes(nccfdriver::netCDFVID &vcdf, int nVarXID,
780 : int nVarYID, const OGRSpatialReference *poSRS);
781 : int NCDFWriteSRSVariable(int cdfid, const OGRSpatialReference *poSRS,
782 : char **ppszCFProjection, bool bWriteGDALTags,
783 : const std::string & = std::string());
784 :
785 : double NCDFGetDefaultNoDataValue(int nCdfId, int nVarId, int nVarType,
786 : bool &bGotNoData);
787 :
788 : int64_t NCDFGetDefaultNoDataValueAsInt64(int nCdfId, int nVarId,
789 : bool &bGotNoData);
790 : uint64_t NCDFGetDefaultNoDataValueAsUInt64(int nCdfId, int nVarId,
791 : bool &bGotNoData);
792 :
793 : CPLErr NCDFGetAttr(int nCdfId, int nVarId, const char *pszAttrName,
794 : double *pdfValue);
795 : CPLErr NCDFGetAttr(int nCdfId, int nVarId, const char *pszAttrName,
796 : char **pszValue);
797 : bool NCDFIsUnlimitedDim(bool bIsNC4, int cdfid, int nDimId);
798 : bool NCDFIsUserDefinedType(int ncid, int type);
799 :
800 : CPLString NCDFGetGroupFullName(int nGroupId);
801 :
802 : CPLErr NCDFResolveVar(int nStartGroupId, const char *pszVar, int *pnGroupId,
803 : int *pnVarId, bool bMandatory = false);
804 :
805 : // Dimension check functions.
806 : bool NCDFIsVarLongitude(int nCdfId, int nVarId, const char *pszVarName);
807 : bool NCDFIsVarLatitude(int nCdfId, int nVarId, const char *pszVarName);
808 : bool NCDFIsVarProjectionX(int nCdfId, int nVarId, const char *pszVarName);
809 : bool NCDFIsVarProjectionY(int nCdfId, int nVarId, const char *pszVarName);
810 : bool NCDFIsVarVerticalCoord(int nCdfId, int nVarId, const char *pszVarName);
811 : bool NCDFIsVarTimeCoord(int nCdfId, int nVarId, const char *pszVarName);
812 :
813 : std::string NCDFReadMetadataAsJson(int cdfid);
814 :
815 : char **NCDFTokenizeCoordinatesAttribute(const char *pszCoordinates);
816 :
817 : extern CPLMutex *hNCMutex;
818 :
819 : #ifdef ENABLE_NCDUMP
820 : bool netCDFDatasetCreateTempFile(NetCDFFormatEnum eFormat,
821 : const char *pszTmpFilename, VSILFILE *fpSrc);
822 : #endif
823 :
824 : int GDAL_nc_open(const char *pszFilename, int nMode, int *pID);
825 : int GDAL_nc_close(int cdfid);
826 :
827 : #endif
|