package fem;

import math.Maths;
import math.matrix.Matrix;
import math.matrix.Vector;
import exception.IllegalDimensionException;

public class K extends Matrix{

	/**
	 * UID
	 */
	private static final long serialVersionUID = 178085470108372130L;

	/**
	 * Linearer Ansatz mit zwei Konoten und zwei Freiheitsgrade.
	 * Verschiebung längs des Stabes oder Verdrehung in eine Dimension x|y|z.
	 * Normal mit ki = EA/L oder Torsion mit ki = GIt/L
	 * @param L Elementlänge
	 * @param ki Dehnsteifigkeit EA oder Torsionssteifigkeit GIt
	 * @return lokale Steifigkeitsmatrix
	 */
	public static Matrix bar2(double L, double ki){
		return new Matrix(new double[][]{{1,-1},{-1,1}}).times(ki/L);
	}

	/**
	 * Quadratischer Ansatz mit drei Konoten und drei Freiheitsgrade.
	 * Verschiebung längs des Stabes oder Verdrehung in eine Dimension x|y|z.
	 * Normal mit ki = EA/L oder Torsion mit ki = GIt/L
	 * @param L Elementlänge
	 * @param ki Dehnsteifigkeit EA oder Torsionssteifigkeit GIt
	 * @return lokale Steifigkeitsmatrix
	 */
	public static Matrix bar3(double L, double ki){
		return new Matrix(new double[][]{
				{ 7, -8,  1},
				{-8, 16, -8},
				{ 1, -8,  7}}).times(ki/(3*L));
	}
	
	/**
	 * Quadratischer Ansatz mit zwei Knoten und vier Freiheitsgrade.
	 * Verschiebung quer zum Balken und Drehung in othogonale Dimension.
	 * @param L Elementlänge
	 * @param EI Steifigkeit
	 * @return lokale Steifigkeitsmatrix
	 */
	public static Matrix beam4(double L, double EI){
		return new Matrix(new double[][]{
				{ 12  , -6*L  , -12  , -6*L  },
				{ -6*L,  4*L*L,   6*L,  2*L*L},
				{-12  ,  6*L  ,  12  ,  6*L  },
				{ -6*L,  2*L*L,   6*L,  4*L*L}}).times(EI/(L*L*L));
	}
	
	/**
	 * Quadratischer Ansatz mit zwei Knoten und sechs Freiheitsgrade.
	 * Verschiebung in zwei Dimensionen und Drehung in othogonale Dimension.
	 * @param L Elementlänge
	 * @param EA Dehnsteifigkeit
	 * @param EI Steifigkeit
	 * @return lokale Steifigkeitsmatrix
	 */
	public static Matrix beam6(double L, double EA, double EI){
		return beam(L, EA, 0, EI, 0);
	}
	
	/**
	 * Allgemeiner Balken mit linearen Dehn- und Torsions-Ansatz in x sowie
	 * quadratischen Biege-Ansatz um x und y 
	 * @param L Elementlänge
	 * @param EA Dehnsteifigkeit in x
	 * @param GIt Torsionssteifigkeit um x
	 * @param EIy Biegesteifigkeit um y
	 * @param EIz Biegesteifigkeit um z
	 * @return lokale Steifigkeitsmatrix 12x12
	 */
	public static Matrix beam12(double L, double EA, double GIt, double EIy, double EIz){
		int i, j, m = 12, r;
		
		// Alle k im Array
		Matrix[] ki = {
				bar2(L, EA),  // Normal
				bar2(L, GIt), // Torsion
				beam4(L, EIy), // Biegung zur y-Achse
				beam4(L, EIz)  // Biegung zur z-Achse
		};

		int[][] iIk = new int[4][];
		iIk[0] = new int[]{1,7};       // x translation Indices
		iIk[1] = new int[]{2,8};       // x rotation Indices	
		iIk[2] = new int[]{3,4,9,10};  // y translation rotation Indices
		iIk[3] = new int[]{5,6,11,12}; // y translation rotation Indices
		
		Matrix k = new Matrix(new double[m][m]);
		for(r=0;r<iIk.length;r++)
			if(iIk[r]!=null)
				for(i=0;i<iIk[r].length;i++)
					for(j=0;j<iIk[r].length;j++)
						k.set(iIk[r][i]-1,iIk[r][j]-1,ki[r].get(i,j));
		
		return k;
	}

