/** * FileWriterCDF.cc * * Created on: 08 oct. 2014 * Author: AKKA */ #include "FileWriterCDF.hh" #include "TimeUtil.hh" #include "FileWriter.hh" #include "ParamMgr.hh" #include "DataSetMgr.hh" #include "InstrumentMgr.hh" #include "MissionMgr.hh" #include #include #include #include namespace AMDA { namespace ParamOutputImpl { namespace Download { namespace FileWriter { #define CDF_TIME_VAR "AMDA_TIME" using namespace AMDA::Info; FileWriterCDF::FileWriterCDF(AMDA::Parameters::ParameterManager &pParameterManager) : FileWriter(pParameterManager), _cdfid(NULL) { } FileWriterCDF::~FileWriterCDF(void) { closeFile(); } std::string FileWriterCDF::getExtension(void) { return "cdf"; } void FileWriterCDF::closeFile(void) { boost::mutex::scoped_lock scoped_lock(ParameterManager::mutexCDFLib); if (_cdfid != NULL) CDFcloseCDF(_cdfid); _cdfid = NULL; for (auto cdfVar : _cdfVarMap) { if (cdfVar.second.buffer != NULL) { free(cdfVar.second.buffer); cdfVar.second.buffer = NULL; } } _cdfVarMap.clear(); } bool FileWriterCDF::createNewFile(std::string filePath) { if (_cdfid != NULL) { closeFile(); } boost::mutex::scoped_lock scoped_lock(ParameterManager::mutexCDFLib); CDFstatus status; // remove old file if exist remove(filePath.c_str()); // CDFcreateCDF add automatically ".cdf" extension status = CDFcreateCDF((char *)filePath.c_str(), &_cdfid); return (status == CDF_OK); } bool FileWriterCDF::addParameter(ParamProperties *paramProp, AMDA::Common::ParameterIndexComponentList &indexList, FileDataType type, bool isFirstParam, int dim1Size, int dim2Size) { if (isFirstParam) { if (!createCDFVar(CDF_TIME_VAR, DT_TIME, 1, 1, _cdfVarMap[CDF_TIME_VAR])) return false; } return addCDFParameter(paramProp->getOutputId(), indexList, type, dim1Size, dim2Size); } bool FileWriterCDF::addCDFParameter(std::string outputId, AMDA::Common::ParameterIndexComponentList &indexList, FileDataType type, int dim1Size, int dim2Size) { std::stringstream paramIdStream; paramIdStream << outputId; int varDim1Size = dim1Size; int varDim2Size = dim2Size; if ((type != DT_TIME) && !indexList.empty() && (dim1Size * dim2Size != (int)indexList.size())) { paramIdStream << "_" << indexList.size(); varDim1Size = indexList.size(); varDim2Size = 1; } std::map::iterator it = _cdfVarMap.find(outputId); if (it != _cdfVarMap.end()) return true; // already exist return createCDFVar(paramIdStream.str().c_str(), type, varDim1Size, varDim2Size, _cdfVarMap[outputId]); } bool FileWriterCDF::createCDFVar(const char *name, FileDataType type, long varDim1Size, long varDim2Size, ParamCDFVar &cdfVar) { boost::mutex::scoped_lock scoped_lock(ParameterManager::mutexCDFLib); if (_cdfid == NULL) return false; cdfVar.dim1Size = varDim1Size; cdfVar.dim2Size = varDim2Size; switch (type) { case DT_FLOAT: cdfVar.type = CDF_FLOAT; break; case DT_SHORT: cdfVar.type = CDF_INT2; break; case DT_INT: cdfVar.type = CDF_INT4; break; case DT_DOUBLE: case DT_LONGDOUBLE: cdfVar.type = CDF_DOUBLE; break; case DT_LOGICAL: cdfVar.type = CDF_UINT2; break; case DT_TIME: cdfVar.type = CDF_EPOCH; break; case DT_TIME2000: cdfVar.type = CDF_TIME_TT2000; break; case DT_NONE: cdfVar.type = CDF_CHAR; break; default: return false; } cdfVar.recNum = 0; long numDims; long *dimSizes = NULL; long *dimVarys = NULL; if (varDim2Size > 1) { numDims = 2L; dimSizes = new long[2]; dimSizes[0] = varDim1Size; dimSizes[1] = varDim2Size; dimVarys = new long[2]; dimVarys[0] = VARY; dimVarys[1] = VARY; } else { numDims = (varDim1Size > 1) ? 1L : 0L; dimSizes = new long[1]; dimSizes[0] = varDim1Size; dimVarys = new long[1]; dimVarys[0] = VARY; } long recVary = {VARY}; long numElts = 1; CDFstatus status = CDFgetDataTypeSize(cdfVar.type, &cdfVar.numBytes); if (status != CDF_OK) { return false; } cdfVar.buffer = malloc(varDim1Size * varDim2Size * cdfVar.numBytes * NB_RECORDS_BUFFER); status = CDFcreatezVar(_cdfid, name, cdfVar.type, numElts, numDims, dimSizes, recVary, dimVarys, &cdfVar.varNum); delete[] dimSizes; delete[] dimVarys; return (status == CDF_OK); } bool FileWriterCDF::isInfoInSeparateFile(bool /* separateInfoFile */, bool /* onlyOneInterval */, OutputStructure /* outputStructure */) { return false; } bool FileWriterCDF::writeError(std::string msg) { addAttribute("AMDA_ERROR", msg, GLOBAL_SCOPE); return true; } bool FileWriterCDF::writeAMDAInfo(std::string version, std::string createdby, std::string acknowledgement) { addAttribute(AMDA_ABOUT, createdby, GLOBAL_SCOPE); addAttribute(AMDA_VERSION, version, GLOBAL_SCOPE); addAttribute(AMDA_ACKNOWLEDGEMENT, acknowledgement, GLOBAL_SCOPE); return true; } bool FileWriterCDF::writeRequestInfo(std::string structure, std::string /* timeFormat */, int timeResolution, std::string outputParams, std::string ttName) { addAttribute(REQUEST_STRUCTURE, structure, GLOBAL_SCOPE); addAttribute(REQUEST_TIMEFORMAT, "EPOCH", GLOBAL_SCOPE); if (timeResolution > 0) { std::stringstream timeRes; timeRes << timeResolution; addAttribute(REQUEST_TIMERES, timeRes.str(), GLOBAL_SCOPE); } addAttribute(REQUEST_OUTPUTPARAMS, outputParams, GLOBAL_SCOPE); if (!ttName.empty()) addAttribute(REQUEST_TTNAME, ttName, GLOBAL_SCOPE); return true; } bool FileWriterCDF::writeMissionInfo(MissionInfoSPtr missionInfo, long varNum) { if (missionInfo == nullptr) return false; // write info about mission std::vector> infoMap = missionInfo->getInfoMap(); for (auto info : infoMap) addAttribute(info.first, info.second, VARIABLE_SCOPE, varNum); return true; } bool FileWriterCDF::writeInstrumentInfo(InstrumentInfoSPtr instrumentInfo, long varNum) { if (instrumentInfo == nullptr) return false; // write info about instrument std::vector> infoMap = instrumentInfo->getInfoMap(); for (auto info : infoMap) addAttribute(info.first, info.second, VARIABLE_SCOPE, varNum); MissionInfoSPtr mission = MissionMgr::getInstance()->getMissionInfoFromId(instrumentInfo->getMissionId()); writeMissionInfo(mission, varNum); return true; } bool FileWriterCDF::writeDatasetInfo(DataSetInfoSPtr datasetInfo, long varNum) { if (datasetInfo == nullptr) return false; // write info about datasetId std::vector> infoMap = datasetInfo->getInfoMap(); for (auto info : infoMap) addAttribute(info.first, info.second, VARIABLE_SCOPE, varNum); InstrumentInfoSPtr instrumentInfo = InstrumentMgr::getInstance()->getInstrumentInfoFromId(datasetInfo->getInstrumentId()); writeInstrumentInfo(instrumentInfo, varNum); return true; } bool FileWriterCDF::writeParameterInfo(ParamInfoSPtr parameterInfo, long varNum) { if (parameterInfo == nullptr) return false; std::vector> infoMap = parameterInfo->getInfoMap(&_parameterManager); for (auto info : infoMap) addAttribute(info.first, info.second, VARIABLE_SCOPE, varNum); DataSetInfoSPtr dataSetInfo = DataSetMgr::getInstance()->getDataSetInfoFromId(parameterInfo->getDatasetId()); writeDatasetInfo(dataSetInfo, varNum); return true; } bool FileWriterCDF::writeTableParamsInfo(std::vector tableParams, int level) { if (tableParams.empty()) return false; for (auto tableId : tableParams) { // get current param info AMDA::Info::ParamInfoSPtr tableInfo = AMDA::Info::ParamMgr::getInstance()->getParamInfoFromId(tableId); std::vector> tableInfoMap = tableInfo->getTableInfoMap(&_parameterManager); for (auto info : tableInfoMap) addAttribute(info.first, info.second, VARIABLE_SCOPE, level); DataSetInfoSPtr dataSetInfo = DataSetMgr::getInstance()->getDataSetInfoFromId(tableInfo->getDatasetId()); writeDatasetInfo(dataSetInfo, level); } return true; } bool FileWriterCDF::writeParamsInfo(ParamPropertiesList ¶mPropertiesList, OutputStructure outputStructure, std::string currentParamId) { std::set, FileWriter::cmpParamInfoStruct> baseParamsInfoList; std::set, FileWriter::cmpParamInfoStruct> derivedParamsInfoList; // sort parameters info for (auto paramProperties : paramPropertiesList) { if ((outputStructure == ONE_FILE_PER_PARAMETER_PER_INTERVAL) && (currentParamId != paramProperties->getOutputId())) // add info only for current parameter continue; sortParametersInfoByType(paramProperties->getOutputId(), baseParamsInfoList, derivedParamsInfoList); } // write derived parameters info for (auto paramInfo : derivedParamsInfoList) { std::map::iterator it = _cdfVarMap.find(paramInfo.first); if (it == _cdfVarMap.end()) { createCDFVar(paramInfo.first.c_str(), DT_NONE, 1, 1, _cdfVarMap[paramInfo.first]); addAttribute("AMDA_INFO", "Derived parameter description. No data output.", VARIABLE_SCOPE, _cdfVarMap[paramInfo.first].varNum); } writeParameterInfo(paramInfo.second, _cdfVarMap[paramInfo.first].varNum); } // write base parameters info for (auto paramInfo : baseParamsInfoList) { std::map::iterator it = _cdfVarMap.find(paramInfo.first); if (it == _cdfVarMap.end()) { createCDFVar(paramInfo.first.c_str(), DT_NONE, 1, 1, _cdfVarMap[paramInfo.first]); addAttribute("AMDA_INFO", "Base parameter description. No data output.", VARIABLE_SCOPE, _cdfVarMap[paramInfo.first].varNum); } writeParameterInfo(paramInfo.second, _cdfVarMap[paramInfo.first].varNum); } return true; } bool FileWriterCDF::writeIntervalInfo(std::string startTime, std::string stopTime, bool isSeveralIntervals) { if (!isSeveralIntervals) { addAttribute(INTERVAL_START, startTime, GLOBAL_SCOPE); addAttribute(INTERVAL_STOP, stopTime, GLOBAL_SCOPE); return true; } else { addAttribute(INTERVAL_MIN_START, startTime, GLOBAL_SCOPE); addAttribute(INTERVAL_MAX_STOP, stopTime, GLOBAL_SCOPE); return true; } } bool FileWriterCDF::addAttribute(std::string attName, std::string attVal, long scope, long varNum) { boost::mutex::scoped_lock scoped_lock(ParameterManager::mutexCDFLib); if (_cdfid == NULL) return false; CDFstatus status; long attNum = CDFgetAttrNum(_cdfid, (char *)attName.c_str()); if (attNum < 0) { status = CDFcreateAttr(_cdfid, (char *)attName.c_str(), scope, &attNum); if (status != CDF_OK) return false; } if (scope == GLOBAL_SCOPE) status = CDFputAttrgEntry(_cdfid, attNum, 0, CDF_CHAR, attVal.size(), (void *)attVal.c_str()); else status = CDFputAttrzEntry(_cdfid, attNum, varNum, CDF_CHAR, attVal.size(), (void *)attVal.c_str()); return (status == CDF_OK); } bool FileWriterCDF::writeTimeData(std::string /* paramId */, double data, OutputFormatTime /* timeFormat */, bool isFirstParam) { if (_cdfid == NULL) return false; if (!isFirstParam) return true; std::stringstream isoTime; TimeUtil::formatTimeDateInIso(data, isoTime); char epString[EPOCH4_STRING_LEN + 1]; memset(&epString, 0, sizeof(epString)); if (!isoTime.str().empty()) strncpy(epString, isoTime.str().c_str(), EPOCH4_STRING_LEN); double epochTime = parseEPOCH4(epString); return writeOneData(CDF_TIME_VAR, 0, &epochTime); } bool FileWriterCDF::writeOneData(std::string paramId, int varIndex, void *data) { if (_cdfid == NULL) return false; if (_cdfVarMap[paramId].varNum < 0) return false; void *pos = _cdfVarMap[paramId].buffer; pos = static_cast(pos) + _cdfVarMap[paramId].bufferNbRec * _cdfVarMap[paramId].dim1Size * _cdfVarMap[paramId].dim2Size * _cdfVarMap[paramId].numBytes + varIndex * _cdfVarMap[paramId].numBytes; memcpy(pos, data, _cdfVarMap[paramId].numBytes); return true; } bool FileWriterCDF::flushData(std::string paramId, bool isFirstParam) { boost::mutex::scoped_lock scoped_lock(ParameterManager::mutexCDFLib); if (_cdfid == NULL) return false; if (_cdfVarMap[paramId].varNum < 0) return false; CDFstatus status; if (isFirstParam) { if (_cdfVarMap[CDF_TIME_VAR].varNum < 0) return false; if (_cdfVarMap[CDF_TIME_VAR].bufferNbRec > 0) { status = CDFputzVarRangeRecordsByVarID(_cdfid, _cdfVarMap[CDF_TIME_VAR].varNum, _cdfVarMap[CDF_TIME_VAR].lastPushRec, _cdfVarMap[CDF_TIME_VAR].lastPushRec + _cdfVarMap[CDF_TIME_VAR].bufferNbRec - 1, _cdfVarMap[CDF_TIME_VAR].buffer); if (status != CDF_OK) { return false; } _cdfVarMap[CDF_TIME_VAR].lastPushRec += (_cdfVarMap[CDF_TIME_VAR].bufferNbRec); _cdfVarMap[CDF_TIME_VAR].bufferNbRec = 0; } } if (_cdfVarMap[paramId].bufferNbRec > 0) { status = CDFputzVarRangeRecordsByVarID(_cdfid, _cdfVarMap[paramId].varNum, _cdfVarMap[paramId].lastPushRec, _cdfVarMap[paramId].lastPushRec + _cdfVarMap[paramId].bufferNbRec - 1, _cdfVarMap[paramId].buffer); if (status != CDF_OK) { return false; } _cdfVarMap[paramId].lastPushRec += (_cdfVarMap[paramId].bufferNbRec); _cdfVarMap[paramId].bufferNbRec = 0; } return true; } bool FileWriterCDF::writeFloatData(std::string paramId, int varIndex, float data, bool /* precision */) { return writeOneData(paramId, varIndex, &data); } bool FileWriterCDF::writeShortData(std::string paramId, int varIndex, short data, bool /* precision */) { return writeOneData(paramId, varIndex, &data); } bool FileWriterCDF::writeIntData(std::string paramId, int varIndex, int data, bool /* precision */) { return writeOneData(paramId, varIndex, &data); } bool FileWriterCDF::writeDoubleData(std::string paramId, int varIndex, double data, bool /* precision */) { return writeOneData(paramId, varIndex, &data); } bool FileWriterCDF::writeLongDoubleData(std::string paramId, int varIndex, long double data, bool /* precision */) { // convert long double to double double doubleData = boost::numeric_cast(data); return writeOneData(paramId, varIndex, &doubleData); } bool FileWriterCDF::writeLogicalData(std::string paramId, int varIndex, AMDA::Parameters::LogicalData data, bool /* precision */) { // convert LogicalData to 2-byte unsigned integer unsigned short uShortData; switch (data) { case AMDA::Parameters::LogicalData::False: uShortData = 0; break; case AMDA::Parameters::LogicalData::True: uShortData = 1; break; case AMDA::Parameters::LogicalData::NaN: uShortData = 2; break; default: return false; } return writeOneData(paramId, varIndex, &uShortData); } bool FileWriterCDF::goToNextRecord(std::string paramId, bool isFirstParam) { ++_cdfVarMap[paramId].recNum; ++_cdfVarMap[paramId].bufferNbRec; if (isFirstParam) { ++_cdfVarMap[CDF_TIME_VAR].recNum; ++_cdfVarMap[CDF_TIME_VAR].bufferNbRec; } if (_cdfVarMap[paramId].bufferNbRec >= NB_RECORDS_BUFFER - 1) { return flushData(paramId, isFirstParam); } return true; } bool FileWriterCDF::finalize(bool /* isInfoFile */) { // nothing to do return true; } } /* namespace FileWriter */ } /* namespace Download */ } /* namespace ParamOutputImpl */ } /* namespace AMDA */