﻿#include "phases.h"
#include <cmath>
#include <fstream>
#include <iostream>
#include <sstream>
#include "cenos_exception.h"


Phases::Phases()
{
	n = 0;
	k = 0;
	t_s = 0;
	t_e = 0;
	deltaF = 0;
	ttt = {};
	currentTime = 0;
	currentTimeStep = 0;
	current_temperature = {};
}

Phases::~Phases()
{
}

void Phases::findActiveNodes(SPData spd, std::string filename) //finds if active nodes exist in previous time steps
{
	if (ttt.austenizationTemperatureAc3 < ttt.austenizationTemperatureAc1)
	{
		throw cenos_exception("Wrong input data, temperature Ac3<Ac1");
	}

	std::ofstream logfile;
	logfile.open(filename, std::ios::out | std::ios::app);
	if (logfile.fail())
	{
		throw cenos_exception("Could not open logfile");
	}

	node_vector = spdata.getNodeNr();

	//std::cout << "NodeActivity().size " << spdata.getNodeActivity().size() << std::endl;
	logfile << "Find active nodes (0f). Number of active nodes: " << spdata.getNodeActivity().size() << "\n";

	if (spdata.getNodeActivity().size() != 0)
	{
		logfile << "NodeActivity().size != 0  " << std::endl;


		f_A = spdata.getAusteniteFraction();
		F = spdata.getBainiteFraction();
		f_M = spdata.getMartensiteFraction();
		if (f_M.size() == 0)
		{
			for (int i = 0; i < node_vector.size(); i++)
			{
				f_M.push_back(0);
			}	
		}
		node_start_time = spdata.getStartTime();
		node_real_time = spdata.getRealTime();
		node_activity_ph = spdata.getNodeActivity();
		for (int i = 0; i < node_vector.size(); i++)
		{
			delta_f_A.push_back(0);
			logfile << "(0f) node nr " << node_vector[i] << " austenite fraction " << f_A[i] << " bainite fraction " << F[i] << " node_start_time " << node_start_time[i] << " node_real_time " << node_real_time[i] << " node activity " << node_activity_ph[i] << "\n";
		}
		
		if (f_A.size() != F.size() || F.size() != f_M.size() || f_M.size() != node_start_time.size() || node_start_time.size() != node_real_time.size() || node_real_time.size() != node_activity_ph.size())
		{
			throw cenos_exception("spdata file incorrect");
		}
	}
	else
	{
		logfile << "NodeActivity().size == 0  " << std::endl;
		for (int i = 0; i < node_vector.size(); i++)
		{
			delta_f_A.push_back(0);
			node_start_time.push_back(0);
			node_real_time.push_back(0);
			F.push_back(0);
			f_A.push_back(0);
			f_M.push_back(0);
			node_activity_ph.push_back(0);
			logfile << "(0f) node nr " << node_vector[i] << " austenite fraction " << f_A[i] << " bainite fraction " << F[i] << " node_start_time " << node_start_time[i] << " node_real_time " << node_real_time[i] << " node activity " << node_activity_ph[i] << "\n";
		}

	}
	logfile.close();
}

void Phases::findNewActiveNodes(std::string filename) // adds new active nodes
{
	std::ofstream logfile;
	logfile.open(filename, std::ios::out | std::ios::app);
	if (logfile.fail())
	{
		throw cenos_exception("Could not open logfile");
	}
	logfile << "Find new active nodes (1f). Number of active nodes: " << node_activity_ph.size() << "\n";

	for (int i = 0; i < node_vector.size(); i++)
	{
		if (node_activity_ph[i] < 0.5)
		{

			if (current_temperature.values[i] > ttt.austenizationTemperatureAc1)
			{
				node_activity_ph[i] = 1;
				logfile << "(1f) node nr " << node_vector[i] << " current_temperature.values[i] " << current_temperature.values[i] << " current time " << currentTime << "node_activity_ph[i] " << node_activity_ph[i] << std::endl;
			}
		}
	}
	logfile.close();
}

