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 1167 : netCDFWriterConfiguration() : m_bIsValid(false)
318 : {
319 1167 : }
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() 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 : char **GetMetadata(const char *) override;
569 :
570 : CPLErr SetMetadataItem(const char *pszName, const char *pszValue,
571 : const char *pszDomain = "") override;
572 : CPLErr SetMetadata(char **papszMD, const char *pszDomain = "") override;
573 :
574 : int TestCapability(const char *pszCap) const override;
575 :
576 2408 : int GetLayerCount() const override
577 : {
578 2408 : return static_cast<int>(this->papoLayers.size());
579 : }
580 :
581 : const OGRLayer *GetLayer(int nIdx) const override;
582 :
583 : std::shared_ptr<GDALGroup> GetRootGroup() const override;
584 :
585 184 : int GetCDFID() const
586 : {
587 184 : return cdfid;
588 : }
589 :
590 2025 : inline bool HasInfiniteRecordDim()
591 : {
592 2025 : return !bSGSupport;
593 : }
594 :
595 : /* static functions */
596 : static GDALDataset *Open(GDALOpenInfo *);
597 :
598 : static netCDFDataset *CreateLL(const char *pszFilename, int nXSize,
599 : int nYSize, int nBands, char **papszOptions);
600 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
601 : int nBands, GDALDataType eType,
602 : char **papszOptions);
603 : static GDALDataset *CreateCopy(const char *pszFilename,
604 : GDALDataset *poSrcDS, int bStrict,
605 : char **papszOptions,
606 : GDALProgressFunc pfnProgress,
607 : void *pProgressData);
608 :
609 : static GDALDataset *
610 : CreateMultiDimensional(const char *pszFilename,
611 : CSLConstList papszRootGroupOptions,
612 : CSLConstList papzOptions);
613 : };
614 :
615 : class netCDFLayer final : public OGRLayer
616 : {
617 : typedef union
618 : {
619 : signed char chVal;
620 : unsigned char uchVal;
621 : short sVal;
622 : unsigned short usVal;
623 : int nVal;
624 : unsigned int unVal;
625 : GIntBig nVal64;
626 : GUIntBig unVal64;
627 : float fVal;
628 : double dfVal;
629 : } NCDFNoDataUnion;
630 :
631 : typedef struct
632 : {
633 : NCDFNoDataUnion uNoData;
634 : nc_type nType;
635 : int nVarId;
636 : int nDimCount;
637 : bool bHasWarnedAboutTruncation;
638 : int nMainDimId;
639 : int nSecDimId;
640 : bool bIsDays;
641 : } FieldDesc;
642 :
643 : netCDFDataset *m_poDS;
644 : int m_nLayerCDFId;
645 : OGRFeatureDefn *m_poFeatureDefn;
646 : CPLString m_osRecordDimName;
647 : int m_nRecordDimID;
648 : int m_nDefaultWidth;
649 : bool m_bAutoGrowStrings;
650 : int m_nDefaultMaxWidthDimId;
651 : int m_nXVarID;
652 : int m_nYVarID;
653 : int m_nZVarID;
654 : nc_type m_nXVarNCDFType;
655 : nc_type m_nYVarNCDFType;
656 : nc_type m_nZVarNCDFType;
657 : NCDFNoDataUnion m_uXVarNoData;
658 : NCDFNoDataUnion m_uYVarNoData;
659 : NCDFNoDataUnion m_uZVarNoData;
660 : CPLString m_osWKTVarName;
661 : int m_nWKTMaxWidth;
662 : int m_nWKTMaxWidthDimId;
663 : int m_nWKTVarID;
664 : nc_type m_nWKTNCDFType;
665 : CPLString m_osCoordinatesValue;
666 : std::vector<FieldDesc> m_aoFieldDesc;
667 : bool m_bLegacyCreateMode;
668 : int m_nCurFeatureId;
669 : CPLString m_osGridMapping;
670 : bool m_bWriteGDALTags;
671 : bool m_bUseStringInNC4;
672 : bool m_bNCDumpCompat;
673 :
674 : CPLString m_osProfileDimName;
675 : int m_nProfileDimID;
676 : CPLString m_osProfileVariables;
677 : int m_nProfileVarID;
678 : bool m_bProfileVarUnlimited;
679 : int m_nParentIndexVarID;
680 : std::shared_ptr<nccfdriver::SGeometry_Reader> m_simpleGeometryReader;
681 : std::unique_ptr<nccfdriver::netCDFVID>
682 : layerVID_alloc; // Allocation wrapper for group specific netCDFVID
683 : nccfdriver::netCDFVID &layerVID; // refers to the "correct" VID
684 : std::string m_sgCRSname;
685 : size_t m_SGeometryFeatInd;
686 :
687 : const netCDFWriterConfigLayer *m_poLayerConfig;
688 :
689 : nccfdriver::ncLayer_SG_Metadata m_layerSGDefn;
690 :
691 : OGRFeature *GetNextRawFeature();
692 : double Get1DVarAsDouble(int nVarId, nc_type nVarType, size_t nIndex,
693 : const NCDFNoDataUnion &noDataVal, bool *pbIsNoData);
694 : CPLErr GetFillValue(int nVarID, char **ppszValue);
695 : CPLErr GetFillValue(int nVarID, double *pdfValue);
696 : void GetNoDataValueForFloat(int nVarId, NCDFNoDataUnion *puNoData);
697 : void GetNoDataValueForDouble(int nVarId, NCDFNoDataUnion *puNoData);
698 : void GetNoDataValue(int nVarId, nc_type nVarType,
699 : NCDFNoDataUnion *puNoData);
700 : bool FillVarFromFeature(OGRFeature *poFeature, int nMainDimId,
701 : size_t nIndex);
702 : OGRFeature *buildSGeometryFeature(size_t featureInd);
703 : void netCDFWriteAttributesFromConf(
704 : int cdfid, int varid,
705 : const std::vector<netCDFWriterConfigAttribute> &aoAttributes);
706 :
707 : protected:
708 : bool FillFeatureFromVar(OGRFeature *poFeature, int nMainDimId,
709 : size_t nIndex);
710 :
711 : public:
712 : netCDFLayer(netCDFDataset *poDS, int nLayerCDFId, const char *pszName,
713 : OGRwkbGeometryType eGeomType, OGRSpatialReference *poSRS);
714 : ~netCDFLayer() override;
715 :
716 : bool Create(char **papszOptions,
717 : const netCDFWriterConfigLayer *poLayerConfig);
718 : void SetRecordDimID(int nRecordDimID);
719 : void SetXYZVars(int nXVarId, int nYVarId, int nZVarId);
720 : void SetWKTGeometryField(const char *pszWKTVarName);
721 : void SetGridMapping(const char *pszGridMapping);
722 : void SetProfile(int nProfileDimID, int nParentIndexVarID);
723 :
724 66 : void EnableSGBypass()
725 : {
726 66 : this->m_bLegacyCreateMode = false;
727 66 : }
728 :
729 : bool AddField(int nVarId);
730 :
731 3 : int GetCDFID() const
732 : {
733 3 : return m_nLayerCDFId;
734 : }
735 :
736 14 : void SetCDFID(int nId)
737 : {
738 14 : m_nLayerCDFId = nId;
739 14 : }
740 :
741 66 : void SetSGeometryRepresentation(
742 : const std::shared_ptr<nccfdriver::SGeometry_Reader> &sg)
743 : {
744 66 : m_simpleGeometryReader = sg;
745 66 : }
746 :
747 45 : nccfdriver::ncLayer_SG_Metadata &getLayerSGMetadata()
748 : {
749 45 : return m_layerSGDefn;
750 : }
751 :
752 : void ResetReading() override;
753 : OGRFeature *GetNextFeature() override;
754 :
755 : GIntBig GetFeatureCount(int bForce) override;
756 :
757 : int TestCapability(const char *pszCap) const override;
758 :
759 : using OGRLayer::GetLayerDefn;
760 : const OGRFeatureDefn *GetLayerDefn() const override;
761 :
762 : OGRErr ICreateFeature(OGRFeature *poFeature) override;
763 : virtual OGRErr CreateField(const OGRFieldDefn *poFieldDefn,
764 : int bApproxOK) override;
765 :
766 : GDALDataset *GetDataset() override;
767 : };
768 :
769 : std::string NCDFGetProjectedCFUnit(const OGRSpatialReference *poSRS);
770 : void NCDFWriteLonLatVarsAttributes(nccfdriver::netCDFVID &vcdf, int nVarLonID,
771 : int nVarLatID);
772 : void NCDFWriteRLonRLatVarsAttributes(nccfdriver::netCDFVID &vcdf,
773 : int nVarRLonID, int nVarRLatID);
774 : void NCDFWriteXYVarsAttributes(nccfdriver::netCDFVID &vcdf, int nVarXID,
775 : int nVarYID, const OGRSpatialReference *poSRS);
776 : int NCDFWriteSRSVariable(int cdfid, const OGRSpatialReference *poSRS,
777 : char **ppszCFProjection, bool bWriteGDALTags,
778 : const std::string & = std::string());
779 :
780 : double NCDFGetDefaultNoDataValue(int nCdfId, int nVarId, int nVarType,
781 : bool &bGotNoData);
782 :
783 : int64_t NCDFGetDefaultNoDataValueAsInt64(int nCdfId, int nVarId,
784 : bool &bGotNoData);
785 : uint64_t NCDFGetDefaultNoDataValueAsUInt64(int nCdfId, int nVarId,
786 : bool &bGotNoData);
787 :
788 : CPLErr NCDFGetAttr(int nCdfId, int nVarId, const char *pszAttrName,
789 : double *pdfValue);
790 : CPLErr NCDFGetAttr(int nCdfId, int nVarId, const char *pszAttrName,
791 : char **pszValue);
792 : bool NCDFIsUnlimitedDim(bool bIsNC4, int cdfid, int nDimId);
793 : bool NCDFIsUserDefinedType(int ncid, int type);
794 :
795 : CPLString NCDFGetGroupFullName(int nGroupId);
796 :
797 : CPLErr NCDFResolveVar(int nStartGroupId, const char *pszVar, int *pnGroupId,
798 : int *pnVarId, bool bMandatory = false);
799 :
800 : // Dimension check functions.
801 : bool NCDFIsVarLongitude(int nCdfId, int nVarId, const char *pszVarName);
802 : bool NCDFIsVarLatitude(int nCdfId, int nVarId, const char *pszVarName);
803 : bool NCDFIsVarProjectionX(int nCdfId, int nVarId, const char *pszVarName);
804 : bool NCDFIsVarProjectionY(int nCdfId, int nVarId, const char *pszVarName);
805 : bool NCDFIsVarVerticalCoord(int nCdfId, int nVarId, const char *pszVarName);
806 : bool NCDFIsVarTimeCoord(int nCdfId, int nVarId, const char *pszVarName);
807 :
808 : std::string NCDFReadMetadataAsJson(int cdfid);
809 :
810 : char **NCDFTokenizeCoordinatesAttribute(const char *pszCoordinates);
811 :
812 : extern CPLMutex *hNCMutex;
813 :
814 : #ifdef ENABLE_NCDUMP
815 : bool netCDFDatasetCreateTempFile(NetCDFFormatEnum eFormat,
816 : const char *pszTmpFilename, VSILFILE *fpSrc);
817 : #endif
818 :
819 : int GDAL_nc_open(const char *pszFilename, int nMode, int *pID);
820 : int GDAL_nc_close(int cdfid);
821 :
822 : #endif
|