Commit 5ddc9ffe0f40411a34772747f9e216a31cbe4696

Authored by Benjamin Renard
1 parent 03e8f845

NetCDF file reader for LocalFileInterface

config/xsd/localbase/base.xsd
... ... @@ -21,6 +21,7 @@
21 21 <xs:enumeration value="ASCII" />
22 22 <xs:enumeration value="CDF" />
23 23 <xs:enumeration value="VOT" />
  24 + <xs:enumeration value="NC" />
24 25 </xs:restriction>
25 26 </xs:simpleType>
26 27 </xs:attribute>
... ... @@ -33,4 +34,4 @@
33 34 <xs:attribute name="start" type="xs:string" use="required" />
34 35 <xs:attribute name="stop" type="xs:string" use="required" />
35 36 </xs:complexType>
36   -</xs:schema>
37 37 \ No newline at end of file
  38 +</xs:schema>
... ...
src/ParamGetImpl/LocalFileInterface/FileReaderNetCDF.cc
... ... @@ -18,6 +18,7 @@ namespace LocalFileInterface {
18 18  
19 19 FileReaderNetCDF::FileReaderNetCDF()
20 20 {
  21 + resetFile();
21 22 }
22 23  
23 24 FileReaderNetCDF::~FileReaderNetCDF()
... ... @@ -26,38 +27,170 @@ FileReaderNetCDF::~FileReaderNetCDF()
26 27  
27 28 bool FileReaderNetCDF::open(std::string filePath)
28 29 {
29   - return false;
  30 + boost::mutex::scoped_lock scoped_lock(AMDA::Parameters::ParameterManager::mutexNetCDFLib);
  31 + if (isOpened()) {
  32 + return true;
  33 + }
  34 +
  35 + int status = nc_open(filePath.c_str(), 0, &_file.id);
  36 + if (status != NC_NOERR) {
  37 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::open - Cannot open netCDF file : " << getErrorMessage(status))
  38 + resetFile();
  39 + return false;
  40 + }
  41 + return loadNetCDFFileInfo();
30 42 }
31 43  
32 44 bool FileReaderNetCDF::close(void)
33 45 {
34   - return false;
  46 + boost::mutex::scoped_lock scoped_lock(AMDA::Parameters::ParameterManager::mutexNetCDFLib);
  47 + if (!isOpened()) {
  48 + return true;
  49 + }
  50 + int status = nc_close(_file.id);
  51 + if (status != NC_NOERR) {
  52 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::close - Cannot close netCDF file : " << getErrorMessage(status))
  53 + return false;
  54 + }
  55 + resetFile();
  56 + return true;
35 57 }
36 58  
37 59 bool FileReaderNetCDF::isOpened(void)
38 60 {
39   - return false;
  61 + return (_file.id != 0);
40 62 }
41 63  
42 64 std::string FileReaderNetCDF::getTimeParamId(void)
43 65 {
  66 + if (!isOpened()) {
  67 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::getTimeParamId - File not opened")
  68 + return "";
  69 + }
  70 +
  71 + for (std::vector<NetCDFVar>::iterator it = _file.vars.begin(); it != _file.vars.end(); ++it) {
  72 + std::string name = it->name;
  73 + std::transform(name.begin(), name.end(), name.begin(), ::tolower);
  74 + if ((std::strcmp(name.c_str(),"time") == 0) && (it->type == NC_DOUBLE)) {
  75 + return it->name;
  76 + }
  77 + }
  78 +
  79 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::getTimeParamId - Cannot find the time variable")
44 80 return "";
45 81 }
46 82  
47 83 bool FileReaderNetCDF::getParamInfo(std::string& paramId, LocalParamType& paramType, int& dim1Size, int& dim2Size)
48 84 {
49   - return false;
  85 + for (std::vector<NetCDFVar>::iterator it = _file.vars.begin(); it != _file.vars.end(); ++it) {
  86 + if (std::strcmp(it->name, paramId.c_str()) == 0) {
  87 + if (it->dimids.size() == 1) {
  88 + //scalar
  89 + dim1Size = 1;
  90 + dim2Size = 1;
  91 + }
  92 + else if (it->dimids.size() == 2) {
  93 + //vector
  94 + dim1Size = _file.dims[it->dimids[1]].length;
  95 + dim2Size = 1;
  96 + }
  97 + else if (it->dimids.size() == 3) {
  98 + //Tab2D
  99 + dim1Size = _file.dims[it->dimids[1]].length;
  100 + dim2Size = _file.dims[it->dimids[2]].length;
  101 + }
  102 + else {
  103 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::getParamInfo - Variable dimensions not supported")
  104 + return false;
  105 + }
  106 + switch (it->type) {
  107 + case NC_FLOAT :
  108 + paramType = LocalParamType::TYPE_FLOAT;
  109 + break;
  110 + case NC_DOUBLE :
  111 + paramType = LocalParamType::TYPE_DOUBLE;
  112 + break;
  113 + case NC_SHORT :
  114 + paramType = LocalParamType::TYPE_SHORT;
  115 + break;
  116 + case NC_INT :
  117 + paramType = LocalParamType::TYPE_INT;
  118 + break;
  119 + default:
  120 + paramType = LocalParamType::TYPE_UNKNOWN;
  121 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::getParamInfo - Unknown variable type")
  122 + return false;
  123 + }
  124 + }
  125 + }
  126 + return true;
50 127 }
51 128  
52 129 int FileReaderNetCDF::getRecordIndex(std::string& timeId, double time)
53 130 {
  131 + boost::mutex::scoped_lock scoped_lock(AMDA::Parameters::ParameterManager::mutexNetCDFLib);
  132 + for (std::vector<NetCDFVar>::iterator it = _file.vars.begin(); it != _file.vars.end(); ++it) {
  133 + if (std::strcmp(it->name, timeId.c_str()) == 0) {
  134 + if (!loadData(*it)) {
  135 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::getRecordIndex - Cannot load time data")
  136 + return -1;
  137 + }
  138 + double* buffer = (double*)it->buffer;
  139 + for (int i = 0; i < getNbVarRecords(*it); ++i) {
  140 + if (time <= buffer[i]) {
  141 + return i;
  142 + }
  143 + }
  144 + }
  145 + }
54 146 return -1;
55 147 }
56 148  
57 149 FileReaderStatus FileReaderNetCDF::getParamPacketData(std::string& timeId, std::string& paramId,
58 150 int recordIndex, double stopTime, LocalParamDataPacket *packet)
59 151 {
60   - return FRS_ERROR;
  152 + boost::mutex::scoped_lock scoped_lock(AMDA::Parameters::ParameterManager::mutexNetCDFLib);
  153 +
  154 + NetCDFVar* timeVar = NULL;
  155 + NetCDFVar* paramVar = NULL;
  156 + for (std::vector<NetCDFVar>::iterator it = _file.vars.begin(); it != _file.vars.end(); ++it) {
  157 + if (std::strcmp(it->name, timeId.c_str()) == 0) {
  158 + timeVar = &(*it);
  159 + }
  160 + if (std::strcmp(it->name, paramId.c_str()) == 0) {
  161 + paramVar = &(*it);
  162 + }
  163 + }
  164 +
  165 + if ((timeVar == NULL) || (paramVar == NULL)) {
  166 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::getParamPacketData - Cannot retrieve time or param variable")
  167 + return FRS_ERROR;
  168 + }
  169 +
  170 + if (!loadData(*timeVar) || !loadData(*paramVar)) {
  171 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::getParamPacketData - Cannot load time or param data")
  172 + return FRS_ERROR;
  173 + }
  174 +
  175 + double* time_buffer = (double*)timeVar->buffer;
  176 + bool packetFull = false;
  177 + int nbValues = getNbVarValuesByRecord(*paramVar);
  178 + for (int i = recordIndex; i < getNbVarRecords(*paramVar); ++i) {
  179 + double crtTime = time_buffer[i];
  180 + void* pos = (void*)((char*)paramVar->buffer + paramVar->valuesize * nbValues * i);
  181 + if (crtTime > stopTime) {
  182 + return FRS_FINISH;
  183 + }
  184 + if (!packet->addData(crtTime, pos, packetFull))
  185 + {
  186 + if (packetFull)
  187 + return FRS_MORE;
  188 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::getParamPacketData - Error to add data in packet");
  189 + return FRS_ERROR;
  190 + }
  191 + }
  192 +
  193 + return FRS_EOF;
61 194 }
62 195  
63 196 bool FileReaderNetCDF::getInfo(const char* /*pInfoName*/, std::vector<double>& /*res*/)
... ... @@ -65,5 +198,167 @@ bool FileReaderNetCDF::getInfo(const char* /*pInfoName*/, std::vector&lt;double&gt;&amp; /
65 198 return false;
66 199 }
67 200  
  201 +void FileReaderNetCDF::resetFile() {
  202 + _file.id = 0;
  203 + _file.dims.clear();
  204 + for (std::vector<NetCDFVar>::iterator it = _file.vars.begin(); it != _file.vars.end(); ++it) {
  205 + if (it->buffer != NULL) {
  206 + std::free(it->buffer);
  207 + it->buffer = NULL;
  208 + }
  209 + }
  210 + _file.vars.clear();
  211 + _file.atts.clear();
  212 +}
  213 +
  214 +bool FileReaderNetCDF::loadNetCDFFileInfo() {
  215 + if (!isOpened()) {
  216 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::loadNetCDFFileInfo - File not opened")
  217 + return false;
  218 + }
  219 +
  220 + int status, ndims, nvars, ngatts, unlimdimid;
  221 + status = nc_inq(_file.id, &ndims, &nvars, &ngatts, &unlimdimid);
  222 +
  223 + if (status != NC_NOERR) {
  224 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::loadNetCDFFileInfo - Cannot load info in netCDF file : " << getErrorMessage(status))
  225 + return false;
  226 + }
  227 +
  228 + //Load dims
  229 + for (int i = 0; i < ndims; ++i) {
  230 + NetCDFDim dim;
  231 + status = nc_inq_dim(_file.id, i, dim.name, &dim.length);
  232 + if (status != NC_NOERR) {
  233 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::loadNetCDFFileInfo - Cannot load dimension info : " << getErrorMessage(status))
  234 + return false;
  235 + }
  236 + dim.isUnlimited = (i == unlimdimid);
  237 + _file.dims.push_back(dim);
  238 + }
  239 +
  240 + //Load global attributes
  241 + for (int i = 0; i < ngatts; ++i) {
  242 + NetCDFAtt att;
  243 + status = nc_inq_attname(_file.id, NC_GLOBAL, i, att.name);
  244 + if (status != NC_NOERR) {
  245 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::loadNetCDFFileInfo - Cannot load global attribute name : " << getErrorMessage(status))
  246 + return false;
  247 + }
  248 + status = nc_inq_att(_file.id, NC_GLOBAL, att.name, &att.type, &att.length);
  249 + if (status != NC_NOERR) {
  250 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::loadNetCDFFileInfo - Cannot load global attribute info : " << getErrorMessage(status))
  251 + return false;
  252 + }
  253 + _file.atts.push_back(att);
  254 + }
  255 +
  256 + //Load variables
  257 + for (int i = 0; i < nvars; ++i) {
  258 + int natts;
  259 + int ndims;
  260 + int dimids[NC_MAX_VAR_DIMS];
  261 + NetCDFVar var;
  262 + var.buffer = NULL;
  263 + status = nc_inq_var(_file.id, i, var.name, &var.type, &ndims, dimids, &natts);
  264 + if (status != NC_NOERR) {
  265 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::loadNetCDFFileInfo - Cannot load variable info : " << getErrorMessage(status))
  266 + return false;
  267 + }
  268 + if (ndims > 3) {
  269 + //Not supported by the kernel
  270 + continue;
  271 + }
  272 + for (int j = 0; j < ndims; ++j) {
  273 + var.dimids.push_back(dimids[j]);
  274 + }
  275 + //Load variable attributes
  276 + for (int j = 0; j < natts; ++j) {
  277 + NetCDFAtt att;
  278 + status = nc_inq_attname(_file.id, i, j, att.name);
  279 + if (status != NC_NOERR) {
  280 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::loadNetCDFFileInfo - Cannot load variable attribute : " << getErrorMessage(status))
  281 + return false;
  282 + }
  283 + status = nc_inq_att(_file.id, i, att.name, &att.type, &att.length);
  284 + if (status != NC_NOERR) {
  285 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::loadNetCDFFileInfo - Cannot load variable attribute : " << getErrorMessage(status))
  286 + return false;
  287 + }
  288 + var.atts.push_back(att);
  289 + }
  290 + _file.vars.push_back(var);
  291 + }
  292 + return true;
  293 +}
  294 +
  295 +int FileReaderNetCDF::getNbVarValuesByRecord(const NetCDFVar& var) {
  296 + if (var.dimids.size() == 1) {
  297 + //scalar
  298 + return 1;
  299 + }
  300 + else if (var.dimids.size() == 2) {
  301 + //vector
  302 + return _file.dims[var.dimids[1]].length;
  303 + }
  304 + else if (var.dimids.size() == 3) {
  305 + //tab2d
  306 + return _file.dims[var.dimids[1]].length * _file.dims[var.dimids[2]].length;
  307 + }
  308 + return 1;
  309 +}
  310 +
  311 +int FileReaderNetCDF::getNbVarRecords(const NetCDFVar& var) {
  312 + if (var.dimids.size() < 1)
  313 + return 0;
  314 + return _file.dims[var.dimids[0]].length;
  315 +}
  316 +
  317 +bool FileReaderNetCDF::loadData(NetCDFVar& var) {
  318 + if (var.buffer != NULL) {
  319 + return true;
  320 + }
  321 + int nbRecords = getNbVarRecords(var);
  322 + int nbValues = getNbVarValuesByRecord(var);
  323 + int varid;
  324 + int status = nc_inq_varid (_file.id, var.name, &varid);
  325 + if (status != NC_NOERR) {
  326 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::loadData - Cannot load variable data : " << getErrorMessage(status))
  327 + return false;
  328 + }
  329 + switch (var.type) {
  330 + case NC_FLOAT :
  331 + var.valuesize = sizeof(float);
  332 + break;
  333 + case NC_DOUBLE :
  334 + var.valuesize = sizeof(double);
  335 + break;
  336 + case NC_SHORT :
  337 + var.valuesize = sizeof(short);
  338 + break;
  339 + case NC_INT :
  340 + var.valuesize = sizeof(int);
  341 + break;
  342 + default:
  343 + return false;
  344 + }
  345 + var.buffer = std::malloc(nbRecords*nbValues*var.valuesize);
  346 + status = nc_get_var(_file.id, varid, var.buffer);
  347 + if (status != NC_NOERR) {
  348 + LOG4CXX_ERROR(gLogger, "FileReaderNetCDF::loadData - Cannot load variable data : " << getErrorMessage(status))
  349 + std::free(var.buffer);
  350 + var.buffer = NULL;
  351 + return false;
  352 + }
  353 + return true;
  354 +}
  355 +
  356 +std::string FileReaderNetCDF::getErrorMessage(int status) {
  357 + if (status == NC_NOERR) {
  358 + return "NO ERROR";
  359 + }
  360 + return nc_strerror(status);
  361 +}
  362 +
68 363 } /* LocalFileInterface */
69 364 } /* AMDA */
... ...
src/ParamGetImpl/LocalFileInterface/FileReaderNetCDF.hh
... ... @@ -12,6 +12,8 @@
12 12  
13 13 #include "netcdf.h"
14 14  
  15 +#include <vector>
  16 +
