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