Skip to content
Snippets Groups Projects
Select Git revision
  • 130bb31e8f3a119fda5cb031a0cc218429fc6117
  • master default
  • 1.1
  • 1.0
4 results

translators.cpp

Blame
  • model.cpp 12.47 KiB
    #include <cstddef>
    #include <model.h>
    #include <iostream>
    #include <assert.h>
    #include <vector>
    #include "strops.h"
    #include "cap.h"
    #include "resistor.h"
    #include "inductor.h"
    #include "constantphase.h"
    #include "finitetr.h"
    #include "warburg.h"
    #include "paralellseriel.h"
    #include "log.h"
    
    using namespace eis;
    
    size_t Model::opposingBraket(const std::string& str, size_t index, char bracketChar)
    {
    	for(size_t i = index; i < str.size(); ++i)
    	{
    		if(str[i] == bracketChar)
    			return i;
    	}
    	return std::string::npos;
    }
    
    size_t Model::deepestBraket(const std::string& str)
    {
    	size_t deepestPos = std::string::npos;
    	size_t deepestLevel = 0;
    	size_t level = 0;
    	for(size_t i = 0; i < str.size(); ++i)
    	{
    		if(str[i] == '(')
    		{
    			++level;
    			if(level > deepestLevel)
    			{
    				deepestLevel = level;
    				deepestPos = i;
    			}
    		}
    	}
    	return deepestPos;
    }
    
    Componant *Model::processBrackets(std::string& str, size_t& bracketCounter)
    {
    	size_t bracketStart = deepestBraket(str);
    	Log(Log::DEBUG)<<str<<" bracket start "<<(bracketStart == std::string::npos ? std::string("npos") :  std::to_string(bracketStart));
    
    	if(bracketStart == std::string::npos)
    	{
    		Componant* componant = processBracket(str);
    		if(!componant)
    			Log(Log::DEBUG)<<"Warning: can not create componant type B for "<<str;
    		return componant;
    	}
    
    	size_t bracketEnd = opposingBraket(str, bracketStart);
    
    	if(bracketEnd == std::string::npos)
    	{
    		return nullptr;
    	}
    
    	std::string bracket = str.substr(bracketStart+1, bracketEnd-1-bracketStart);
    
    	Componant* componant = processBracket(bracket);
    	if(!componant)
    	{
    		Log(Log::DEBUG)<<"can not create componant type A for "<<bracket;
    	}
    	_bracketComponants.push_back(componant);
    
    	str.erase(str.begin()+bracketStart, str.begin()+bracketEnd+1);
    	str.insert(str.begin()+bracketStart, bracketCounter+48);
    	++bracketCounter;
    	return processBrackets(str, bracketCounter);
    }
    
    std::string Model::getParamStr(const std::string& str, size_t index)
    {
    	if(static_cast<int64_t>(str.size())-index < 3 || str[index+1] != '{')
    	{
    		Log(Log::WARN)<<"missing parameter string for "<<str[index];
    		return "";
    	}
    
    	size_t end = opposingBraket(str, index, '}');
    	std::string parameterStr = str.substr(index+2, end-index-2);
    	Log(Log::DEBUG)<<"param for "<<str[index]<<' '<<parameterStr;
    	return parameterStr;
    }
    
    Componant *Model::processBracket(std::string& str)
    {
    	Log(Log::DEBUG)<<__func__<<'('<<str<<')';
    	std::vector<std::string> tokens = tokenize(str, '-', '{', '}');
    
    	std::vector<Componant*> nodes;
    
    	for(const std::string& nodeStr : tokens)
    	{
    		Log(Log::DEBUG)<<__func__<<" full node str: "<<nodeStr;
    		std::vector<Componant*> componants;
    		for(size_t i = 0; i < nodeStr.size(); ++i)
    		{
    			Log(Log::DEBUG)<<__func__<<" arg: "<<nodeStr[i];
    			switch(nodeStr[i])
    			{
    				case Cap::staticGetComponantChar():
    				{
    					componants.push_back(new Cap(getParamStr(nodeStr, i)));
    					size_t opposing = opposingBraket(nodeStr, i, '}');
    					if(opposing != std::string::npos)
    						i = opposingBraket(nodeStr, i, '}');
    					break;
    				}
    				case Resistor::staticGetComponantChar():
    				{
    					componants.push_back(new Resistor(getParamStr(nodeStr, i)));
    					size_t opposing = opposingBraket(nodeStr, i, '}');
    					if(opposing != std::string::npos)
    						i = opposingBraket(nodeStr, i, '}');
    					break;
    				}
    				case Inductor::staticGetComponantChar():
    				{
    					componants.push_back(new Inductor(getParamStr(nodeStr, i)));
    					size_t opposing = opposingBraket(nodeStr, i, '}');
    					if(opposing != std::string::npos)
    						i = opposingBraket(nodeStr, i, '}');
    					break;
    				}
    				case Cpe::staticGetComponantChar():
    				{
    					componants.push_back(new Cpe(getParamStr(nodeStr, i)));
    					size_t opposing = opposingBraket(nodeStr, i, '}');
    					if(opposing != std::string::npos)
    						i = opposingBraket(nodeStr, i, '}');
    					break;
    				}
    				case Warburg::staticGetComponantChar():
    				{
    					componants.push_back(new Warburg(getParamStr(nodeStr, i)));
    					size_t opposing = opposingBraket(nodeStr, i, '}');
    					if(opposing != std::string::npos)
    						i = opposingBraket(nodeStr, i, '}');
    					break;
    				}
    				case FiniteTransmitionline::staticGetComponantChar():
    				{
    					componants.push_back(new FiniteTransmitionline(getParamStr(nodeStr, i)));
    					size_t opposing = opposingBraket(nodeStr, i, '}');
    					if(opposing != std::string::npos)
    						i = opposingBraket(nodeStr, i, '}');
    					break;
    				}
    				case '{':
    					i = opposingBraket(nodeStr, i, '}');
    				case '}':
    					Log(Log::WARN)<<getModelStr()<<" stray "<<nodeStr[i]<<" in model string";
    					break;
    				case '0' ... '9':
    				{
    					size_t j = nodeStr[i]-48;
    					if(_bracketComponants.size() > j)
    						componants.push_back(_bracketComponants[j]);
    					break;
    				}
    				default:
    					break;
    			}
    		}
    		if(componants.size() > 1)
    			nodes.push_back(new Parallel(componants));
    		else if(componants.size() == 1)
    			nodes.push_back(componants[0]);
    		else
    			Log(Log::WARN)<<"empty node for "<<nodeStr;
    	}
    
    	if(nodes.size() > 1)
    		return new Serial(nodes);
    	else if(nodes.size() == 1)
    		return nodes[0];
    	else
    		return nullptr;
    }
    
    Model::Model(const std::string& str): _modelStr(str)
    {
    	size_t bracketCounter = 0;
    	std::string strCpy(str);
    	_model = processBrackets(strCpy, bracketCounter);
    }
    
    Model::Model(const Model& in)
    {
    	operator=(in);
    }
    
    Model& Model::operator=(const Model& in)
    {
    	delete _model;
    	_modelStr = in._modelStr;
    	_bracketComponants.clear();
    	_flatComponants.clear();
    	_model = Componant::copy(in._model);
    	return *this;
    }
    
    Model::~Model()
    {
    	delete _model;
    }
    
    DataPoint Model::execute(fvalue omega, Componant* model)
    {
    	if(!model)
    		model = _model;
    
    	if(_model)
    	{
    		DataPoint dataPoint;
    		dataPoint.omega = omega;
    		dataPoint.im = _model->execute(omega);
    		return dataPoint;
    	}
    	else
    	{
    		Log(Log::WARN)<<"model not ready";
    	}
    	return DataPoint({std::complex<fvalue>(0,0), 0});
    }
    
    void Model::addComponantToFlat(Componant* componant, std::vector<Componant*>* flatComponants)
    {
    	Parallel* paralell = dynamic_cast<Parallel*>(componant);
    	if(paralell)
    	{
    		for(Componant* element : paralell->componants)
    			addComponantToFlat(element, flatComponants);
    		return;
    	}
    
    	Serial* serial = dynamic_cast<Serial*>(componant);
    	if(serial)
    	{
    		for(Componant* element : serial->componants)
    			addComponantToFlat(element, flatComponants);
    		return;
    	}
    
    	flatComponants->push_back(componant);
    }
    
    std::vector<Componant*> Model::getFlatComponants(Componant *model)
    {
    	if(model == nullptr || model == _model)
    	{
    		if(!_flatComponants.empty())
    			return _flatComponants;
    
    		addComponantToFlat(_model, &_flatComponants);
    		return getFlatComponants();
    	}
    	else
    	{
    		std::vector<Componant*> flatComponants;
    		addComponantToFlat(model, &flatComponants);
    		return flatComponants;
    	}
    }
    
    std::vector<DataPoint> Model::executeSweep(const Range& omega, Componant* model)
    {
    	if(!model)
    		model = _model;
    
    	std::vector<DataPoint> results;
    	results.reserve(omega.count);
    
    	if(!omega.log)
    	{
    		fvalue currOmega = omega.start;
    		fvalue step = (omega.end - omega.start)/(omega.count-1);
    
    		for(size_t i = 0; i < omega.count; ++i)
    		{
    			results.push_back(execute(currOmega, model));
    			currOmega+=step;
    		}
    	}
    	else
    	{
    		fvalue start = log10(omega.start);
    		fvalue end = log10(omega.end);
    		fvalue step = (end-start)/(omega.count-1);
    		fvalue currOmegaL = start;
    
    		for(size_t i = 0; i < omega.count; ++i)
    		{
    			results.push_back(execute(pow(10, currOmegaL), model));
    			currOmegaL+=step;
    		}
    	}
    	return results;
    }
    
    std::vector<DataPoint> Model::executeParamByIndexC(const std::vector<Range>& componantRanges, const Range& omega, size_t index)
    {
    	std::vector<fvalue> parameters = getSweepParamByIndex(componantRanges, index);
    
    	Componant* model = Componant::copy(_model);
    	setFlatParameters(parameters, model);
    
    	std::vector<DataPoint> data = executeSweep(omega, model);
    
    	delete model;
    
    	return data;
    }
    
    std::vector<DataPoint> Model::executeParamByIndex(const std::vector<Range>& componantRanges, const Range& omega, size_t index)
    {
    	std::vector<fvalue> parameters = getSweepParamByIndex(componantRanges, index);
    	assert(setFlatParameters(parameters));
    
    	return executeSweep(omega);
    }
    
    size_t Model::getRequiredStepsForSweeps(const std::vector<Range>& componantRanges)
    {
    	size_t stepsRequired = 1;
    	for(size_t i = 0; i < componantRanges.size(); ++i)
    		stepsRequired *= componantRanges[i].count;
    	return stepsRequired;
    }
    
    std::vector<fvalue> Model::getSweepParamByIndex(const std::vector<Range>& componantRanges, size_t index)
    {
    	size_t parametersCount = componantRanges.size();
    	std::vector<size_t> parameterIndexies(parametersCount, 0);
    	for(size_t i = 0; i < parametersCount && index > 0; ++i)
    	{
    		index = i > 0 ? index/componantRanges[i-1].count : index;
    		parameterIndexies[i] = index % componantRanges[i].count;
    		index -= parameterIndexies[i];
    	}
    
    	std::vector<fvalue> parameters(parametersCount, 0);
    	for(size_t i = 0; i < parametersCount; ++i)
    		parameters[i] = parameterIndexies[i]*componantRanges[i].stepSize()+componantRanges[i].start;
    	return parameters;
    }
    
    bool Model::executeParamSweep(const std::vector<Range>& componantRanges, const Range& omega,
                                  std::function<void(std::vector<DataPoint>&, const std::vector<fvalue>&)> dataCb)
    {
    	size_t parametersCount = getFlatParametersCount();
    
    	if(!checkParameterRanges(componantRanges))
    		return false;
    
    	size_t stepsRequired = getRequiredStepsForSweeps(componantRanges);
    
    	std::vector<fvalue> currentParam(parametersCount, 0);
    	for(size_t i = 0; i < parametersCount; ++i)
    		currentParam[i] = componantRanges[i].start;
    
    	Log(Log::INFO)<<"Executing sweep. Steps requried: "<<stepsRequired;
    
    	for(size_t i = 0; i < stepsRequired; ++i)
    	{
    		setFlatParameters(getSweepParamByIndex(componantRanges, i));
    		std::vector<DataPoint> result = executeSweep(omega);
    		dataCb(result, currentParam);
    	}
    
    	return true;
    }
    
    bool Model::setFlatParameters(const std::vector<fvalue>& parameters, Componant* model)
    {
    	if(parameters.size() != getFlatParametersCount())
    		return false;
    
    	if(!model)
    		model = _model;
    
    	size_t i = 0;
    	for(Componant* componant : getFlatComponants())
    	{
    		std::vector<fvalue> params;
    		for(size_t j = 0; j < componant->paramCount(); ++j)
    			params.push_back(parameters[i++]);
    		componant->setParam(params);
    	}
    
    	return true;
    }
    
    
    Componant* Model::flatParameterToFlatComponant(size_t parameterIndex)
    {
    	size_t i = 0;
    	for(Componant* componant : getFlatComponants())
    	{
    		i += componant->paramCount();
    		if(i > parameterIndex)
    			return componant;
    	}
    	return nullptr;
    }
    
    std::vector<fvalue> Model::getFlatParameters(Componant *model)
    {
    	if(!model)
    		model = _model;
    
    	std::vector<fvalue> params;
    	std::vector<Componant*> componants = getFlatComponants(model);
    	for(Componant* componant : componants)
    	{
    		for(fvalue param : componant->getParam())
    			params.push_back(param);
    	}
    	return params;
    }
    
    size_t Model::getFlatParametersCount()
    {
    	size_t count = 0;
    	for(Componant* componant : getFlatComponants())
    		count += componant->paramCount();
    	return count;
    }
    
    std::string Model::getModelStr() const
    {
    	std::string output;
    	output.reserve(_modelStr.size());
    	int bracket = 0;
    	for(const char c : _modelStr)
    	{
    		if(c == '{')
    			++bracket;
    		else  if(bracket == 0)
    			output.push_back(c);
    
    		if(c == '}')
    		{
    			--bracket;
    			if(bracket < 0)
    				return _modelStr;
    		}
    	}
    	return output;
    }
    
    bool Model::checkParameterRanges(const std::vector<eis::Range> ranges, Componant* model)
    {
    	if(!model)
    		model = _model;
    
    	if(!model)
    	{
    		Log(Log::ERROR)<<"model not ready";
    		return false;
    	}
    
    	size_t parametersCount = getFlatParametersCount();
    	std::vector<Componant*> flatComponants = getFlatComponants(model);
    
    	if(ranges.size() != parametersCount)
    	{
    		Log(Log::ERROR)<<"a parameter range must be provided for eatch componant parameter";
    		return false;
    	}
    
    	for(size_t i = 0; i < parametersCount; ++i)
    	{
    		if(ranges[i].count == 0 || (ranges[i].count < 2 && ranges[i].start != ranges[i].end))
    		{
    			Log(Log::ERROR)<<getModelStr()<<" paramter range must specify at least one paramter point if"
    				<<"one paramer point is specified start and end must be the same";
    			return false;
    		}
    		else if(ranges[i].start > ranges[i].end)
    		{
    			Log(Log::ERROR)<<getModelStr()<<" paramter range end-start must be positive";
    			return false;
    		}
    		else if(ranges[i].type != 'x' && ranges[i].type != flatParameterToFlatComponant(i)->getComponantChar())
    		{
    			Log(Log::ERROR)<<getModelStr()<<" componnant "<<i<<"'s range is of invalid type "
    				<<ranges[i].type<<". expected "<<flatComponants[i]->getComponantChar()<<'\n'
    				<<"Expected order:";
    
    			for(const Componant* componant : flatComponants)
    			{
    				Log(Log::ERROR, false)<<componant->getComponantChar();
    			}
    			std::cout<<std::endl;
    
    			return false;
    		}
    	}
    	return true;
    }