	/**
	 * Allgemeiner Balken mit linearen Dehn- und Torsions-Ansatz in x sowie
	 * quadratischen Biege-Ansatz um x und y.
	 * Steifigkeiten Nullsetzen zur Reduzierung
	 * @param L Elementlänge
	 * @param EA Dehnsteifigkeit in x
	 * @param GIt Torsionssteifigkeit um x
	 * @param EIy Biegesteifigkeit um y
	 * @param EIz Biegesteifigkeit um z
	 * @return lokale Steifigkeitsmatrix nxn
	 */
	public static Matrix beam(double L, double EA, double GIt, double EIy, double EIz){
		int i,j,r;
		
		// local
		Matrix kx = fem.K.bar2(L, EA);  // Normal
		Matrix kt = fem.K.bar2(L, GIt); // Torsion
		Matrix ky = fem.K.beam4(L, EIy); // Biegung zur y-Achse
		Matrix kz = fem.K.beam4(L, EIz); // Biegung zur z-Achse
		
		// Alle k im Array
		Matrix[] ki = {kx,kt,ky,kz};
		
		int x = 0, t = 0, y = 0, z = 0;
		if(EA!=0)  x=1;
		if(GIt!=0) t=1;
		if(EIy!=0) y=1;
		if(EIz!=0) z=1;

		// Matrixdimension bestimmen
		int[][] iIk = new int[4][];
		if(x==1) // x translation Indices
			iIk[0] = new int[]{1,x+t+2*y+2*z+1};
		if(t==1) // x rotation Indices
			iIk[1] = new int[]{x+1,2*x+t+2*y+2*z+1};
		if(y==1) // y translation rotation Indices
			iIk[2] = new int[]{x+t+1,x+t+2,2*(x+t)+2*z+3,2*(x+t)+2*z+4};
		if(z==1) // y translation rotation Indices
			iIk[3] = new int[]{x+t+2*y+1,x+t+2*y+2,2*(x+t+2*y)+3,2*(x+t+2*y)+4};
		
		int m = (x + t + 2*y + 2*z) * 2;
		Matrix k = new Matrix(new double[m][m]);
		for(r=0;r<iIk.length;r++)
			if(iIk[r]!=null)
				for(i=0;i<iIk[r].length;i++)
					for(j=0;j<iIk[r].length;j++)
						k.set(iIk[r][i]-1,iIk[r][j]-1,ki[r].get(i,j));
		
		return k;
	}
	
	/**
	 * Transformation um y für Dehnstab in x
	 * @param L Elementlänge
	 * @param EA Dehnsteifigkeit
	 * @param alpha Drehwinkel in Grad um y
	 * @return globale Steifigkeitsmatrix
	 */
	public static Matrix yx(double L, double EA, double alpha){
		return yx(bar2(L,EA), alpha);
	}
	
