StatisticOutput.cc 12.5 KB
/**
 * StatisticOutput.cc
 *
 *  Created on: 04 nov. 2014
 *      Author: AKKA
 */

#include "StatisticOutput.hh"

#include "ServicesServer.hh"
#include "TimeUtil.hh"

#include "AMDA-Kernel_Config.hh"
#include "Parameter.hh"
#include "ParamMgr.hh"
#include "MissionMgr.hh"
#include "InstrumentMgr.hh"

#include <boost/filesystem/path.hpp>
#include <boost/filesystem.hpp>


namespace AMDA {
namespace ParamOutputImpl {

/**
 * @brief Implementation of a ParamOutput to apply statistic processes on parameters.
 */
namespace Statistic {

StatisticOutput::StatisticOutput(AMDA::Parameters::ParameterManager& pParameterManager) :
			ParamOutput(pParameterManager),
			_statisticProperties(),
			_currentIntervalIndex(0)
{
}

StatisticOutput::~StatisticOutput()
{
}

/**
 * @overload DataClient::establishConnection()
 */
void StatisticOutput::establishConnection()
{
	LOG4CXX_DEBUG(_logger,"StatisticOutput::establishConnection");

	for (auto paramProp : _statisticProperties.getParamPropertiesList())
	{
		try {
			AMDA::Parameters::ParameterSPtr param = _parameterManager.getParameter(
									paramProp->getId());

			for (auto statisticFunc : paramProp->getFunctionPropertiesList())
			{
				ProcessDescription procDesc;
				procDesc._paramId = paramProp->getId();
				procDesc._functionName = statisticFunc->getName();
				procDesc._index = paramProp->getIndex();
				procDesc._statisticProcesSPtr.reset(AMDA::Parameters::ServicesServer::getInstance()->getStatisticProcess(statisticFunc->getName(), *param.get(), paramProp->getIndex()));
				procDesc._statisticProcesSPtr->setArguments(statisticFunc->getArgumentMap());
				_processDescriptionList.push_back(procDesc);
				procDesc._statisticProcesSPtr->establishConnection();
			}
		} catch (...) {
			LOG4CXX_ERROR(_logger, "StatisticOutput::establishConnection - It's impossible to create statistic process for parameter " << paramProp->getId());
			throw;
		}
	}
}

/**
 * @overload ParamOutput::init()
 */
void StatisticOutput::init()
{
	LOG4CXX_DEBUG(_logger,"StatisticOutput::init");

	//init all needed parameters
	for (auto procDesc : _processDescriptionList)
	{
		try {
			procDesc._statisticProcesSPtr->init(_timeIntervalList);
		} catch (...) {
			LOG4CXX_ERROR(_logger, "StatisticOutput::init - It's impossible to init a statistic process");
			throw;
		}
	}
}

/**
 * @overload ParamOutput::apply()
 */
void StatisticOutput::apply()
{
	LOG4CXX_DEBUG(_logger,"StatisticOutput::apply");

	try {
		bool isFirstInterval = true;
		//Intervals loop
		while (_currentTimeInterval != _timeIntervalList->end())
		{
			//select output structure
			switch (_statisticProperties.getOutputStructure())
			{
			case OutputStructure::ONE_FILE :
				applyOneFile(isFirstInterval);
				break;
			case OutputStructure::ONE_FILE_PER_PARAMETER :
				applyOneFilePerParameter(isFirstInterval);
				break;
			default :
				LOG4CXX_WARN(_logger, "StatisticOutput::apply - output structure not implemented => use ONE-FILE");
			}
			//go to next time interval
			++_currentTimeInterval;
			++_currentIntervalIndex;
			isFirstInterval = false;
		}

		//write catalog
		for (auto catalog : _statisticCatalogMap)
		{
			std::string filePath = catalog.second.write(_workPath, _statisticProperties.getFileFormatKey());
			if (!filePath.empty())
				_files.push_back(filePath);
		}
	} catch (...) {
		LOG4CXX_ERROR(_logger, "StatisticOutput::apply : Error to apply output");
		throw;
	}
}

void StatisticOutput::applyOneFile(bool isFirstInterval)
{
	//init catalog if need
	if (isFirstInterval)
		initCatalog("");
	//create catalog interval
	TimeTableCatalog::TimeInterval newInt(_currentTimeInterval->_startTime,_currentTimeInterval->_stopTime);
	//compute statistic result for current interval
	for (auto &procDesc : _processDescriptionList)
	{
		try {
			std::vector<std::string> crtResult;
			std::vector<std::string> crtCoverage;
			procDesc._statisticProcesSPtr->compute(crtResult,crtCoverage);
			if (isFirstInterval)
				addProcessDescriptionInCatalog(&_statisticCatalogMap[""], &procDesc);
			newInt.addParameterData(procDesc._dataKey, crtResult);
			newInt.addParameterData(procDesc._coverageKey, crtCoverage);
		} catch (...) {
			LOG4CXX_ERROR(_logger, "StatisticOutput::applyOneFile - It's impossible to apply a statistic process");
			throw;
		}
	}
	_statisticCatalogMap[""].addInterval(newInt);
}

void StatisticOutput::applyOneFilePerParameter(bool isFirstInterval)
{
	std::map<std::string,TimeTableCatalog::TimeInterval *> intMap;
	for (auto &procDesc : _processDescriptionList)
	{
		try {
			std::vector<std::string> crtResult;
			std::vector<std::string> crtCoverage;
			procDesc._statisticProcesSPtr->compute(crtResult,crtCoverage);
			//init catalog if need
			if (isFirstInterval)
				initCatalog(procDesc._paramId);
			//create new interval if need
			if (intMap[procDesc._paramId] == NULL)
			{
				//init new interval
				intMap[procDesc._paramId] = new TimeTableCatalog::TimeInterval(_currentTimeInterval->_startTime,_currentTimeInterval->_stopTime);
			}
			//add process description in catalog
			if (isFirstInterval)
				addProcessDescriptionInCatalog(&_statisticCatalogMap[procDesc._paramId], &procDesc);
			//add process data and coverage in catalog
			intMap[procDesc._paramId]->addParameterData(procDesc._dataKey, crtResult);
			intMap[procDesc._paramId]->addParameterData(procDesc._coverageKey, crtCoverage);
		} catch (...) {
			LOG4CXX_ERROR(_logger, "StatisticOutput::applyOneFilePerParameter - It's impossible to apply a statistic process");
			throw;
		}
	}

	//add intervals in corresponding catalog
	for (auto intervalDef : intMap)
	{
		_statisticCatalogMap[intervalDef.first].addInterval(*intervalDef.second);
		delete intervalDef.second;
	}
}

void StatisticOutput::initCatalog(std::string paramId)
{
	if (_statisticCatalogMap.find(paramId) != _statisticCatalogMap.end())
		//already exist => nothing to do
		return;

	_statisticCatalogMap[paramId]._timeFormat = _statisticProperties.getTimeFormat();

	_statisticCatalogMap[paramId]._name = getCatalogName(paramId);

	if(getenv("HIDE_AMDA_DATE") != NULL)
		_statisticCatalogMap[paramId]._creationDate = 0;
	else
		_statisticCatalogMap[paramId]._creationDate = std::time(0);

	_statisticCatalogMap[paramId]._description.push_back("Generated by CDPP/AMDA Statistic Module");
                    //adding other infomation
        
                   for (ProcessDescription  processDes: _processDescriptionList)
                   {
                       std::stringstream statInfo;
                       AMDA::Info::ParamInfoSPtr paramInfo = AMDA::Info::ParamMgr::getInstance()->getParamInfoFromId(processDes._paramId);
                       
                       //AMDA::Info::MissionInfoSPtr missionInfo = AMDA::Info::MissionMgr::getInstance()->getMissionInfoFromId(processDes._paramId);
                       if(processDes._index == _processDescriptionList.front()._index)
                            statInfo<<"by using params: \n";

                       if(paramInfo->getInstrumentId() !="")
                       {
                            AMDA::Info::InstrumentInfoSPtr instrumentInfo = AMDA::Info::InstrumentMgr::getInstance()->getInstrumentInfoFromId(paramInfo->getInstrumentId());
                            if (instrumentInfo.get() != nullptr) {
                               if(instrumentInfo->getMissionId() != ""){
                                  AMDA::Info::MissionInfoSPtr missionInfo = AMDA::Info::MissionMgr::getInstance()->getMissionInfoFromId(instrumentInfo->getMissionId());
                                  if (missionInfo.get() != nullptr) {
                                     statInfo<< missionInfo->getName()<<"/";
                                  }
                               }
                               statInfo<<instrumentInfo->getName()<<"/";
                            }
                       }
                       statInfo<<processDes._paramId;
                       if(processDes._index != -1)
                          statInfo<<"["<<processDes._index<<"]";
                       statInfo<<"  with function ";
                       statInfo<<processDes._functionName;
                     // ading information about the origin 
                     if (_timeIntervalList->size() ==1 && _timeIntervalList->front()._ttPath.empty() && _timeIntervalList->front()._ttName.empty())
                     {
                         if(processDes._index == _processDescriptionList.back()._index){
                                     statInfo<<"\nwith interval : ";
                                     statInfo<<AMDA::TimeUtil::formatTimeDateInIso(_timeIntervalList->front()._startTime)<<" - ";
                                     statInfo<<AMDA::TimeUtil::formatTimeDateInIso(_timeIntervalList->front()._stopTime);
                         }
                     }else{
                         statInfo<<"\nfrom TimeTable/Catalog: ";
                         if(_currentTimeInterval->_ttName.empty())
                         {
                         statInfo<<_currentTimeInterval->_ttPath;
                         }else{
                             statInfo<< _currentTimeInterval->_ttName;
                     }   
                     }
                       _statisticCatalogMap[paramId]._description.push_back(statInfo.str());
                   }
}

void StatisticOutput::addProcessDescriptionInCatalog(TimeTableCatalog::Catalog* pCatalog, ProcessDescription* pProcDesc)
{
	//two parameters are created in a catalog for each process (for data and coverage).
	int indexOfDesc = pCatalog->getParameterDescriptions().size() / 2;

	//add catalog description for this process

	//data name
	std::stringstream dataName;

	dataName << pProcDesc->_functionName;
	dataName << "(";
	dataName << pProcDesc->_paramId;
	if (pProcDesc->_index >= 0)
	{
		dataName << "[";
		dataName << pProcDesc->_index;
		dataName << "]";
	}
	dataName << ")";

	//data key
	std::stringstream dataKey;
	dataKey << "stat_data_" << indexOfDesc;
	pProcDesc->_dataKey = dataKey.str();

	TimeTableCatalog::ParameterDescription desc(
		pProcDesc->_dataKey,
		dataName.str(),
		pProcDesc->_statisticProcesSPtr->getResultDimDefinition(),
		TimeTableCatalog::ParameterDescription::ParameterType::Double,
		"",
		"Statistic result computed by CDPP/AMDA",
		"",
		pProcDesc->_statisticProcesSPtr->getUCD(),
		""
	);
	pCatalog->addParameterDescription(desc);

	//coverage name
	std::stringstream covName;
	covName << "Coverage of ";
	covName << dataName.str();
	pProcDesc->_coverageKey = covName.str();

	//coverage key
	std::stringstream covKey;
	covKey << "stat_cov_" << indexOfDesc;
	pProcDesc->_coverageKey = covKey.str();


	TimeTableCatalog::ParameterDescription coverageDesc(
		pProcDesc->_coverageKey,
		covName.str(),
		pProcDesc->_statisticProcesSPtr->getResultDimDefinition(true),
		TimeTableCatalog::ParameterDescription::ParameterType::Double,
		"",
		"Coverage of the statistic result computed by CDPP/AMDA",
		"",
		"meta.code.qual",
		""
	);
	pCatalog->addParameterDescription(coverageDesc);
}

std::string StatisticOutput::getCatalogName(std::string paramId)
{
	std::stringstream fileName;

	if (_statisticProperties.getFileName().empty())
	{
		std::stringstream fileNameSuffix;
		if (_currentTimeInterval->_ttName.empty()) {
			//add start time
			double lStartTime = _currentTimeInterval->_startTime;
			char buffer[TIMELENGTH];
			Double2DD_Time(buffer, lStartTime);
			fileNameSuffix << "-" << buffer;
		}
		else {
			//add TT name
			fileNameSuffix << "-" <<  _currentTimeInterval->_ttName;
		}

		fileName << "statistic-";

		if (_statisticProperties.getOutputStructure() == OutputStructure::ONE_FILE_PER_PARAMETER)
		{
			fileName << paramId;
		}
		else
		{
			int crtFileNameSize = fileName.str().size() + fileNameSuffix.str().size();
			bool isFirst = true;
			for (auto paramProp : _statisticProperties.getParamPropertiesList())
			{
				std::stringstream paramPart;
				if (!isFirst) {
					paramPart << "-" ;
				}
				isFirst = false;

				for (auto statisticFunc : paramProp->getFunctionPropertiesList()) {
					paramPart << statisticFunc->getName() << "_";
				}
				paramPart << paramProp->getId();
				if (paramProp->getIndex() >= 0) {
					paramPart << "_" << paramProp->getIndex();
				}
				if (crtFileNameSize + paramPart.str().size() > 247) {
					//Filename is limited to 255 characters by Linux
					//+ we keep 4 characters for extension
					//+ we keep 3 characters for "etc"
					fileName << "_etc";
					break;

				}
				crtFileNameSize += paramPart.str().size();
				fileName << paramPart.str();
			}
		}

		fileName << fileNameSuffix.str();
	}
	else
		fileName << _statisticProperties.getFileName();

	return fileName.str();
}

} /* namespace Statistic */
} /* namespace ParamOutputImpl */
} /* namespace AMDA */