Line data Source code
1 : /******************************************************************************
2 : * $Id$
3 : *
4 : * Project: netCDF read/write Driver
5 : * Purpose: GDAL bindings over netCDF library.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2004, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #ifndef NETCDFDATASET_H_INCLUDED_
31 : #define NETCDFDATASET_H_INCLUDED_
32 :
33 : #include <array>
34 : #include <ctime>
35 : #include <cfloat>
36 : #include <cstdlib>
37 : #include <functional>
38 : #include <map>
39 : #include <memory>
40 : #include <utility>
41 : #include <vector>
42 :
43 : #include "cpl_mem_cache.h"
44 : #include "cpl_string.h"
45 : #include "gdal_frmts.h"
46 : #include "gdal_pam.h"
47 : #include "gdal_priv.h"
48 : #include "netcdf.h"
49 : #include "netcdfformatenum.h"
50 : #include "netcdfsg.h"
51 : #include "netcdfsgwriterutil.h"
52 : #include "ogr_spatialref.h"
53 : #include "ogrsf_frmts.h"
54 : #include "netcdfuffd.h"
55 : #include "netcdf_cf_constants.h"
56 :
57 : #if CPL_IS_LSB
58 : #define PLATFORM_HEADER 1
59 : #else
60 : #define PLATFORM_HEADER 0
61 : #endif
62 :
63 : /************************************************************************/
64 : /* ==================================================================== */
65 : /* defines */
66 : /* ==================================================================== */
67 : /************************************************************************/
68 :
69 : /* -------------------------------------------------------------------- */
70 : /* Creation and Configuration Options */
71 : /* -------------------------------------------------------------------- */
72 :
73 : /* Creation options
74 :
75 : FORMAT=NC/NC2/NC4/NC4C (COMPRESS=DEFLATE sets FORMAT=NC4C)
76 : COMPRESS=NONE/DEFLATE (default: NONE)
77 : ZLEVEL=[1-9] (default: 1)
78 : WRITE_BOTTOMUP=YES/NO (default: YES)
79 : WRITE_GDAL_TAGS=YES/NO (default: YES)
80 : WRITE_LONLAT=YES/NO/IF_NEEDED (default: YES for geographic, NO for projected)
81 : TYPE_LONLAT=float/double (default: double for geographic, float for
82 : projected) PIXELTYPE=DEFAULT/SIGNEDBYTE (use SIGNEDBYTE to get a signed Byte
83 : Band)
84 : */
85 :
86 : /* Config Options
87 :
88 : GDAL_NETCDF_BOTTOMUP=YES/NO overrides bottom-up value on import
89 : GDAL_NETCDF_VERIFY_DIMS=[YES/STRICT] : Try to guess which dimensions
90 : represent the latitude and longitude only by their attributes (STRICT) or
91 : also by guessing the name (YES), default is YES.
92 : GDAL_NETCDF_IGNORE_XY_AXIS_NAME_CHECKS=[YES/NO] Whether X/Y dimensions should
93 : be always considered as geospatial axis, even if the lack conventional
94 : attributes confirming it. Default is NO. GDAL_NETCDF_ASSUME_LONGLAT=[YES/NO]
95 : Whether when all else has failed for determining a CRS, a meaningful
96 : geotransform has been found, and is within the bounds -180,360 -90,90, if YES
97 : assume OGC:CRS84. Default is NO.
98 :
99 : // TODO: this unusued and a few others occur in the source that are not
100 : documented, flush out unused opts and document the rest mdsumner@gmail.com
101 : GDAL_NETCDF_CONVERT_LAT_180=YES/NO convert longitude values from ]180,360] to
102 : [-180,180]
103 : */
104 :
105 : /* -------------------------------------------------------------------- */
106 : /* Driver-specific defines */
107 : /* -------------------------------------------------------------------- */
108 :
109 : /* NETCDF driver defs */
110 : static const size_t NCDF_MAX_STR_LEN = 8192;
111 : #define NCDF_CONVENTIONS "Conventions"
112 : #define NCDF_CONVENTIONS_CF_V1_5 "CF-1.5"
113 : #define GDAL_DEFAULT_NCDF_CONVENTIONS NCDF_CONVENTIONS_CF_V1_5
114 : #define NCDF_CONVENTIONS_CF_V1_6 "CF-1.6"
115 : #define NCDF_CONVENTIONS_CF_V1_8 "CF-1.8"
116 : #define NCDF_GEOTRANSFORM "GeoTransform"
117 : #define NCDF_DIMNAME_X "x"
118 : #define NCDF_DIMNAME_Y "y"
119 : #define NCDF_DIMNAME_LON "lon"
120 : #define NCDF_DIMNAME_LAT "lat"
121 : #define NCDF_LONLAT "lon lat"
122 : #define NCDF_DIMNAME_RLON "rlon" // rotated longitude
123 : #define NCDF_DIMNAME_RLAT "rlat" // rotated latitude
124 :
125 : /* compression parameters */
126 : typedef enum
127 : {
128 : NCDF_COMPRESS_NONE = 0,
129 : /* TODO */
130 : /* http://www.unidata.ucar.edu/software/netcdf/docs/BestPractices.html#Packed%20Data%20Values
131 : */
132 : NCDF_COMPRESS_PACKED = 1,
133 : NCDF_COMPRESS_DEFLATE = 2,
134 : NCDF_COMPRESS_SZIP = 3 /* no support for writing */
135 : } NetCDFCompressEnum;
136 :
137 : static const int NCDF_DEFLATE_LEVEL = 1; /* best time/size ratio */
138 :
139 : /* helper for libnetcdf errors */
140 : #define NCDF_ERR(status) \
141 : do \
142 : { \
143 : int NCDF_ERR_status_ = (status); \
144 : if (NCDF_ERR_status_ != NC_NOERR) \
145 : { \
146 : CPLError(CE_Failure, CPLE_AppDefined, \
147 : "netcdf error #%d : %s .\nat (%s,%s,%d)\n", status, \
148 : nc_strerror(NCDF_ERR_status_), __FILE__, __FUNCTION__, \
149 : __LINE__); \
150 : } \
151 : } while (0)
152 :
153 : #define NCDF_ERR_RET(status) \
154 : do \
155 : { \
156 : int NCDF_ERR_RET_status_ = (status); \
157 : if (NCDF_ERR_RET_status_ != NC_NOERR) \
158 : { \
159 : NCDF_ERR(NCDF_ERR_RET_status_); \
160 : return CE_Failure; \
161 : } \
162 : } while (0)
163 :
164 : #define ERR_RET(eErr) \
165 : do \
166 : { \
167 : CPLErr ERR_RET_eErr_ = (eErr); \
168 : if (ERR_RET_eErr_ != CE_None) \
169 : return ERR_RET_eErr_; \
170 : } while (0)
171 :
172 : /* Check for NC2 support in case it was not enabled at compile time. */
173 : /* NC4 has to be detected at compile as it requires a special build of netcdf-4.
174 : */
175 : #ifndef NETCDF_HAS_NC2
176 : #ifdef NC_64BIT_OFFSET
177 : #define NETCDF_HAS_NC2 1
178 : #endif
179 : #endif
180 :
181 : /* Some additional metadata */
182 : #define OGR_SG_ORIGINAL_LAYERNAME "ogr_layer_name"
183 :
184 : /* -------------------------------------------------------------------- */
185 : /* CF-1 Coordinate Type Naming (Chapter 4. Coordinate Types ) */
186 : /* -------------------------------------------------------------------- */
187 : static const char *const papszCFLongitudeVarNames[] = {CF_LONGITUDE_VAR_NAME,
188 : "longitude", nullptr};
189 : static const char *const papszCFLongitudeAttribNames[] = {
190 : CF_UNITS, CF_UNITS, CF_UNITS, CF_STD_NAME, CF_AXIS, CF_LNG_NAME, nullptr};
191 : static const char *const papszCFLongitudeAttribValues[] = {
192 : CF_DEGREES_EAST,
193 : CF_DEGREE_EAST,
194 : CF_DEGREES_E,
195 : CF_LONGITUDE_STD_NAME,
196 : "X",
197 : CF_LONGITUDE_LNG_NAME,
198 : nullptr};
199 : static const char *const papszCFLatitudeVarNames[] = {CF_LATITUDE_VAR_NAME,
200 : "latitude", nullptr};
201 : static const char *const papszCFLatitudeAttribNames[] = {
202 : CF_UNITS, CF_UNITS, CF_UNITS, CF_STD_NAME, CF_AXIS, CF_LNG_NAME, nullptr};
203 : static const char *const papszCFLatitudeAttribValues[] = {CF_DEGREES_NORTH,
204 : CF_DEGREE_NORTH,
205 : CF_DEGREES_N,
206 : CF_LATITUDE_STD_NAME,
207 : "Y",
208 : CF_LATITUDE_LNG_NAME,
209 : nullptr};
210 :
211 : static const char *const papszCFProjectionXVarNames[] = {CF_PROJ_X_VAR_NAME,
212 : "xc", nullptr};
213 : static const char *const papszCFProjectionXAttribNames[] = {CF_STD_NAME,
214 : CF_AXIS, nullptr};
215 : static const char *const papszCFProjectionXAttribValues[] = {CF_PROJ_X_COORD,
216 : "X", nullptr};
217 : static const char *const papszCFProjectionYVarNames[] = {CF_PROJ_Y_VAR_NAME,
218 : "yc", nullptr};
219 : static const char *const papszCFProjectionYAttribNames[] = {CF_STD_NAME,
220 : CF_AXIS, nullptr};
221 : static const char *const papszCFProjectionYAttribValues[] = {CF_PROJ_Y_COORD,
222 : "Y", nullptr};
223 :
224 : static const char *const papszCFVerticalAttribNames[] = {CF_AXIS, "positive",
225 : "positive", nullptr};
226 : static const char *const papszCFVerticalAttribValues[] = {"Z", "up", "down",
227 : nullptr};
228 : static const char *const papszCFVerticalUnitsValues[] = {
229 : /* units of pressure */
230 : "bar", "bars", "millibar", "millibars", "decibar", "decibars", "atmosphere",
231 : "atmospheres", "atm", "pascal", "pascals", "Pa", "hPa",
232 : /* units of length */
233 : "meter", "meters", "m", "kilometer", "kilometers", "km",
234 : /* dimensionless vertical coordinates */
235 : "level", "layer", "sigma_level", nullptr};
236 : /* dimensionless vertical coordinates */
237 : static const char *const papszCFVerticalStandardNameValues[] = {
238 : "atmosphere_ln_pressure_coordinate",
239 : "atmosphere_sigma_coordinate",
240 : "atmosphere_hybrid_sigma_pressure_coordinate",
241 : "atmosphere_hybrid_height_coordinate",
242 : "atmosphere_sleve_coordinate",
243 : "ocean_sigma_coordinate",
244 : "ocean_s_coordinate",
245 : "ocean_sigma_z_coordinate",
246 : "ocean_double_sigma_coordinate",
247 : "atmosphere_ln_pressure_coordinate",
248 : "atmosphere_sigma_coordinate",
249 : "atmosphere_hybrid_sigma_pressure_coordinate",
250 : "atmosphere_hybrid_height_coordinate",
251 : "atmosphere_sleve_coordinate",
252 : "ocean_sigma_coordinate",
253 : "ocean_s_coordinate",
254 : "ocean_sigma_z_coordinate",
255 : "ocean_double_sigma_coordinate",
256 : nullptr};
257 :
258 : static const char *const papszCFTimeAttribNames[] = {CF_AXIS, CF_STD_NAME,
259 : nullptr};
260 : static const char *const papszCFTimeAttribValues[] = {"T", "time", nullptr};
261 : static const char *const papszCFTimeUnitsValues[] = {
262 : "days since", "day since", "d since", "hours since",
263 : "hour since", "h since", "hr since", "minutes since",
264 : "minute since", "min since", "seconds since", "second since",
265 : "sec since", "s since", nullptr};
266 :
267 : /************************************************************************/
268 : /* ==================================================================== */
269 : /* netCDFWriterConfig classes */
270 : /* ==================================================================== */
271 : /************************************************************************/
272 :
273 : class netCDFWriterConfigAttribute
274 : {
275 : public:
276 : CPLString m_osName;
277 : CPLString m_osType;
278 : CPLString m_osValue;
279 :
280 : bool Parse(CPLXMLNode *psNode);
281 : };
282 :
283 : class netCDFWriterConfigField
284 : {
285 : public:
286 : CPLString m_osName;
287 : CPLString m_osNetCDFName;
288 : CPLString m_osMainDim;
289 : std::vector<netCDFWriterConfigAttribute> m_aoAttributes;
290 :
291 : bool Parse(CPLXMLNode *psNode);
292 : };
293 :
294 : class netCDFWriterConfigLayer
295 : {
296 : public:
297 : CPLString m_osName;
298 : CPLString m_osNetCDFName;
299 : std::map<CPLString, CPLString> m_oLayerCreationOptions;
300 : std::vector<netCDFWriterConfigAttribute> m_aoAttributes;
301 : std::map<CPLString, netCDFWriterConfigField> m_oFields;
302 :
303 : bool Parse(CPLXMLNode *psNode);
304 : };
305 :
306 : class netCDFWriterConfiguration
307 : {
308 : public:
309 : bool m_bIsValid;
310 : std::map<CPLString, CPLString> m_oDatasetCreationOptions;
311 : std::map<CPLString, CPLString> m_oLayerCreationOptions;
312 : std::vector<netCDFWriterConfigAttribute> m_aoAttributes;
313 : std::map<CPLString, netCDFWriterConfigField> m_oFields;
314 : std::map<CPLString, netCDFWriterConfigLayer> m_oLayers;
315 :
316 961 : netCDFWriterConfiguration() : m_bIsValid(false)
317 : {
318 961 : }
319 :
320 : bool Parse(const char *pszFilename);
321 : static bool SetNameValue(CPLXMLNode *psNode,
322 : std::map<CPLString, CPLString> &oMap);
323 : };
324 :
325 : /************************************************************************/
326 : /* ==================================================================== */
327 : /* netCDFDataset */
328 : /* ==================================================================== */
329 : /************************************************************************/
330 :
331 : class netCDFRasterBand;
332 : class netCDFLayer;
333 :
334 : class netCDFDataset final : public GDALPamDataset
335 : {
336 : friend class netCDFRasterBand; // TMP
337 : friend class netCDFLayer;
338 : friend class netCDFVariable;
339 :
340 : typedef enum
341 : {
342 : SINGLE_LAYER,
343 : SEPARATE_FILES,
344 : SEPARATE_GROUPS
345 : } MultipleLayerBehavior;
346 :
347 : /* basic dataset vars */
348 : CPLString osFilename;
349 : #ifdef ENABLE_NCDUMP
350 : bool bFileToDestroyAtClosing;
351 : #endif
352 : int cdfid;
353 : #ifdef ENABLE_UFFD
354 : cpl_uffd_context *pCtx = nullptr;
355 : #endif
356 : VSILFILE *fpVSIMEM = nullptr;
357 : int nSubDatasets;
358 : char **papszSubDatasets;
359 : char **papszMetadata;
360 :
361 : // Used to report metadata found in Sentinel 5
362 : std::map<std::string, CPLStringList> m_oMapDomainToJSon{};
363 :
364 : CPLStringList papszDimName;
365 : bool bBottomUp;
366 : NetCDFFormatEnum eFormat;
367 : bool bIsGdalFile; /* was this file created by GDAL? */
368 : bool bIsGdalCfFile; /* was this file created by the (new) CF-compliant
369 : driver? */
370 : char *pszCFProjection;
371 : const char *pszCFCoordinates;
372 : double nCFVersion;
373 : bool bSGSupport;
374 : MultipleLayerBehavior eMultipleLayerBehavior;
375 : std::vector<netCDFDataset *> apoVectorDatasets;
376 : std::string logHeader;
377 : int logCount;
378 : nccfdriver::netCDFVID vcdf;
379 : nccfdriver::OGR_NCScribe GeometryScribe;
380 : nccfdriver::OGR_NCScribe FieldScribe;
381 : nccfdriver::WBufferManager bufManager;
382 :
383 : bool bWriteGDALVersion = true;
384 : bool bWriteGDALHistory = true;
385 :
386 : /* projection/GT */
387 : double m_adfGeoTransform[6];
388 : OGRSpatialReference m_oSRS{};
389 : int nXDimID;
390 : int nYDimID;
391 : bool bIsProjected;
392 : bool bIsGeographic;
393 : bool bSwitchedXY = false;
394 :
395 : /* state vars */
396 : bool bDefineMode;
397 : bool m_bHasProjection = false;
398 : bool m_bHasGeoTransform = false;
399 : bool m_bAddedProjectionVarsDefs = false;
400 : bool m_bAddedProjectionVarsData = false;
401 : bool bAddedGridMappingRef;
402 :
403 : /* create vars */
404 : char **papszCreationOptions;
405 : NetCDFCompressEnum eCompress;
406 : int nZLevel;
407 : bool bChunking;
408 : int nCreateMode;
409 : bool bSignedData;
410 :
411 : // IDs of the dimensions of the variables
412 : std::vector<int> m_anDimIds{};
413 :
414 : // Extra dimension info (size of those arrays is m_anDimIds.size() - 2)
415 : std::vector<int> m_anExtraDimVarIds{};
416 : std::vector<int> m_anExtraDimGroupIds{};
417 :
418 : std::vector<std::shared_ptr<OGRLayer>> papoLayers;
419 :
420 : netCDFWriterConfiguration oWriterConfig;
421 :
422 : struct ChunkKey
423 : {
424 : size_t xChunk; // netCDF chunk number along X axis
425 : size_t yChunk; // netCDF chunk number along Y axis
426 : int nBand;
427 :
428 26 : ChunkKey(size_t xChunkIn, size_t yChunkIn, int nBandIn)
429 26 : : xChunk(xChunkIn), yChunk(yChunkIn), nBand(nBandIn)
430 : {
431 26 : }
432 :
433 28 : bool operator==(const ChunkKey &other) const
434 : {
435 48 : return xChunk == other.xChunk && yChunk == other.yChunk &&
436 48 : nBand == other.nBand;
437 : }
438 :
439 22 : bool operator!=(const ChunkKey &other) const
440 : {
441 22 : return !(operator==(other));
442 : }
443 : };
444 :
445 : struct KeyHasher
446 : {
447 45 : std::size_t operator()(const ChunkKey &k) const
448 : {
449 45 : return std::hash<size_t>{}(k.xChunk) ^
450 45 : (std::hash<size_t>{}(k.yChunk) << 1) ^
451 45 : (std::hash<size_t>{}(k.nBand) << 2);
452 : }
453 : };
454 :
455 : typedef lru11::Cache<
456 : ChunkKey, std::shared_ptr<std::vector<GByte>>, lru11::NullLock,
457 : std::unordered_map<
458 : ChunkKey,
459 : typename std::list<lru11::KeyValuePair<
460 : ChunkKey, std::shared_ptr<std::vector<GByte>>>>::iterator,
461 : KeyHasher>>
462 : ChunkCacheType;
463 :
464 : std::unique_ptr<ChunkCacheType> poChunkCache;
465 :
466 : static double rint(double);
467 :
468 : double FetchCopyParam(const char *pszGridMappingValue, const char *pszParam,
469 : double dfDefault, bool *pbFound = nullptr);
470 :
471 : std::vector<std::string>
472 : FetchStandardParallels(const char *pszGridMappingValue);
473 :
474 : const char *FetchAttr(const char *pszVarFullName, const char *pszAttr);
475 : const char *FetchAttr(int nGroupId, int nVarId, const char *pszAttr);
476 :
477 : void ProcessCreationOptions();
478 : int DefVarDeflate(int nVarId, bool bChunkingArg = true);
479 : CPLErr AddProjectionVars(bool bDefsOnly, GDALProgressFunc pfnProgress,
480 : void *pProgressData);
481 : bool AddGridMappingRef();
482 :
483 10 : bool GetDefineMode() const
484 : {
485 10 : return bDefineMode;
486 : }
487 :
488 : bool SetDefineMode(bool bNewDefineMode);
489 :
490 : CPLErr ReadAttributes(int, int);
491 :
492 : void CreateSubDatasetList(int nGroupId);
493 :
494 : void SetProjectionFromVar(int nGroupId, int nVarId, bool bReadSRSOnly,
495 : const char *pszGivenGM, std::string *,
496 : nccfdriver::SGeometry_Reader *,
497 : std::vector<std::string> *paosRemovedMDItems);
498 : void SetProjectionFromVar(int nGroupId, int nVarId, bool bReadSRSOnly);
499 :
500 : bool ProcessNASAL2OceanGeoLocation(int nGroupId, int nVarId);
501 :
502 : bool ProcessNASAEMITGeoLocation(int nGroupId, int nVarId);
503 :
504 : int ProcessCFGeolocation(int nGroupId, int nVarId,
505 : const std::string &osGeolocWKT,
506 : std::string &osGeolocXNameOut,
507 : std::string &osGeolocYNameOut);
508 : CPLErr Set1DGeolocation(int nGroupId, int nVarId, const char *szDimName);
509 : double *Get1DGeolocation(const char *szDimName, int &nVarLen);
510 :
511 : static bool CloneAttributes(int old_cdfid, int new_cdfid, int nSrcVarId,
512 : int nDstVarId);
513 : static bool CloneVariableContent(int old_cdfid, int new_cdfid,
514 : int nSrcVarId, int nDstVarId);
515 : static bool CloneGrp(int nOldGrpId, int nNewGrpId, bool bIsNC4,
516 : int nLayerId, int nDimIdToGrow, size_t nNewSize);
517 : bool GrowDim(int nLayerId, int nDimIdToGrow, size_t nNewSize);
518 :
519 : void ProcessSentinel3_SRAL_MWR();
520 :
521 : CPLErr
522 : FilterVars(int nCdfId, bool bKeepRasters, bool bKeepVectors,
523 : char **papszIgnoreVars, int *pnRasterVars, int *pnGroupId,
524 : int *pnVarId, int *pnIgnoredVars,
525 : // key is (dim1Id, dim2Id, nc_type varType)
526 : // value is (groupId, varId)
527 : std::map<std::array<int, 3>, std::vector<std::pair<int, int>>>
528 : &oMap2DDimsToGroupAndVar);
529 : CPLErr CreateGrpVectorLayers(int nCdfId, const CPLString &osFeatureType,
530 : const std::vector<int> &anPotentialVectorVarID,
531 : const std::map<int, int> &oMapDimIdToCount,
532 : int nVarXId, int nVarYId, int nVarZId,
533 : int nProfileDimId, int nParentIndexVarID,
534 : bool bKeepRasters);
535 :
536 : bool DetectAndFillSGLayers(int ncid);
537 : CPLErr LoadSGVarIntoLayer(int ncid, int nc_basevarId);
538 :
539 : static GDALDataset *OpenMultiDim(GDALOpenInfo *);
540 : std::shared_ptr<GDALGroup> m_poRootGroup{};
541 :
542 : void SetGeoTransformNoUpdate(double *);
543 : void SetSpatialRefNoUpdate(const OGRSpatialReference *);
544 :
545 : protected:
546 : CPLXMLNode *SerializeToXML(const char *pszVRTPath) override;
547 :
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 : virtual ~netCDFDataset();
557 : bool SGCommitPendingTransaction();
558 : void SGLogPendingTransaction();
559 : static std::string generateLogName();
560 :
561 : /* Projection/GT */
562 : CPLErr GetGeoTransform(double *) override;
563 : CPLErr SetGeoTransform(double *) override;
564 : const OGRSpatialReference *GetSpatialRef() const override;
565 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
566 :
567 : virtual char **GetMetadataDomainList() override;
568 : char **GetMetadata(const char *) override;
569 :
570 : virtual CPLErr SetMetadataItem(const char *pszName, const char *pszValue,
571 : const char *pszDomain = "") override;
572 : virtual CPLErr SetMetadata(char **papszMD,
573 : const char *pszDomain = "") override;
574 :
575 : virtual int TestCapability(const char *pszCap) override;
576 :
577 1922 : virtual int GetLayerCount() override
578 : {
579 1922 : return static_cast<int>(this->papoLayers.size());
580 : }
581 :
582 : virtual OGRLayer *GetLayer(int nIdx) override;
583 :
584 : std::shared_ptr<GDALGroup> GetRootGroup() const override;
585 :
586 171 : int GetCDFID() const
587 : {
588 171 : 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 : 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 : virtual ~netCDFLayer();
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 71 : void EnableSGBypass()
726 : {
727 71 : this->m_bLegacyCreateMode = false;
728 71 : }
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 71 : void SetSGeometryRepresentation(
743 : const std::shared_ptr<nccfdriver::SGeometry_Reader> &sg)
744 : {
745 71 : m_simpleGeometryReader = sg;
746 71 : }
747 :
748 114 : nccfdriver::ncLayer_SG_Metadata &getLayerSGMetadata()
749 : {
750 114 : return m_layerSGDefn;
751 : }
752 :
753 : virtual void ResetReading() override;
754 : virtual OGRFeature *GetNextFeature() override;
755 :
756 : virtual GIntBig GetFeatureCount(int bForce) override;
757 :
758 : virtual int TestCapability(const char *pszCap) override;
759 :
760 : virtual OGRFeatureDefn *GetLayerDefn() override;
761 :
762 : virtual 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
|