/src/gdal/frmts/netcdf/netcdfdataset.h
Line | Count | Source (jump to first uncovered line) |
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 | 0 | #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 | 399 | #define NCDF_CONVENTIONS "Conventions" |
95 | 2 | #define NCDF_CONVENTIONS_CF_V1_5 "CF-1.5" |
96 | 2 | #define GDAL_DEFAULT_NCDF_CONVENTIONS NCDF_CONVENTIONS_CF_V1_5 |
97 | 0 | #define NCDF_CONVENTIONS_CF_V1_6 "CF-1.6" |
98 | 0 | #define NCDF_CONVENTIONS_CF_V1_8 "CF-1.8" |
99 | 0 | #define NCDF_GEOTRANSFORM "GeoTransform" |
100 | 0 | #define NCDF_DIMNAME_X "x" |
101 | 0 | #define NCDF_DIMNAME_Y "y" |
102 | 0 | #define NCDF_DIMNAME_LON "lon" |
103 | 0 | #define NCDF_DIMNAME_LAT "lat" |
104 | 0 | #define NCDF_LONLAT "lon lat" |
105 | 0 | #define NCDF_DIMNAME_RLON "rlon" // rotated longitude |
106 | 0 | #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 | 18.8k | do \ |
125 | 18.8k | { \ |
126 | 18.8k | int NCDF_ERR_status_ = (status); \ |
127 | 18.8k | if (NCDF_ERR_status_ != NC_NOERR) \ |
128 | 18.8k | { \ |
129 | 14.9k | CPLError(CE_Failure, CPLE_AppDefined, \ |
130 | 14.9k | "netcdf error #%d : %s .\nat (%s,%s,%d)\n", \ |
131 | 14.9k | NCDF_ERR_status_, nc_strerror(NCDF_ERR_status_), \ |
132 | 14.9k | __FILE__, __FUNCTION__, __LINE__); \ |
133 | 14.9k | } \ |
134 | 18.8k | } while (0) |
135 | | |
136 | | #define NCDF_ERR_RET(status) \ |
137 | 227k | do \ |
138 | 227k | { \ |
139 | 227k | int NCDF_ERR_RET_status_ = (status); \ |
140 | 227k | if (NCDF_ERR_RET_status_ != NC_NOERR) \ |
141 | 227k | { \ |
142 | 11.1k | NCDF_ERR(NCDF_ERR_RET_status_); \ |
143 | 11.1k | return CE_Failure; \ |
144 | 11.1k | } \ |
145 | 227k | } while (0) |
146 | | |
147 | | #define ERR_RET(eErr) \ |
148 | 239k | do \ |
149 | 239k | { \ |
150 | 239k | CPLErr ERR_RET_eErr_ = (eErr); \ |
151 | 239k | if (ERR_RET_eErr_ != CE_None) \ |
152 | 239k | return ERR_RET_eErr_; \ |
153 | 239k | } 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 | 0 | #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 | 30 | #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 | 399 | netCDFWriterConfiguration() : m_bIsValid(false) |
322 | 399 | { |
323 | 399 | } |
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 | | ChunkKey(size_t xChunkIn, size_t yChunkIn, int nBandIn) |
435 | 0 | : xChunk(xChunkIn), yChunk(yChunkIn), nBand(nBandIn) |
436 | 0 | { |
437 | 0 | } |
438 | | |
439 | | bool operator==(const ChunkKey &other) const |
440 | 0 | { |
441 | 0 | return xChunk == other.xChunk && yChunk == other.yChunk && |
442 | 0 | nBand == other.nBand; |
443 | 0 | } |
444 | | |
445 | | bool operator!=(const ChunkKey &other) const |
446 | 0 | { |
447 | 0 | return !(operator==(other)); |
448 | 0 | } |
449 | | }; |
450 | | |
451 | | struct KeyHasher |
452 | | { |
453 | | std::size_t operator()(const ChunkKey &k) const |
454 | 0 | { |
455 | 0 | return std::hash<size_t>{}(k.xChunk) ^ |
456 | 0 | (std::hash<size_t>{}(k.yChunk) << 1) ^ |
457 | 0 | (std::hash<size_t>{}(k.nBand) << 2); |
458 | 0 | } |
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 | | bool GetDefineMode() const |
490 | 0 | { |
491 | 0 | return bDefineMode; |
492 | 0 | } |
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 | | virtual int GetLayerCount() override |
582 | 867 | { |
583 | 867 | return static_cast<int>(this->papoLayers.size()); |
584 | 867 | } |
585 | | |
586 | | virtual OGRLayer *GetLayer(int nIdx) override; |
587 | | |
588 | | std::shared_ptr<GDALGroup> GetRootGroup() const override; |
589 | | |
590 | | int GetCDFID() const |
591 | 0 | { |
592 | 0 | return cdfid; |
593 | 0 | } |
594 | | |
595 | | inline bool HasInfiniteRecordDim() |
596 | 0 | { |
597 | 0 | return !bSGSupport; |
598 | 0 | } |
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 | | void EnableSGBypass() |
730 | 0 | { |
731 | 0 | this->m_bLegacyCreateMode = false; |
732 | 0 | } |
733 | | |
734 | | bool AddField(int nVarId); |
735 | | |
736 | | int GetCDFID() const |
737 | 0 | { |
738 | 0 | return m_nLayerCDFId; |
739 | 0 | } |
740 | | |
741 | | void SetCDFID(int nId) |
742 | 0 | { |
743 | 0 | m_nLayerCDFId = nId; |
744 | 0 | } |
745 | | |
746 | | void SetSGeometryRepresentation( |
747 | | const std::shared_ptr<nccfdriver::SGeometry_Reader> &sg) |
748 | 0 | { |
749 | 0 | m_simpleGeometryReader = sg; |
750 | 0 | } |
751 | | |
752 | | nccfdriver::ncLayer_SG_Metadata &getLayerSGMetadata() |
753 | 0 | { |
754 | 0 | return m_layerSGDefn; |
755 | 0 | } |
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 |