15 17 namespace AMDA {
16 18 namespace LocalFileInterface {
17 19  
... ... @@ -72,6 +74,51 @@ public:
72 74 */
73 75 virtual bool getInfo(const char* pInfoName, std::vector<double>& res);
74 76  
  77 +private:
  78 + struct NetCDFDim {
  79 + int id;
  80 + char name[NC_MAX_NAME+1];
  81 + size_t length;
  82 + bool isUnlimited;
  83 + };
  84 +
  85 + struct NetCDFAtt {
  86 + int id;
  87 + char name[NC_MAX_NAME+1];
  88 + size_t length;
  89 + nc_type type;
  90 + };
  91 +
  92 + struct NetCDFVar {
  93 + int id;
  94 + char name[NC_MAX_NAME+1];
  95 + std::vector<int> dimids;
  96 + std::vector<NetCDFAtt> atts;
  97 + nc_type type;
  98 + void* buffer;
  99 + int valuesize;
  100 + };
  101 +
  102 + struct NetCDFFile {
  103 + int id;
  104 + std::vector<NetCDFDim> dims;
  105 + std::vector<NetCDFVar> vars;
  106 + std::vector<NetCDFAtt> atts;
  107 + };
  108 +
  109 + NetCDFFile _file;
  110 +
  111 + void resetFile();
  112 +
  113 + bool loadNetCDFFileInfo();
  114 +
  115 + int getNbVarRecords(const NetCDFVar& var);
  116 +
  117 + int getNbVarValuesByRecord(const NetCDFVar& var);
  118 +
  119 + bool loadData(NetCDFVar& var);
  120 +
  121 + std::string getErrorMessage(int status);
75 122 };
76 123  
77 124 } /* LocalFileInterface */
... ...
src/ParamGetImpl/LocalFileInterface/VirtualInstrumentBaseParser.cc
... ... @@ -115,7 +115,7 @@ public:
115 115 lVI->setFilesFormat(VIFileFormat::FORMAT_CDF);
116 116 else if (loadedVIFormat == "VOT")
117 117 lVI->setFilesFormat(VIFileFormat::FORMAT_VOT);
118   - else if (loadedVIFormat == "NETCDF")
  118 + else if (loadedVIFormat == "NC")
