/* This file is part of the FElt finite element analysis package. Copyright (C) 1993-2000 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: beam.c * * * * Description: This file contains the definition structure and * * stiffness function for a beam element. * ************************************************************************/ # include # include "allocate.h" # include "fe.h" # include "error.h" # include "misc.h" int beamEltSetup ( ); int beamEltStress ( ); struct definition beamDefinition = { "beam", beamEltSetup, beamEltStress, Linear, 2, 2, 3, 3, {0, 1, 2, 6, 0, 0, 0}, 1 }; Matrix BeamLocalK ( ); Matrix BeamTransformMatrix ( ); Vector BeamEquivNodalForces ( ); Matrix BeamConsistentMassMatrix ( ); Matrix BeamLumpedMassMatrix ( ); static void ResolveEndForces ( ); int beamEltSetup (element, mass_mode, tangent) Element element; char mass_mode; int tangent; { Matrix T, me, ke; Vector equiv; int count; if (element -> material -> A == 0) { error ("beam element %d has 0.0 for cross-sectional area (A)", element -> number); return 1; } if (element -> material -> E == 0) { error ("beam element %d has 0.0 for Young's modulus (E)", element -> number); return 1; } if (element -> material -> Ix == 0) { error ("beam element %d has 0.0 for Ixx moment of inertia (Ix)", element -> number); return 1; } ke = BeamLocalK (element); if (ke == NullMatrix) return 1; T = BeamTransformMatrix (element); if (T == NullMatrix) return 1; if (element -> K == NullMatrix) element -> K = CreateMatrix (6,6); MultiplyAtBA (element -> K, T, ke); /* * deal with the possibility of hinged boundary conditions */ ResolveHingeConditions (element); /* * deal with the possibility of distributed loads */ if (element -> numdistributed > 0) { equiv = BeamEquivNodalForces (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[6] += 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[6] += VectorData (equiv) [6]; } /* * do we need to form the mass matrix? If so which kind? */ if (mass_mode) { if (mass_mode == 'c') me = BeamConsistentMassMatrix (element); else if (mass_mode == 'l') me = BeamLumpedMassMatrix (element); else me = NullMatrix; if (me == NullMatrix) return 1; if (element -> M == NullMatrix) element -> M = CreateMatrix (6,6); MultiplyAtBA (element -> M, T, me); } return 0; } int beamEltStress (element) Element element; { unsigned i; int count; static Vector f, dlocal, d = NullMatrix; Matrix T; static Matrix ke = NullMatrix; static Matrix Tt; Vector equiv; static Vector eq_local; if (d == NullMatrix) { ke = CreateMatrix (6,6); d = CreateVector (6); f = CreateVector (6); Tt = CreateMatrix (6,6); dlocal = CreateVector (6); eq_local = CreateVector (6); } VectorData (d) [1] = element -> node[1] -> dx[1]; VectorData (d) [2] = element -> node[1] -> dx[2]; VectorData (d) [3] = element -> node[1] -> dx[6]; VectorData (d) [4] = element -> node[2] -> dx[1]; VectorData (d) [5] = element -> node[2] -> dx[2]; VectorData (d) [6] = element -> node[2] -> dx[6]; T = BeamTransformMatrix (element); if (T == NullMatrix) return 1; /* * We already have the element stiffness matrix (we saved it * by setting element -> retainK = True). We do have to transform * it back to local coordinates however. Once we're done with * it, we should go ahead and destroy it. */ TransposeMatrix (Tt, T); MultiplyAtBA (ke, Tt, element -> K); DestroyMatrix (element -> K); element -> K = NullMatrix; MultiplyMatrices (dlocal, T, d); MultiplyMatrices (f, ke, dlocal); if (element -> numdistributed > 0) { equiv = BeamEquivNodalForces (element, &count); if (equiv == NullMatrix) return count; MultiplyMatrices (eq_local, T, equiv); for (i = 1 ; i <= 6 ; i++) VectorData (f) [i] -= VectorData (eq_local) [i]; } element -> ninteg = 2; SetupStressMemory (element); element -> stress [1] -> x = element -> node[1] -> x; element -> stress [1] -> y = element -> node[1] -> y; element -> stress [2] -> x = element -> node[2] -> x; element -> stress [2] -> y = element -> node[2] -> y; for (i = 1; i <= 3 ; i++) { element -> stress [1] -> values [i] = VectorData (f) [i]; element -> stress [2] -> values [i] = VectorData (f) [i+3]; } return 0; } /* * These are the essentially private functions */ Matrix BeamLocalK (element) Element element; { double L, L3, L2; double EI, AEonL; static Matrix ke = NullMatrix; if (ke == NullMatrix) ke = CreateMatrix (6,6); ZeroMatrix (ke); L = ElementLength (element, 2); if (L <= TINY) { error ("length of element %d is zero to machine precision", element -> number); return NullMatrix; } L2 = L*L; L3 = L2*L; EI = element -> material -> E * element -> material -> Ix; AEonL = (element -> material -> E * element -> material -> A)/L; MatrixData (ke) [1][1] = AEonL; MatrixData (ke) [1][4] = -AEonL; MatrixData (ke) [2][2] = 12*EI/L3; MatrixData (ke) [2][3] = 6*EI/L2; MatrixData (ke) [2][5] = -12*EI/L3; MatrixData (ke) [2][6] = 6*EI/L2; MatrixData (ke) [3][3] = 4*EI/L; MatrixData (ke) [3][5] = -6*EI/L2; MatrixData (ke) [3][6] = 2*EI/L; MatrixData (ke) [4][4] = AEonL; MatrixData (ke) [5][5] = 12*EI/L3; MatrixData (ke) [5][6] = -6*EI/L2; MatrixData (ke) [6][6] = 4*EI/L; MirrorMatrix (ke); return ke; } Matrix BeamLumpedMassMatrix (element) Element element; { static Matrix me = NullMatrix; double L; double factor; double I_factor; if (me == NullMatrix) { me = CreateMatrix (6,6); ZeroMatrix (me); } L = ElementLength (element, 2); factor = (element -> material -> A * element -> material -> rho * L)/2.0; I_factor = factor*L*L/12.0; MatrixData (me) [1][1] = factor; MatrixData (me) [2][2] = factor; MatrixData (me) [3][3] = I_factor; MatrixData (me) [4][4] = factor; MatrixData (me) [5][5] = factor; MatrixData (me) [6][6] = I_factor; return me; } Matrix BeamConsistentMassMatrix (element) Element element; { static Matrix me = NullMatrix; double L; double f1,f2; if (me == NullMatrix) { me = CreateMatrix (6,6); ZeroMatrix (me); } L = ElementLength (element, 2); f1 = (element -> material -> A * element -> material -> rho * L)/6.0; f2 = f1/70.0; MatrixData (me) [1][1] = 2.0*f1; MatrixData (me) [1][4] = f1; MatrixData (me) [2][2] = 156.0*f2; MatrixData (me) [2][3] = 22.0*L*f2; MatrixData (me) [2][5] = 54.0*f2; MatrixData (me) [2][6] = -13.0*L*f2; MatrixData (me) [3][3] = 4.0*L*L*f2; MatrixData (me) [3][5] = 13.0*L*f2; MatrixData (me) [3][6] = -3.0*L*L*f2; MatrixData (me) [4][4] = 2.0*f1; MatrixData (me) [5][5] = 156.0*f2; MatrixData (me) [5][6] = -22.0*L*f2; MatrixData (me) [6][6] = 4.0*L*L*f2; MirrorMatrix (me); return me; } Matrix BeamTransformMatrix (element) Element element; { double cx,cy, L; static Matrix T = NullMatrix; if (T == NullMatrix) { T = CreateMatrix (6,6); ZeroMatrix (T); } L = ElementLength (element, 2); if (L <= TINY) { error ("length of element %d is zero to machine precision", element -> number); return NullMatrix; } cx = (element -> node[2] -> x - element -> node[1] -> x)/L; cy = (element -> node[2] -> y - element -> node[1] -> y)/L; MatrixData (T) [1][1] = cx; MatrixData (T) [1][2] = cy; MatrixData (T) [2][1] = -cy; MatrixData (T) [2][2] = cx; MatrixData (T) [3][3] = 1; MatrixData (T) [4][4] = cx; MatrixData (T) [4][5] = cy; MatrixData (T) [5][4] = -cy; MatrixData (T) [5][5] = cx; MatrixData (T) [6][6] = 1; return T; } Vector BeamEquivNodalForces (element, err_count) Element element; int *err_count; { double L; double wa,wb; int count; unsigned i,j; Matrix T; static Matrix Tt; static Vector equiv = NullMatrix; static Vector result; double theta; if (equiv == NullMatrix) { equiv = CreateVector (6); result = CreateVector (6); Tt = CreateMatrix (6,6); } ZeroMatrix (equiv); count = 0; wa = wb = 0; /* gcc -Wall */ if (element -> numdistributed > 2) { error ("beam elt %d can only have one distributed load", element -> number); count++; } L = ElementLength (element, 2); if (L <= TINY) { error ("length of element %d is zero to machine precision", element -> number); count ++; } for (i = 1 ; i <= element -> numdistributed ; i++) { if (element -> distributed[i] -> nvalues != 2) { error ("beam elt %d must have 2 values for a distributed load %s", element -> number, element -> distributed[i] -> name); count++; } if (element -> distributed[i] -> direction == GlobalZ || element -> distributed[i] -> direction == LocalZ) { error ("invalid direction specified for beam elt %d distrib load %s", element -> number, element -> distributed[i] -> name); count++; } for (j = 1 ; j <= element -> distributed[i] -> nvalues ; j++) { if (element -> distributed[i] -> value[j].node < 1 || element -> distributed[i] -> value[j].node > 2) { error ("invalid node numbering for beam elt %d distrib load %s", element -> number, element -> distributed[i] -> name); count++; } } if (element -> distributed[i] -> value[1].node == element -> distributed[i] -> value[2].node) { error ("incorrect node numbering for elt %d distributed load %s", element -> number, element -> distributed[i] -> name); count++; } } /* * Thats all the error checking, bail out if we've had any */ if (count) { *err_count = count; return NullMatrix; } if (element -> node[2] -> y - element -> node[1] -> y == 0 && element -> node[2] -> x - element -> node[1] -> x == 0) theta = 0.0; else theta = atan2 (element -> node[2] -> y - element -> node[1] -> y, element -> node[2] -> x - element -> node[1] -> x); for (i = 1 ; i <= element -> numdistributed ; i++) { if (element -> distributed[i] -> direction == GlobalX) { if (element -> distributed[i] -> value[1].node == 1) { wa = element -> distributed[i] -> value[1].magnitude*cos(-theta); wb = element -> distributed[i] -> value[2].magnitude*cos(-theta); ResolveEndForces (equiv, wa, wb, Parallel, L); wa = element -> distributed[i] -> value[1].magnitude*sin(-theta); wb = element -> distributed[i] -> value[2].magnitude*sin(-theta); ResolveEndForces (equiv, wa, wb, Perpendicular, L); } else if (element -> distributed[i] -> value[1].node == 2) { wb = element -> distributed[i] -> value[1].magnitude*cos(theta); wa = element -> distributed[i] -> value[2].magnitude*cos(theta); ResolveEndForces (equiv, wa, wb, Parallel, L); wb = element -> distributed[i] -> value[1].magnitude*sin(theta); wa = element -> distributed[i] -> value[2].magnitude*sin(theta); ResolveEndForces (equiv, wa, wb, Perpendicular, L); } } else if (element -> distributed[i] -> direction == GlobalY) { if (element -> distributed[i] -> value[1].node == 1) { wa = element -> distributed[i] -> value[1].magnitude*sin(theta); wb = element -> distributed[i] -> value[2].magnitude*sin(theta); ResolveEndForces (equiv, wa, wb, Parallel, L); wa = element -> distributed[i] -> value[1].magnitude*cos(theta); wb = element -> distributed[i] -> value[2].magnitude*cos(theta); ResolveEndForces (equiv, wa, wb, Perpendicular, L); } else if (element -> distributed[i] -> value[1].node == 2) { wb = element -> distributed[i] -> value[1].magnitude*sin(theta); wa = element -> distributed[i] -> value[2].magnitude*sin(theta); ResolveEndForces (equiv, wa, wb, Parallel, L); wb = element -> distributed[i] -> value[1].magnitude*cos(theta); wa = element -> distributed[i] -> value[2].magnitude*cos(theta); ResolveEndForces (equiv, wa, wb, Perpendicular, L); } } else { if (element -> distributed[i] -> value[1].node == 1) { wa = element -> distributed[i] -> value[1].magnitude; wb = element -> distributed[i] -> value[2].magnitude; } else if (element -> distributed[i] -> value[1].node == 2) { wb = element -> distributed[i] -> value[1].magnitude; wa = element -> distributed[i] -> value[2].magnitude; } ResolveEndForces (equiv, wa, wb, element -> distributed[i] -> direction, L); } } /* * Now that we know all is okay, allocate some memory if we * haven't already done so for some other element */ SetEquivalentForceMemory (element); T = BeamTransformMatrix (element); TransposeMatrix (Tt, T); MultiplyMatrices (result, Tt, equiv); *err_count = 0; return result; } static void ResolveEndForces (equiv, wa, wb, direction, L) Vector equiv; double wa; double wb; Direction direction; double L; { double force1, force2; double moment1, moment2; force1 = force2 = moment1 = moment2 = 0; /* gcc -Wall */ if (direction == Perpendicular || direction == LocalY) { if (wa == wb) { /* uniform distributed load */ force1 = force2 = wa*L/2.0; moment1 = wa*L*L/12.0; moment2 = -moment1; } else if (fabs(wa) > fabs(wb)) { /* load sloping node1 to node2 */ force1 = wb*L/2.0 + 7.0*(wa - wb)*L/20.0; force2 = wb*L/2.0 + 3.0*(wa - wb)*L/20.0; moment1 = wb*L*L/12.0 + (wa - wb)*L*L/20.0; moment2 = -wb*L*L/12.0 - (wa - wb)*L*L/30.0; } else if (fabs(wa) < fabs(wb)) { /* load sloping node2 to node1 */ force1 = wa*L/2.0 + 3.0*(wb - wa)*L/20.0; force2 = wa*L/2.0 + 7.0*(wb - wa)*L/20.0; moment1 = wa*L*L/12.0 + (wb - wa)*L*L/30.0; moment2 = -wa*L*L/12.0 - (wb - wa)*L*L/20.0; } VectorData (equiv) [2] += force1; VectorData (equiv) [3] += moment1; VectorData (equiv) [5] += force2; VectorData (equiv) [6] += moment2; } else if (direction == LocalX || direction == Parallel) { 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) [4] += force2; } }