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

#include "StatisticOutput.hh"

#include "ServicesServer.hh"
#include "TimeUtil.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");

	bool isFirstInterval = true;
	try {
		//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);

	char *hideDate;
	if((hideDate = 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");
}

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())
	{
		fileName << "statistic-";

		if (_statisticProperties.getOutputStructure() == OutputStructure::ONE_FILE_PER_PARAMETER)
		{
			fileName << paramId;
		}
		else
		{
			bool isFirst = true;
			for (auto paramProp : _statisticProperties.getParamPropertiesList())
			{
				if (!isFirst)
					fileName << "-" ;
				isFirst = false;

				for (auto statisticFunc : paramProp->getFunctionPropertiesList())
					fileName << statisticFunc->getName() << "_";
				fileName << paramProp->getId();
				if (paramProp->getIndex() >= 0)
					fileName << "_" << paramProp->getIndex();
			}
		}

		if (_parameterManager.getTimeTablePath().empty())
		{
				//add start time
			double lStartTime = _currentTimeInterval->_startTime;
			char buffer[TIMELENGTH];
			Double2DD_Time(buffer, lStartTime);
			fileName << "-" << buffer;
		}
		else
		{
			//add TT name
			fileName << "-" <<  getTTName();
		}
	}
	else
		fileName << _statisticProperties.getFileName();

	return fileName.str();
}

std::string StatisticOutput::getTTName(void)
{
	boost::filesystem::path ttPath(_parameterManager.getTimeTablePath());
	std::string fileName = ttPath.filename().string();
	// name of the tt without parent path and extension
	fileName = fileName.substr(0, fileName.size() - ttPath.extension().string().size());
	return fileName;
}

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