void Phases::checkActiveNodes(std::string filename) //checks temperature of active node, sets node start time and real time
{
	std::ofstream logfile;
	logfile.open(filename, std::ios::out | std::ios::app);
	if (logfile.fail())
	{
		throw cenos_exception("Could not open logfile");
	}

	logfile << " Check active nodes (2f). Number of nodes: "<< node_vector.size() << "\n";


	for (int i = 0; i < node_vector.size(); i++)
	{

		if (current_temperature.values[i] > ttt.austenizationTemperatureAc3)
		{
			node_start_time[i] = 0;
			node_real_time[i] = 0;
			F[i] = 0;
			f_A[i] = 1;
			logfile << "(2f)node nr " << node_vector[i] << " current_temperature.values[i] " << current_temperature.values[i] << " current time " << currentTime  << " node_start_time " << node_start_time[i] << " node_real_time " << node_real_time[i] << "\n";
			
		}
		else
		{
			node_start_time[i] = node_start_time[i];
			node_real_time[i] = node_real_time[i];
			F[i] = F[i];
			logfile << "(2f) node nr " << node_vector[i] << " current_temperature.values[i] " << current_temperature.values[i] << " current time " << currentTime  << " node_start_time " << node_start_time[i] << " node_real_time " << node_real_time[i] << "\n";
		}
	}
	logfile.close();
}

void Phases::calculateAustenite(std::string filename) //calculate austenite fraction
{
	std::ofstream logfile;
	logfile.open(filename, std::ios::out | std::ios::app);
	if (logfile.fail())
	{
		throw cenos_exception("Could not open logfile");
	}

	logfile <<"Calculate austenite fraction (3f). "<< "\n";


	for (int i = 0; i < node_vector.size(); i++)
	{
		if (current_temperature.values[i] > ttt.austenizationTemperatureAc1)
		{

			if (ttt.austenizationTemperatureAc3 != ttt.austenizationTemperatureAc1)
			{

				delta_f_A[i] = (current_temperature.values[i] - ttt.austenizationTemperatureAc1) / (ttt.austenizationTemperatureAc3 - ttt.austenizationTemperatureAc1) - f_A[i];
				if (delta_f_A[i] > 0)
				{
					f_A[i] = f_A[i] + delta_f_A[i];
					node_start_time[i] = 0;
					node_real_time[i] = 0;

					if (f_A[i] > 1)
					{
						f_A[i] = 1;
						logfile << "(3f) node nr " << node_vector[i] << " current_temperature.values[i] " << current_temperature.values[i] << " current time " << currentTime <<  " austenite fraction " << f_A[i] << "\n";
					}

				}
				else
				{
					f_A[i] = f_A[i];
					logfile << "(3f) node nr " << node_vector[i]  << " current_temperature.values[i] " << current_temperature.values[i] << " current time " << currentTime  << " austenite fraction " << f_A[i] << "\n";
				}
			}
			else
			{
				f_A[i] = 1;
				logfile << "(3f) node nr " << node_vector[i] << " current_temperature.values[i] " << current_temperature.values[i] << " current time " << currentTime << " austenite fraction " << f_A[i] << "\n";
			}
		}

	}
	logfile.close();
}

void Phases::setTTTData(TTT_data data)
{
	ttt = data;
}


void Phases::setSPData(SPData spd)
{
	spdata = spd;
}
void Phases::setSHData(SHData shd)
{
	shdata = shd;
}

void Phases::setTime(double t)
{

	currentTime = t;
}

void Phases::setTimeStep(double t)
{
	currentTimeStep = t;
}

void Phases::setCurrentTemperature(Field temperature_current)
{
	current_temperature = temperature_current;
}



void Phases::updateStartTime(std::string filename)
{
	std::ofstream logfile;
	logfile.open(filename, std::ios::out | std::ios::app);
	if (logfile.fail())
	{
		throw cenos_exception("Could not open logfile");
	}
	logfile << "Update start time (4f). " << "\n";
	for (int i = 0; i < node_vector.size(); i++)
	{
		if (node_activity_ph[i] > 0.5)
		{
			if (current_temperature.values[i] < ttt.austenizationTemperatureAc3)
			{
				if (node_start_time[i] != 0)
				{
					node_real_time[i] = currentTime - node_start_time[i];
					logfile << "(4f)node nr " << node_vector[i] << " current_temperature.values[i] " << current_temperature.values[i] << " current time " << currentTime  << " node_start_time " << node_start_time[i] << " node_real_time " << node_real_time[i] << "\n";
				}
				else
				{
					node_start_time[i] = currentTime;
					logfile << "(4f) node nr " << node_vector[i] << " current_temperature.values[i] " << current_temperature.values[i] << " current time " << currentTime << " node_start_time " << node_start_time[i] << " node_real_time " << node_real_time[i] << "\n";
				}
			}
			else
			{
				node_start_time[i] = 0;
				logfile << "(4f) node nr " << node_vector[i] << " current_temperature.values[i] " << current_temperature.values[i] << " current time " << currentTime << " node_start_time " << node_start_time[i] << " node_real_time " << node_real_time[i] << "\n";
			}
		}
	}
	logfile.close();
}



