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