/*
    This file is part of the FElt finite element analysis package.
    Copyright (C) 1993 Jason I. Gobat and Darren C. Atkinson

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/************************************************************************
 * File:	truss.c							*
 *									*
 * Description:	This file contains the definition structure and		*
 *		stiffness function for a truss element.			*
 *									*
 * History:	V1.0 by Jason Gobat and Darren C. Atkinson		*
 ************************************************************************/

# include <math.h>
# include <stdio.h>
# include "allocate.h"
# include "element.h"
# include "misc.h"


struct definition trussDefinition = {
    trussType, Linear, 2, 2, 1, 3, {0, 1, 2, 3, 0, 0, 0}, 0
};

Vector TrussEquivNodalForces ();
Matrix TrussTransformMatrix ();

int trussEltStiffness (element)
   Element 	element;
{

   double		AEonL,L;
   Matrix		T;
   static Vector	equiv;
   int			count;
   static Matrix	Tt,
			ke,
			temp = NullMatrix;

   if (temp == NullMatrix) {
      equiv = CreateVector (6);
      ke = CreateMatrix (2,2);
      Tt = CreateMatrix (6,2);
      temp = CreateMatrix (6,2);

      if(ke==NullMatrix || Tt==NullMatrix || 
         temp==NullMatrix || equiv==NullMatrix)
         Fatal ("allocation error creating element stiffness matrix");
   }

   L = ElementLength (element, 3); 

   if (L <= TINY) {
      error ("length of element %d is zero to machine precision",element -> number);
      return 1;
   } 

   if (element -> material -> E == 0) {
      error ("truss element %d has 0.0 for Young's modulus (E)", element -> number);
      return 1;
   }
   if (element -> material -> A == 0) {
      error ("truss element %d has 0.0 for cros-sectional area (A)", element -> number);
      return 1;
   }

   AEonL = (element -> material -> A * element -> material -> E / L);

   MatrixData (ke) [1][1] = AEonL;
   MatrixData (ke) [1][2] = -AEonL;
   MatrixData (ke) [2][1] = -AEonL;
   MatrixData (ke) [2][2] = AEonL;

   T = TrussTransformMatrix (element);

   Tt = TransposeMatrix (Tt,T);

   element -> K = CreateMatrix (6,6);
   if (element -> K == NullMatrix)
      Fatal ("allocation error creating element %d stiffness matrix",element -> number);

   temp = MultiplyMatrices (temp,Tt,ke); 
   element -> K = MultiplyMatrices (element -> K,temp,T);

   if (element -> numdistributed > 0) {
      equiv = TrussEquivNodalForces (element, &count);
      if (equiv == NullMatrix)
         return count; 

      element -> node[1] -> eq_force[1] += VectorData (equiv) [1];
      element -> node[1] -> eq_force[2] += VectorData (equiv) [2];
      element -> node[1] -> eq_force[3] += VectorData (equiv) [3];
      element -> node[2] -> eq_force[1] += VectorData (equiv) [4];
      element -> node[2] -> eq_force[2] += VectorData (equiv) [5];
      element -> node[2] -> eq_force[3] += VectorData (equiv) [6];
   }
   return 0;
}

int trussEltStress (element)
   Element	element;
{
   double	cx,cy,cz,
		dx1,dy1,dz1,
		dx2,dy2,dz2,
		L,EonL,
		stress;
		
   L = ElementLength (element, 3);

   if (L <= TINY) {
      error ("length of element %d is zero to machine precision",element -> number);
      return 1;
   } 

   cx = (element -> node[2] -> x - element -> node[1] -> x)/L;
   cy = (element -> node[2] -> y - element -> node[1] -> y)/L;
   cz = (element -> node[2] -> z - element -> node[1] -> z)/L;

   EonL = element -> material -> E / L;

   dx1 = element -> node[1] -> dx[1];
   dy1 = element -> node[1] -> dx[2];
   dz1 = element -> node[1] -> dx[3];
   dx2 = element -> node[2] -> dx[1];
   dy2 = element -> node[2] -> dx[2];
   dz2 = element -> node[2] -> dx[3];

   stress = EonL*(cx*dx2 + cy*dy2 + cz*dz2 - cx*dx1 - cy*dy1 - cz*dz1);

   element -> ninteg = 1;
   SetupStressMemory (element);
  
   element -> stress[1] -> x = (element -> node[1] -> x + 
                                element -> node[2] -> x)/2.0;
   element -> stress[1] -> y = (element -> node[1] -> y + 
                                element -> node[2] -> y)/2.0;

   element -> stress[1] -> values[1] = stress;

   return 0;
}