void Phases::calculate(std::string filename) // calculate bainite&pearlite fraction
{

	std::ofstream logfile;
	logfile.open(filename, std::ios::out | std::ios::app);
	if (logfile.fail())
	{
		throw cenos_exception("Could not open logfile");
	}

	logfile << "Phase change calculation (5f). " << "\n";

	for (int i = 0; i < node_vector.size(); i++)

	{
		t_s = ttt.getTStart(current_temperature.values[i]);
		t_e = ttt.getTEnd(current_temperature.values[i]);
		if (node_activity_ph[i] < 0.5)
		{
			continue;
		}
		if (currentTimeStep == 0)
		{ 
			continue;
		}
		if (node_real_time[i] < t_s)
		{ 
			continue;
		}
		if (t_s == 0 || t_e == 0)
		{
			continue;
		}
		
		n = log(log(1 - 0.01) / log(1 - 0.99)) / log(t_s / t_e); //constant
		k = -log(1 - 0.01) / pow(t_s, n); //constant
		deltaF = k * n * pow(node_real_time[i], (n - 1)) * exp(-k * (pow(node_real_time[i], n))) * currentTimeStep * f_A[i]; //  // how much phase changed in particular node in this time step
		F[i] = F[i] + deltaF;
		
		//f_A[i] = f_A[i] - F[i];
		if (F[i] > f_A[i])
		{
			F[i] = f_A[i];
		}

		logfile << "(5f) node nr " << node_vector[i] << " current_temperature.values[i] " << current_temperature.values[i] << " current time " << currentTime  << " node_real_time " << node_real_time[i] << " node_start_time " << node_start_time[i] << " t_s " << t_s << " t_e " << t_e << " n " << n << " k " << k <<" austenite fraction "<< f_A[i] << " bainite fraction " << F[i] << "\n";
		
	}
	logfile.close();

}
void Phases::calculateMartensite(std::string filename) // calculate bainite&pearlite fraction
{
	for (int i = 0; i < node_vector.size(); i++)
	{
		if (node_activity_ph[i] > 0.5)
		{
			if (current_temperature.values[i] < ttt.martensiteStartTemperature)
			{
				f_M[i] = f_A[i] - F[i];
			}
			else
			{
				f_M[i] = 0;
			}
		}
		else
		{
			f_M[i] = 0;
		}

	}
}

void Phases::calculatePhases(std::string filename)
{
	findNewActiveNodes(filename);
	checkActiveNodes(filename);
	calculateAustenite(filename);
	updateStartTime(filename);
	calculateMartensite(filename);
	calculate(filename);
}

void Phases::writeSPData(std::string filename)
{
	std::cout << "writing spdata to " << filename << std::endl;
	spdata.setAusteniteFraction(f_A);
	spdata.setBainiteFraction(F);
	spdata.setMartensiteFraction(f_M);
	spdata.setStartTime(node_start_time);
	spdata.setRealTime(node_real_time);
	spdata.setTime(currentTime);
	spdata.setNodeActivity(node_activity_ph);
	spdata.writeData(filename);
}


void Phases::writePhases(std::string filename)
{

	std::ofstream calculatedPhases;
	calculatedPhases.open(filename);
	if (calculatedPhases.fail())
	{
		throw cenos_exception("Could not open PhaseField file");
	}
	calculatedPhases << current_temperature.nr_of_nodes <<  "\n";

	for (int i = 0; i < node_vector.size(); i++)
	{
		if (node_activity_ph[i] > 0.5)
		{
			if (current_temperature.values[i] > ttt.martensiteStartTemperature)
			{
				calculatedPhases << current_temperature.nodes[i] << " " << (1 + F[i]) << "\n";
			}
			else
			{
				calculatedPhases << current_temperature.nodes[i] << " " << (3 - F[i]) << "\n";
			}
		}
		else
		{
			calculatedPhases << current_temperature.nodes[i] <<  " 0\n";
		}


	}
	calculatedPhases.close();
}

