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 1205 : netCDFWriterConfiguration() : m_bIsValid(false)
318 : {
319 1205 : }
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) const;
472 :
473 : std::vector<std::string>
474 : FetchStandardParallels(const char *pszGridMappingValue) const;
475 :
476 : const char *FetchAttr(const char *pszVarFullName,
477 : const char *pszAttr) const;
478 : const char *FetchAttr(int nGroupId, int nVarId, const char *pszAttr) const;
479 :
480 : void ProcessCreationOptions();
481 : int DefVarDeflate(int nVarId, bool bChunkingArg = true) const;
482 : CPLErr AddProjectionVars(bool bDefsOnly, GDALProgressFunc pfnProgress,
483 : void *pProgressData);
484 : bool AddGridMappingRef();
485 :
486 10 : bool GetDefineMode() const
487 : {
488 10 : return bDefineMode;
489 : }
490 :
491 : bool SetDefineMode(bool bNewDefineMode);
492 :
493 : CPLErr ReadAttributes(int, int);
494 :
495 : void CreateSubDatasetList(int nGroupId);
496 :
497 : void SetProjectionFromVar(int nGroupId, int nVarId, bool bReadSRSOnly,
498 : const char *pszGivenGM, std::string *,
499 : nccfdriver::SGeometry_Reader *,
500 : std::vector<std::string> *paosRemovedMDItems);
501 : void SetProjectionFromVar(int nGroupId, int nVarId, bool bReadSRSOnly);
502 :
503 : bool ProcessNASAL2OceanGeoLocation(int nGroupId, int nVarId);
504 :
505 : bool ProcessNASAEMITGeoLocation(int nGroupId, int nVarId);
506 :
507 : int ProcessCFGeolocation(int nGroupId, int nVarId,
508 : const std::string &osGeolocWKT,
509 : std::string &osGeolocXNameOut,
510 : std::string &osGeolocYNameOut);
511 : CPLErr Set1DGeolocation(int nGroupId, int nVarId, const char *szDimName);
512 : double *Get1DGeolocation(const char *szDimName, int &nVarLen);
513 :
514 : static bool CloneAttributes(int old_cdfid, int new_cdfid, int nSrcVarId,
515 : int nDstVarId);
516 : static bool CloneVariableContent(int old_cdfid, int new_cdfid,
517 : int nSrcVarId, int nDstVarId);
518 : static bool CloneGrp(int nOldGrpId, int nNewGrpId, bool bIsNC4,
519 : int nLayerId, int nDimIdToGrow, size_t nNewSize);
520 : bool GrowDim(int nLayerId, int nDimIdToGrow, size_t nNewSize);
521 :
522 : void ProcessSentinel3_SRAL_MWR();
523 :
524 : CPLErr
525 : FilterVars(int nCdfId, bool bKeepRasters, bool bKeepVectors,
526 : char **papszIgnoreVars, int *pnRasterVars, int *pnGroupId,
527 : int *pnVarId, int *pnIgnoredVars,
528 : // key is (dim1Id, dim2Id, nc_type varType)
529 : // value is (groupId, varId)
530 : std::map<std::array<int, 3>, std::vector<std::pair<int, int>>>
531 : &oMap2DDimsToGroupAndVar);
532 : CPLErr CreateGrpVectorLayers(int nCdfId, const CPLString &osFeatureType,
533 : const std::vector<int> &anPotentialVectorVarID,
534 : const std::map<int, int> &oMapDimIdToCount,
535 : int nVarXId, int nVarYId, int nVarZId,
536 : int nProfileDimId, int nParentIndexVarID,
537 : bool bKeepRasters);
538 :
539 : bool DetectAndFillSGLayers(int ncid);
540 : CPLErr LoadSGVarIntoLayer(int ncid, int nc_basevarId);
541 :
542 : static GDALDataset *OpenMultiDim(GDALOpenInfo *);
543 : std::shared_ptr<GDALGroup> m_poRootGroup{};
544 :
545 : void SetGeoTransformNoUpdate(const GDALGeoTransform >);
546 : void SetSpatialRefNoUpdate(const OGRSpatialReference *);
547 :
548 : protected:
549 : OGRLayer *ICreateLayer(const char *pszName,
550 : const OGRGeomFieldDefn *poGeomFieldDefn,
551 : CSLConstList papszOptions) override;
552 :
553 : CPLErr Close(GDALProgressFunc = nullptr, void * = nullptr) override;
554 :
555 : public:
556 : netCDFDataset();
557 : ~netCDFDataset() override;
558 : bool SGCommitPendingTransaction();
559 : void SGLogPendingTransaction();
560 : static std::string generateLogName();
561 :
562 : /* Projection/GT */
563 : CPLErr GetGeoTransform(GDALGeoTransform >) const override;
564 : CPLErr SetGeoTransform(const GDALGeoTransform >) override;
565 : const OGRSpatialReference *GetSpatialRef() const override;
566 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
567 :
568 : char **GetMetadataDomainList() override;
569 : CSLConstList GetMetadata(const char *) override;
570 :
571 : CPLErr SetMetadataItem(const char *pszName, const char *pszValue,
572 : const char *pszDomain = "") override;
573 : CPLErr SetMetadata(CSLConstList papszMD,
574 : const char *pszDomain = "") override;
575 :
576 : int TestCapability(const char *pszCap) const override;
577 :
578 2446 : int GetLayerCount() const override
579 : {
580 2446 : return static_cast<int>(this->papoLayers.size());
581 : }
582 :
583 : const OGRLayer *GetLayer(int nIdx) const override;
584 :
585 : std::shared_ptr<GDALGroup> GetRootGroup() const override;
586 :
587 188 : int GetCDFID() const
588 : {
589 188 : return cdfid;
590 : }
591 :
592 2025 : inline bool HasInfiniteRecordDim()
593 : {
594 2025 : return !bSGSupport;
595 : }
596 :
597 : /* static functions */
598 : static GDALDataset *Open(GDALOpenInfo *);
599 :
600 : static netCDFDataset *CreateLL(const char *pszFilename, int nXSize,
601 : int nYSize, int nBands,
602 : CSLConstList papszOptions);
603 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
604 : int nBands, GDALDataType eType,
605 : CSLConstList papszOptions);
606 : static GDALDataset *CreateCopy(const char *pszFilename,
607 : GDALDataset *poSrcDS, int bStrict,
608 : CSLConstList papszOptions,
609 : GDALProgressFunc pfnProgress,
610 : void *pProgressData);
611 :
612 : static GDALDataset *
613 : CreateMultiDimensional(const char *pszFilename,
614 : CSLConstList papszRootGroupOptions,
615 : CSLConstList papzOptions);
616 : };
617 :
618 : class netCDFLayer final : public OGRLayer
619 : {
620 : typedef union
621 : {
622 : signed char chVal;
623 : unsigned char uchVal;
624 : short sVal;
625 : unsigned short usVal;
626 : int nVal;
627 : unsigned int unVal;
628 : GIntBig nVal64;
629 : GUIntBig unVal64;
630 : float fVal;
631 : double dfVal;
632 : } NCDFNoDataUnion;
633 :
634 : typedef struct
635 : {
636 : NCDFNoDataUnion uNoData;
637 : nc_type nType;
638 : int nVarId;
639 : int nDimCount;
640 : bool bHasWarnedAboutTruncation;
641 : int nMainDimId;
642 : int nSecDimId;
643 : bool bIsDays;
644 : } FieldDesc;
645 :
646 : netCDFDataset *m_poDS;
647 : int m_nLayerCDFId;
648 : OGRFeatureDefn *m_poFeatureDefn;
649 : CPLString m_osRecordDimName;
650 : int m_nRecordDimID;
651 : int m_nDefaultWidth;
652 : bool m_bAutoGrowStrings;
653 : int m_nDefaultMaxWidthDimId;
654 : int m_nXVarID;
655 : int m_nYVarID;
656 : int m_nZVarID;
657 : nc_type m_nXVarNCDFType;
658 : nc_type m_nYVarNCDFType;
659 : nc_type m_nZVarNCDFType;
660 : NCDFNoDataUnion m_uXVarNoData;
661 : NCDFNoDataUnion m_uYVarNoData;
662 : NCDFNoDataUnion m_uZVarNoData;
663 : CPLString m_osWKTVarName;
664 : int m_nWKTMaxWidth;
665 : int m_nWKTMaxWidthDimId;
666 : int m_nWKTVarID;
667 : nc_type m_nWKTNCDFType;
668 : CPLString m_osCoordinatesValue;
669 : std::vector<FieldDesc> m_aoFieldDesc;
670 : bool m_bLegacyCreateMode;
671 : int m_nCurFeatureId;
672 : CPLString m_osGridMapping;
673 : bool m_bWriteGDALTags;
674 : bool m_bUseStringInNC4;
675 : bool m_bNCDumpCompat;
676 :
677 : CPLString m_osProfileDimName;
678 : int m_nProfileDimID;
679 : CPLString m_osProfileVariables;
680 : int m_nProfileVarID;
681 : bool m_bProfileVarUnlimited;
682 : int m_nParentIndexVarID;
683 : std::shared_ptr<nccfdriver::SGeometry_Reader> m_simpleGeometryReader;
684 : std::unique_ptr<nccfdriver::netCDFVID>
685 : layerVID_alloc; // Allocation wrapper for group specific netCDFVID
686 : nccfdriver::netCDFVID &layerVID; // refers to the "correct" VID
687 : std::string m_sgCRSname;
688 : size_t m_SGeometryFeatInd;
689 :
690 : const netCDFWriterConfigLayer *m_poLayerConfig;
691 :
692 : nccfdriver::ncLayer_SG_Metadata m_layerSGDefn;
693 :
694 : OGRFeature *GetNextRawFeature();
695 : double Get1DVarAsDouble(int nVarId, nc_type nVarType, size_t nIndex,
696 : const NCDFNoDataUnion &noDataVal, bool *pbIsNoData);
697 : CPLErr GetFillValue(int nVarID, char **ppszValue);
698 : CPLErr GetFillValue(int nVarID, double *pdfValue);
699 : void GetNoDataValueForFloat(int nVarId, NCDFNoDataUnion *puNoData);
700 : void GetNoDataValueForDouble(int nVarId, NCDFNoDataUnion *puNoData);
701 : void GetNoDataValue(int nVarId, nc_type nVarType,
702 : NCDFNoDataUnion *puNoData);
703 : bool FillVarFromFeature(OGRFeature *poFeature, int nMainDimId,
704 : size_t nIndex);
705 : OGRFeature *buildSGeometryFeature(size_t featureInd);
706 : void netCDFWriteAttributesFromConf(
707 : int cdfid, int varid,
708 : const std::vector<netCDFWriterConfigAttribute> &aoAttributes);
709 :
710 : protected:
711 : bool FillFeatureFromVar(OGRFeature *poFeature, int nMainDimId,
712 : size_t nIndex);
713 :
714 : public:
715 : netCDFLayer(netCDFDataset *poDS, int nLayerCDFId, const char *pszName,
716 : OGRwkbGeometryType eGeomType, OGRSpatialReference *poSRS);
717 : ~netCDFLayer() override;
718 :
719 : bool Create(CSLConstList papszOptions,
720 : const netCDFWriterConfigLayer *poLayerConfig);
721 : void SetRecordDimID(int nRecordDimID);
722 : void SetXYZVars(int nXVarId, int nYVarId, int nZVarId);
723 : void SetWKTGeometryField(const char *pszWKTVarName);
724 : void SetGridMapping(const char *pszGridMapping);
725 : void SetProfile(int nProfileDimID, int nParentIndexVarID);
726 :
727 66 : void EnableSGBypass()
728 : {
729 66 : this->m_bLegacyCreateMode = false;
730 66 : }
731 :
732 : bool AddField(int nVarId);
733 :
734 3 : int GetCDFID() const
735 : {
736 3 : return m_nLayerCDFId;
737 : }
738 :
739 14 : void SetCDFID(int nId)
740 : {
741 14 : m_nLayerCDFId = nId;
742 14 : }
743 :
744 66 : void SetSGeometryRepresentation(
745 : const std::shared_ptr<nccfdriver::SGeometry_Reader> &sg)
746 : {
747 66 : m_simpleGeometryReader = sg;
748 66 : }
749 :
750 45 : nccfdriver::ncLayer_SG_Metadata &getLayerSGMetadata()
751 : {
752 45 : return m_layerSGDefn;
753 : }
754 :
755 : void ResetReading() override;
756 : OGRFeature *GetNextFeature() override;
757 :
758 : GIntBig GetFeatureCount(int bForce) override;
759 :
760 : int TestCapability(const char *pszCap) const override;
761 :
762 : using OGRLayer::GetLayerDefn;
763 : const OGRFeatureDefn *GetLayerDefn() const override;
764 :
765 : OGRErr ICreateFeature(OGRFeature *poFeature) override;
766 : virtual OGRErr CreateField(const OGRFieldDefn *poFieldDefn,
767 : int bApproxOK) override;
768 :
769 : GDALDataset *GetDataset() override;
770 : };
771 :
772 : std::string NCDFGetProjectedCFUnit(const OGRSpatialReference *poSRS);
773 : void NCDFWriteLonLatVarsAttributes(nccfdriver::netCDFVID &vcdf, int nVarLonID,
774 : int nVarLatID);
775 : void NCDFWriteRLonRLatVarsAttributes(nccfdriver::netCDFVID &vcdf,
776 : int nVarRLonID, int nVarRLatID);
777 : void NCDFWriteXYVarsAttributes(nccfdriver::netCDFVID &vcdf, int nVarXID,
778 : int nVarYID, const OGRSpatialReference *poSRS);
779 : int NCDFWriteSRSVariable(int cdfid, const OGRSpatialReference *poSRS,
780 : char **ppszCFProjection, bool bWriteGDALTags,
781 : const std::string & = std::string());
782 :
783 : double NCDFGetDefaultNoDataValue(int nCdfId, int nVarId, int nVarType,
784 : bool &bGotNoData);
785 :
786 : int64_t NCDFGetDefaultNoDataValueAsInt64(int nCdfId, int nVarId,
787 : bool &bGotNoData);
788 : uint64_t NCDFGetDefaultNoDataValueAsUInt64(int nCdfId, int nVarId,
789 : bool &bGotNoData);
790 :
791 : CPLErr NCDFGetAttr(int nCdfId, int nVarId, const char *pszAttrName,
792 : double *pdfValue);
793 : CPLErr NCDFGetAttr(int nCdfId, int nVarId, const char *pszAttrName,
794 : char **pszValue);
795 : bool NCDFIsUnlimitedDim(bool bIsNC4, int cdfid, int nDimId);
796 : bool NCDFIsUserDefinedType(int ncid, int type);
797 :
798 : CPLString NCDFGetGroupFullName(int nGroupId);
799 :
800 : CPLErr NCDFResolveVar(int nStartGroupId, const char *pszVar, int *pnGroupId,
801 : int *pnVarId, bool bMandatory = false);
802 :
803 : // Dimension check functions.
804 : bool NCDFIsVarLongitude(int nCdfId, int nVarId, const char *pszVarName);
805 : bool NCDFIsVarLatitude(int nCdfId, int nVarId, const char *pszVarName);
806 : bool NCDFIsVarProjectionX(int nCdfId, int nVarId, const char *pszVarName);
807 : bool NCDFIsVarProjectionY(int nCdfId, int nVarId, const char *pszVarName);
808 : bool NCDFIsVarVerticalCoord(int nCdfId, int nVarId, const char *pszVarName);
809 : bool NCDFIsVarTimeCoord(int nCdfId, int nVarId, const char *pszVarName);
810 :
811 : std::string NCDFReadMetadataAsJson(int cdfid);
812 :
813 : char **NCDFTokenizeCoordinatesAttribute(const char *pszCoordinates);
814 :
815 : extern CPLMutex *hNCMutex;
816 :
817 : #ifdef ENABLE_NCDUMP
818 : bool netCDFDatasetCreateTempFile(NetCDFFormatEnum eFormat,
819 : const char *pszTmpFilename, VSILFILE *fpSrc);
820 : #endif
821 :
822 : int GDAL_nc_open(const char *pszFilename, int nMode, int *pID);
823 : int GDAL_nc_close(int cdfid);
824 :
825 : #endif
|