Matrix TrussTransformMatrix (element)
   Element	element;
{
   double		L;
   double		cx,cy,cz;
   static Matrix	T = NullMatrix;

   if (T == NullMatrix) {
      T = CreateMatrix (2,6);
     
      if (T == NullMatrix)
         Fatal ("allocation error creating elt %d transform matrix",element -> number);
   }

   ZeroMatrix (T);

   L = ElementLength (element, 3);

   cx = (element -> node[2] -> x - element -> node[1] -> x)/L;
   cy = (element -> node[2] -> y - element -> node[1] -> y)/L;
   cz = (element -> node[2] -> z - element -> node[1] -> z)/L;

   MatrixData (T) [1][1] = cx;
   MatrixData (T) [1][2] = cy;
   MatrixData (T) [1][3] = cz;
   MatrixData (T) [2][4] = cx;
   MatrixData (T) [2][5] = cy;
   MatrixData (T) [2][6] = cz;

   return T;
}

Vector TrussEquivNodalForces (element, err_count)
   Element	element;
   int		*err_count;
{
   double		L;
   double		wa,wb;
   double		force1,
			force2;
   int			count;
   unsigned		i,j;
   Matrix		T;
   static Matrix	Tt;
   static Vector 	equiv = NullMatrix;
   static Vector	result;
 
   if (equiv == NullMatrix) {
      equiv = CreateVector (2);
      result = CreateVector (6);
      Tt = CreateMatrix (6,2);

      if (equiv == NullMatrix || result == NullMatrix || Tt == NullMatrix)
         Fatal ("error creating equivalent force vector for element %d",element -> number);
   }

   count = 0;
 
   if (element -> numdistributed != 1) {
      error ("element %d can only have one distributed load", element -> number);
      count ++;
   }

   if (element -> distributed[1] -> nvalues != 2) {
      error ("truss elt %d does not have 2 nodal values for a distributed load",
              element -> number);
      count++;
   }

   L = ElementLength (element, 3);

   if (L <= TINY) {
      error ("length of element %d is zero to machine precision",element -> number);
      count ++;
   } 

   if (element -> distributed[1] -> direction != Parallel) {
       error ("invalid direction specified for beam elt %d distributed load",
              element -> number);
       count++;
   }

   for (i = 1 ; i <= element -> distributed[1] -> nvalues ; i++) {
      if (element -> distributed[1] -> value[i].node < 1 || 
          element -> distributed[1] -> value[i].node > 2) {

          error ("incorrect node numbering for beam elt %d distributed load",
                  element -> number);
          count++;
      }
   }

   if (element -> distributed[1] -> value[1].node == 
       element -> distributed[1] -> value[2].node) {

       error ("incorrect node numbering for elt %d distributed load", 
               element -> number);
       count++;
   }

	/* 
	 * Thats all the error checking, bail out if we've had any
	 */

   if (count) {
      *err_count = count;
      return NullMatrix;
   }

   if (element -> distributed[1] -> value[1].node == 1) {
      wa = element -> distributed[1] -> value[1].magnitude;
      wb = element -> distributed[1] -> value[2].magnitude;
   }
   else if (element -> distributed[1] -> value[1].node == 2) {
      wb = element -> distributed[1] -> value[1].magnitude;
      wa = element -> distributed[1] -> value[2].magnitude;
   }

   if (wa == wb) 
      force1 = force2 = wa*L/2;
   else if (fabs (wa) > fabs (wb)) {
      force1 = wb*L/2 + (wa - wb)*L/3;
      force2 = wb*L/2 + (wa - wb)*L/6;
   }
   else if (fabs (wb) > fabs (wa)) {
      force1 = wa*L/2 + (wb - wa)*L/6;
      force2 = wa*L/2 + (wb - wa)*L/3;
   }

   VectorData (equiv) [1] = force1;
   VectorData (equiv) [2] = force2;

	/*
	 * Now that we know all is okay, allocate some memory if we
	 * haven't already done so for some other element
	 */

   SetEquivalentForceMemory (element);

   T = TrussTransformMatrix (element);
   Tt = TransposeMatrix (Tt, T);
   result = MultiplyMatrices (result, Tt, equiv);

   *err_count = 0;
   return result; 
}
