/*
 * \file Loads.c
 * \brief: implementation of the Loads class, derived from DataSet class
 */

/*Headers: {{{*/
#ifdef HAVE_CONFIG_H
	#include <config.h>
#else
#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
#endif

#include <vector>
#include <functional>
#include <algorithm>
#include <iostream>

#include "./DataSet.h"
#include "../shared/shared.h"
#include "../include/include.h"
#include "../EnumDefinitions/EnumDefinitions.h"

using namespace std;
/*}}}*/

/*Object constructors and destructor*/
/*FUNCTION Loads::Loads(){{{*/
Loads::Loads(){
	enum_type=LoadsEnum;
	return;
}
/*}}}*/
/*FUNCTION Loads::~Loads(){{{*/
Loads::~Loads(){
	return;
}
/*}}}*/

/*Numerics:*/
/*FUNCTION Loads::Configure{{{*/
void Loads::Configure(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters){

	vector<Object*>::iterator object;
	Load* load=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		load=dynamic_cast<Load*>(*object);
		load->Configure(elements,loads,nodes,vertices,materials,parameters);

	}

}
/*}}}*/
/*FUNCTION Loads::IsPenalty{{{*/
bool Loads::IsPenalty(int analysis_type){

	int ispenalty=0;
	int allispenalty=0;

	/*Now go through all loads, and get how many nodes they own, unless they are clone nodes: */
	for(int i=0;i<this->Size();i++){

		Load* load=dynamic_cast<Load*>(this->GetObjectByOffset(i));
		if (load->InAnalysis(analysis_type)){
			if(load->IsPenalty()) ispenalty++;
		}
	}

	/*Grab sum of all cpus: */
#ifdef _HAVE_MPI_
	MPI_Allreduce((void*)&ispenalty,(void*)&allispenalty,1,MPI_INT,MPI_SUM,IssmComm::GetComm());
	ispenalty=allispenalty;
#endif

	if(ispenalty)
	 return true;
	else
	 return false;
}
/*}}}*/
/*FUNCTION Loads::MaxNumNodes{{{*/
int Loads::MaxNumNodes(int analysis_type){

	int max=0;
	int allmax;
	int numnodes=0;

	/*Now go through all loads, and get how many nodes they own, unless they are clone nodes: */
	for(int i=0;i<this->Size();i++){

		Load* load=dynamic_cast<Load*>(this->GetObjectByOffset(i));
		if (load->InAnalysis(analysis_type)){
			numnodes=load->GetNumberOfNodes();
			if(numnodes>max)max=numnodes;
		}
	}

	/*Grab max of all cpus: */
#ifdef _HAVE_MPI_
	MPI_Allreduce((void*)&max,(void*)&allmax,1,MPI_INT,MPI_MAX,IssmComm::GetComm());
	max=allmax;
#endif

	return max;
}
/*}}}*/
/*FUNCTION Loads::NumberOfLoads(){{{*/
int Loads::NumberOfLoads(void){

	int localloads;
	int numberofloads;

	/*Get number of local loads*/
	localloads=this->Size();

	/*figure out total number of loads combining all the cpus (no clones here)*/
	#ifdef _HAVE_MPI_
	MPI_Reduce(&localloads,&numberofloads,1,MPI_INT,MPI_SUM,0,IssmComm::GetComm() );
	MPI_Bcast(&numberofloads,1,MPI_INT,0,IssmComm::GetComm());
	#else
	numberofloads=localloads;
	#endif

	return numberofloads;
}
/*}}}*/
/*FUNCTION Loads::NumberOfLoads(int analysis){{{*/
int Loads::NumberOfLoads(int analysis_type){

	int localloads = 0;
	int numberofloads;

	/*Get number of local loads*/
	for(int i=0;i<this->Size();i++){

		Load* load=dynamic_cast<Load*>(this->GetObjectByOffset(i));

		/*Check that this load corresponds to our analysis currently being carried out: */
		if (load->InAnalysis(analysis_type)) localloads++;
	}

	/*figure out total number of loads combining all the cpus (no clones here)*/
#ifdef _HAVE_MPI_
	MPI_Reduce(&localloads,&numberofloads,1,MPI_INT,MPI_SUM,0,IssmComm::GetComm() );
	MPI_Bcast(&numberofloads,1,MPI_INT,0,IssmComm::GetComm());
#else
	numberofloads=localloads;
#endif

	return numberofloads;
}
/*}}}*/
/*FUNCTION Loads::Size(){{{*/
int Loads::Size(void){

	return this->DataSet::Size();
}
/*}}}*/
/*FUNCTION Loads::Size(int analysis){{{*/
int Loads::Size(int analysis_type){

	int localloads = 0;

	/*Get number of local loads*/
	for(int i=0;i<this->Size();i++){

		Load* load=dynamic_cast<Load*>(this->GetObjectByOffset(i));

		/*Check that this load corresponds to our analysis currently being carried out: */
		if (load->InAnalysis(analysis_type)) localloads++;
	}

	return localloads;
}
/*}}}*/
/*FUNCTION Loads::SetCurrentConfiguration{{{*/
void Loads::SetCurrentConfiguration(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters){

	vector<Object*>::iterator object;
	Load* load=NULL;

	for ( object=objects.begin() ; object < objects.end(); object++ ){

		load=dynamic_cast<Load*>(*object);
		load->SetCurrentConfiguration(elements,loads,nodes,vertices,materials,parameters);

	}

}
/*}}}*/