	/**
	 * Transformation um y für Dehnstab in x
	 * @param k lokale Steifigkeitsmatrix
	 * @param alpha Drehwinkel in Grad um y
	 * @return globale Steifigkeitsmatrix T<sup>T</sup>kT
	 */
	public static Matrix yx(Matrix k, double alpha){
		Matrix K = null;
		try {
			K = fem.T.yx2(alpha).transpose().times(k).times(fem.T.yx2(alpha));
		} catch (IllegalDimensionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return K;
	}
	
	/**
	 * Transformation um z für Dehnstab in x
	 * @param L Elementlänge
	 * @param EA Dehnsteifigkeit
	 * @param beta Drehwinkel in Grad um z
	 * @return globale Steifigkeitsmatrix
	 */
	public static Matrix zx(double L, double EA, double beta){
		return zx(bar2(L,EA), beta);
	}
	
	/**
	 * Transformation um z für Dehnstab in x
	 * @param inz Inzidenztabelle
	 * @param L Elementlängen
	 * @param E Elastizitäten
	 * @param A Querschnitte
	 * @param beta Drehwinkel in Grad um z
	 * @return gesamte Steifigkeitsmatrix
	 */
	public static Matrix zx(int[][] inz, double[] L, double[] E, double[] A, double[] beta){
		int DOFs = Maths.max(inz);
		int i, j, k;
		Matrix Ki;
		double[][] Kd = new double[DOFs][DOFs];
		for(i=0; i<inz.length; i++){
			Ki = K.zx(L[i], E[i]*A[i], beta[i]);
			for(j=0; j<inz[0].length; j++)
				for(k=0; k<inz[0].length; k++)
					Kd[inz[i][j]-1][inz[i][k]-1] += Ki.get(j, k);
		}
		return new Matrix(Kd);
	}
	
	/**
	 * Transformation um z für Dehnstab in x
	 * @param inz Inzidenztabelle
	 * @param L Elementlängen
	 * @param E Elastizitäten
	 * @param A Querschnitte
	 * @param beta Drehwinkel in Grad um z
	 * @return gesamte Steifigkeitsmatrix
	 */
	public static Matrix zx(int[][] inz, Vector L, Vector E, Vector A, Vector beta){
		return zx(inz, L.getArray(), E.getArray(), A.getArray(), beta.getArray());
	}
	
	/**
	 * Transformation um z für Dehnstab in x
	 * @param k lokale Steifigkeitsmatrix
	 * @param beta Drehwinkel in Grad um z
	 * @return globale Steifigkeitsmatrix
	 */
	public static Matrix zx(Matrix k, double beta){
		Matrix K = null;
		try {
			K = fem.T.zx2(beta).transpose().times(k).times(fem.T.zx2(beta));
		} catch (IllegalDimensionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return K;
	}
	
	/**
	 * Transformation um y für Biegebalken in z und um y
	 * @param L Elementlänge
	 * @param EIy Biegesteifigkeit um y
	 * @param alpha Drehwinkel in Grad um y
	 * @return globale Steifigkeitsmatrix
	 */
	public static Matrix yzy(double L, double EIy, double alpha){
		return yzy(beam4(L,EIy), alpha);
	}
	
	/**
	 * Transformation um y für Biegebalken in z und um y
	 * @param k lokale Steifigkeitsmatrix
	 * @param alpha Drehwinkel in Grad um y
	 * @return globale Steifigkeitsmatrix
	 */
	public static Matrix yzy(Matrix k, double alpha){
		Matrix K = null;
		try {
			K = fem.T.yzy(alpha).transpose().times(k).times(fem.T.yzy(alpha));
		} catch (IllegalDimensionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return K;
	}
	
	/**
	 * Transformation um y für Dehnstab in x und Biegebalken in z und um y
	 * @param L Elementlänge
	 * @param EA Dehnsteifigkeit in x
	 * @param EIy Biegesteifigkeit um y
	 * @param alpha Drehwinkel in Grad um y
	 * @return globale Steifigkeitsmatrix
	 */
	public static Matrix yxzy(double L, double EA, double EIy, double alpha){
		return yxzy(beam6(L,EA,EIy), alpha);
	}
	
	/**
	 * Transformation um y für Dehnstab in x und Biegebalken in z und um y
	 * @param k lokale Steifigkeitsmatrix
	 * @param alpha Drehwinkel in Grad um y
	 * @return globale Steifigkeitsmatrix
	 */
	public static Matrix yxzy(Matrix k, double alpha){
		Matrix K = null;
		try {
			K = fem.T.yxzy(alpha).transpose().times(k).times(fem.T.yxzy(alpha));
		} catch (IllegalDimensionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return K;
	}
	
	public static void main(String[] args){
		System.out.println(K.beam12(1, 2, 4, 1, 1));
		System.out.println(K.beam(1, 1, 0, 0, 0));
		System.out.println(K.yx(1, 1, 0.01));
	}
}