void Phases::writeAustenite(std::string filename)
{

	std::ofstream calculatedAustenite;
	calculatedAustenite.open(filename);
	if (calculatedAustenite.fail())
	{
		throw cenos_exception("Could not open AusteniteField file");
	}
	calculatedAustenite << current_temperature.nr_of_nodes  << "\n";

	for (int i = 0; i < node_vector.size(); i++)
	{
		if (current_temperature.values[i] > ttt.martensiteStartTemperature)
		{
			calculatedAustenite << current_temperature.nodes[i] << " " << (f_A[i]-F[i]) *100 << "\n";
		}
		else
		{
			calculatedAustenite << current_temperature.nodes[i] << " 0\n";
		}
			
		
	}
	calculatedAustenite.close();
}

void Phases::writeMartensite(std::string filename)
{

	std::ofstream calculatedMartensite;
	calculatedMartensite.open(filename);
	if (calculatedMartensite.fail())
	{
		throw cenos_exception("Could not open MartensiteField file");
	}
	calculatedMartensite << current_temperature.nr_of_nodes << "\n";


	for (int i = 0; i < node_vector.size(); i++)

		calculatedMartensite << current_temperature.nodes[i] << " " << f_M[i] * 100 << "\n";

	calculatedMartensite.close();
}

void Phases::writeBainite(std::string filename)
{

	std::ofstream calculatedBainite;
	calculatedBainite.open(filename);
	if (calculatedBainite.fail())
	{
		throw cenos_exception("Could not open BainiteField file");
	}
	calculatedBainite << current_temperature.nr_of_nodes  << "\n";

	for (int i = 0; i < node_vector.size(); i++)
	{
		
		calculatedBainite << current_temperature.nodes[i] << " " << F[i] * 100 << "\n";

		
	}
	calculatedBainite.close();
}

//////////// <calculate max temperature in every node during the whole heating-cooling process/////////////////////

void Phases::readMaxTempInNode(SHData shd, std::string filename) //finds if data is saved from previous time steps
{
	std::ofstream logfile;
	logfile.open(filename, std::ios::out | std::ios::app);
	if (logfile.fail())
	{
		throw cenos_exception("Could not open logfile");
	}

	node_vector_sh = shdata.getNodeNr();
	node_max_temp = shdata.getNodeMaxTemperature();
	//std::cout << "getNodeMaxTemperature().size() " << spdata.getNodeActivity().size() << std::endl;
	if (shdata.getNodeMaxTemperature().size() != 0)
	{
		logfile << "Node nr != 0" << " current time " << currentTime << std::endl;
	}
	else
	{
		logfile << "Node nr == 0" << " current time " << currentTime << std::endl;
		for (int i = 0; i < node_vector_sh.size(); i++)
		{
			node_max_temp.push_back(0);
		}
	}
	logfile.close();
}



void Phases::findMaxTempInNode(std::string filename) //sets( on the current temp value) or calculates the max temperature in node
{
	std::ofstream logfile;
	logfile.open(filename, std::ios::out | std::ios::app);
	node_vector_sh = shdata.getNodeNr();

	for (int i = 0; i < node_vector_sh.size(); i++)
	{
		if (currentTime == 0)
		{
			node_max_temp[i] = current_temperature.values[i];
		}
		else
		{
			node_max_temp[i] = node_max_temp[i];
		}

		if (node_max_temp[i] < current_temperature.values[i])
		{
			node_max_temp[i] = current_temperature.values[i];
			logfile << " current time " << currentTime << " Node nr " << i << " node_max_temp[i] " << node_max_temp[i] << " current_temperature.values[i] " << current_temperature.values[i] <<  std::endl;
		}
		else
		{
			node_max_temp[i] = node_max_temp[i];
			logfile << " current time " << currentTime << " Node nr " << i << " node_max_temp[i] " << node_max_temp[i] << " current_temperature.values[i] " << current_temperature.values[i] << std::endl;
		}
	}
	logfile.close();
}

void Phases::writeSHData(std::string filename) /// write data in shdata.spd file in getdpresults folder
{
	//std::cout << "writing shdata to " << filename << std::endl;
	shdata.setNodeMaxTemperature(node_max_temp);
	shdata.writeData(filename);
}
void Phases::writeMaxTemperature(std::string filename) /// write data from every time step in MaxTemperatureField.dat (in getdpresults folder)
{
	std::ofstream MaxTemp;
	MaxTemp.open(filename);
	if (MaxTemp.fail())
	{
		throw cenos_exception("Could not open MaxTemperatureField file");
	}
	MaxTemp << current_temperature.nr_of_nodes << "\n";

	for (int i = 0; i < node_vector_sh.size(); i++)
	{
		MaxTemp << current_temperature.nodes[i] << " " << node_max_temp[i] << "\n";
	}
	MaxTemp.close();
}