119 119 lVI->setFilesFormat(VIFileFormat::FORMAT_NETCDF);
120 120 else
121 121 {
... ...
src/Parameters/ParameterManager.cc
... ... @@ -41,6 +41,13 @@ log4cxx::LoggerPtr ParameterManager::_logger(
41 41 */
42 42 boost::mutex ParameterManager::mutexCDFLib;
43 43  
  44 +/*
  45 + * @brief Mutex used to protect multi-thread access to NetCDF lib (NetCDF lib is not thread-safe!)
  46 + * This mutex is a part of the ParameterManager to be shared between by FileWriterNetCDF (DownloadOutput plugin)
  47 + * and class and FileReaderNetCDF (ParamGetLocalFile)
  48 + */
  49 +boost::mutex ParameterManager::mutexNetCDFLib;
  50 +
44 51 #define DEFAULT_GAP_THRESHOLD_VALUE 5
45 52  
46 53 ParameterManager::ParameterManager() :
... ...
src/Parameters/ParameterManager.hh
... ... @@ -55,6 +55,13 @@ namespace AMDA
55 55 */
56 56 static boost::mutex mutexCDFLib;
57 57  
  58 + /*
  59 + * @brief Mutex used to protect multi-thread access to netCDF lib (netCDF lib is not thread-safe!)
  60 + * This mutex is a part of the ParameterManager to be shared between by FileWriterNetCDF (DownloadOutput plugin)
  61 + * and class and FileReaderNetCDF (ParamGetLocalFile)
  62 + */
  63 + static boost::mutex mutexNetCDFLib;
  64 +
58 65 /**
59 66 * @return no return, do a getParameter
60 67 */
... ...
test/data/DataBaseParameters/local_netcdf_b.xml
1 1 <?xml version="1.0" encoding="UTF-8"?>
2 2 <param xml:id="local_netcdf_b">
3 3 <info>
4   - <name>Mag Field vector</name>
5   - <short_name>Mag Field</short_name>
6   - <components>Bx,By,Bz</components>
  4 + <name>B Mag</name>
  5 + <short_name>|B|</short_name>
  6 + <components></components>
7 7 <units>nT</units>
8 8 <coordinates_system></coordinates_system>
9 9 <tensor_order>1</tensor_order>
... ...
test/data/DataBaseParameters/local_netcdf_v.xml 0 → 100644
... ... @@ -0,0 +1,22 @@
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<param xml:id="local_netcdf_v">
  3 + <info>
  4 + <name>Velocity</name>
  5 + <short_name>V</short_name>
  6 + <components></components>
  7 + <units>km/s</units>
  8 + <coordinates_system></coordinates_system>
  9 + <tensor_order>1</tensor_order>
  10 + <si_conversion></si_conversion>
  11 + <fill_value></fill_value>
  12 + <ucd></ucd>
  13 + <dataset_id></dataset_id>
  14 + </info>
  15 + <get>
  16 + <localvi id="15">
  17 + <param id="V" minSampling="3600" maxSampling="3600"/>
  18 + </localvi>
  19 + </get>
  20 + <process/>
  21 + <output/>
  22 +</param>
... ...
test/data/LocalBase/base.xml
... ... @@ -87,7 +87,7 @@
87 87 <file name="mms1_scm_brst_l2_scb_20150815130334_v1.1.0.cdf" start="1439643815.000000"
88 88 stop="1439643925.000000" />
89 89 </vi>
90   - <vi id="15" format="NETCDF" start="662691600.000000" stop="694223999.000000">
  90 + <vi id="15" format="NC" start="662691600.000000" stop="694223999.000000">
91 91 <file name="venus_1991.nc" start="662691600.000000"
92 92 stop="694223999.000000" />
93 93 </vi>
... ...