/* 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: misc.c * * Description: contains various commonly used routines in formulating * element stiffness matrices * ******************************************************************************/ # include # include "fe.h" # include "misc.h" # include "error.h" # include "allocate.h" /***************************************************************************** * * Function: GaussPoints * * Description: sets an array containing the appropriate Gauss points * for a given number of points for Gaussian quadrature * ******************************************************************************/ unsigned GaussPoints (npoints, xpoints, weights) unsigned npoints; double **xpoints, **weights; { static double x[3][3] = {{0.0,0.0,0.0}, {-0.57735026918962,0.57735026918962,0.0}, {-0.77459666924148,0.0,0.77459666924148}}; static double w[3][3] = {{1.0,0.0,0.0}, {1.0,1.0,0.0}, {0.5555555555555,0.8888888888888,0.5555555555555}}; if (npoints > 3 || npoints < 1) return 1; else { if (xpoints != NULL) *xpoints = x[npoints - 1]; if (weights != NULL) *weights = w[npoints - 1]; return 0; } } /***************************************************************************** * * Function: PlaneStrainD * *****************************************************************************/ Matrix PlaneStrainD (element) Element element; { static Matrix D = NullMatrix; static double prev_nu = -99; static double prev_E = -99; double poisson, factor; if (D == NullMatrix) D = CreateMatrix (3,3); if (element -> material -> E != prev_E || element -> material -> nu != prev_nu) { ZeroMatrix (D); poisson = element -> material -> nu; MatrixData (D) [1][1] = 1 - poisson; MatrixData (D) [1][2] = poisson; MatrixData (D) [2][1] = poisson; MatrixData (D) [2][2] = 1 - poisson; MatrixData (D) [3][3] = (1 - 2*poisson)/2; if (1 - 2*poisson <= TINY) { error ("singularity in constitutive matrix for element %d",element -> number); return NULL; } factor = element -> material -> E / ((1 + poisson)*(1 - 2*poisson)); ScaleMatrix (D,D,factor,0.0); prev_nu = element -> material -> nu; prev_E = element -> material -> E; } return D; } /***************************************************************************** * * Function: PlaneStressD * *****************************************************************************/ Matrix PlaneStressD (element) Element element; { static Matrix D = NullMatrix; static double prev_nu = -99; static double prev_E = -99; double poisson, factor; if (D == NullMatrix) D = CreateMatrix (3,3); if (element -> material -> nu != prev_nu || element -> material -> E != prev_E) { ZeroMatrix (D); poisson = element -> material -> nu; MatrixData (D) [1][1] = 1; MatrixData (D) [1][2] = poisson; MatrixData (D) [2][1] = poisson; MatrixData (D) [2][2] = 1; MatrixData (D) [3][3] = (1 - poisson)/2; if (1 - poisson*poisson <= TINY) { error ("singularity in constitutive matrix for element %d",element -> number); return NullMatrix; } factor = element -> material -> E / (1 - poisson*poisson); ScaleMatrix (D,D,factor,0.0); prev_E = element -> material -> E; prev_nu = element -> material -> nu; } return D; } Matrix AxisymmetricD (element) Element element; { static Matrix D = NullMatrix; static double prev_nu = -99; static double prev_E = -99; double poisson, factor; if (D == NullMatrix) D = CreateMatrix (4,4); if (element -> material -> nu != prev_nu || element -> material -> E != prev_E) { ZeroMatrix (D); poisson = element -> material -> nu; MatrixData (D) [1][1] = 1 - poisson; MatrixData (D) [1][2] = poisson; MatrixData (D) [1][3] = poisson; MatrixData (D) [2][1] = poisson; MatrixData (D) [2][2] = 1 - poisson; MatrixData (D) [2][3] = poisson; MatrixData (D) [3][1] = poisson; MatrixData (D) [3][2] = poisson; MatrixData (D) [3][3] = 1 - poisson; MatrixData (D) [4][4] = 0.5*(1 - 2*poisson); if (1 - 2*poisson <= TINY) { error ("singularity in constitutive matrix for element %d",element -> number); return NullMatrix; } factor = element -> material -> E / (1 - 2*poisson) / (1 + poisson); ScaleMatrix (D,D,factor,0.0); prev_E = element -> material -> E; prev_nu = element -> material -> nu; } return D; } Matrix IsotropicD (element) Element element; { static Matrix D = NullMatrix; static double prev_nu = -99; static double prev_E = -99; double poisson, factor; if (D == NullMatrix) D = CreateMatrix (6, 6); if (element -> material -> nu != prev_nu || element -> material -> E != prev_E) { ZeroMatrix (D); poisson = element -> material -> nu; MatrixData (D) [1][1] = 1.0 - poisson; MatrixData (D) [1][2] = poisson; MatrixData (D) [1][3] = poisson; MatrixData (D) [2][1] = poisson; MatrixData (D) [2][2] = 1.0 - poisson; MatrixData (D) [2][3] = poisson; MatrixData (D) [3][1] = poisson; MatrixData (D) [3][2] = poisson; MatrixData (D) [3][3] = 1.0 - poisson; MatrixData (D) [4][4] = (1.0 - 2*poisson)/2.0; MatrixData (D) [5][5] = (1.0 - 2*poisson)/2.0; MatrixData (D) [6][6] = (1.0 - 2*poisson)/2.0; if (1.0 - 2.0*poisson <= TINY) { error ("singularity in constitutive matrix for element %d",element -> number); return NullMatrix; } factor = element -> material -> E / (1.0 + poisson) / (1.0 - 2*poisson); ScaleMatrix (D, D, factor, 0.0); prev_E = element -> material -> E; prev_nu = element -> material -> nu; } return D; } double ElementLength (element, coords) Element element; unsigned coords; { if (coords == 1) return fabs (element -> node[2] -> x - element -> node[1] -> x); else if (coords == 2) return sqrt ((element -> node[2] -> x - element -> node[1] -> x)* (element -> node[2] -> x - element -> node[1] -> x) + (element -> node[2] -> y - element -> node[1] -> y)* (element -> node[2] -> y - element -> node[1] -> y)); else if (coords == 3) return sqrt ((element -> node[2] -> x - element -> node[1] -> x)* (element -> node[2] -> x - element -> node[1] -> x) + (element -> node[2] -> y - element -> node[1] -> y)* (element -> node[2] -> y - element -> node[1] -> y) + (element -> node[2] -> z - element -> node[1] -> z)* (element -> node[2] -> z - element -> node[1] -> z)); else return 0.0; } /***************************************************************************** * * Function: ElementArea * * Description: Finds the area of a planar element of n nodes * ******************************************************************************/ double ElementArea (e, n) Element e; unsigned n; { unsigned i; double sum; sum = e -> node[1] -> x*(e -> node[2] -> y - e -> node[n] -> y) + e -> node[n] -> x*(e -> node[1] -> y - e -> node[n-1] -> y); for (i = 2 ; i <= n-1 ; i++) sum += e -> node[i] -> x*(e -> node[i+1] -> y - e -> node[i-1] -> y); return sum/2; } /**************************************************************************** * * Function: ResolveHingeConditions * * Description: Given a hinged DOF, we need to knock out the rows and * columns associated with that DOF in the element stiffness * matrix. We also need to adjust all the coefficients * in that stiffness matrix according to: * * a(i,j) += [-a(m,j)/a(m,m)]*a(i,m) * * where m is the row number of the hinged DOF. The * downside to this procedure is that we will _not_ be able * to get displacements at this DOF. In general, the * end displacements of elements connected at a hinged DOF * will not be continuous. Given the way FElt deals with * displacements (i.e., as a solution), I figured it was * a better compromise to put as much of this in as I could * without completely changing the output paradigm (i.e., * I don't want to start outputting element end displacement * in lieu of or in addition to the global displacements that * we already calculate.) * ****************************************************************************/ void ResolveHingeConditions (element) Element element; { unsigned nodes, ndofs; unsigned i,j; unsigned m,n; unsigned dof; nodes = element -> definition -> numnodes; ndofs = element -> definition -> numdofs; for (i = 1 ; i <= nodes ; i++) { for (j = 1 ; j <= ndofs ; j++) { if (element -> node[i] -> constraint -> constraint [element -> definition -> dofs[j]] == 'h') { dof = (i-1)*ndofs + j; for (m = 1 ; m <= nodes*ndofs ; m++) { for (n = 1 ; n <= nodes*ndofs ; n++) { if (m != dof && n != dof) { MatrixData (element -> K) [m][n] -= MatrixData (element -> K) [dof][n] / MatrixData (element -> K) [dof][dof] * MatrixData (element -> K) [m][dof]; } } } element -> K = ZeroRowCol (element -> K, dof); } } } return; } /***************************************************************************** * * Function: SetEquivalentForceMemory * *****************************************************************************/ void SetEquivalentForceMemory (element) Element element; { unsigned i,j; /* * loop over all this element's nodes and allocate space for * the eq_force array if that has not already been done (i.e., it * could have gotten done from some other element */ for (i = 1 ; i <= element -> definition -> numnodes ; i++) { if (element -> node[i] -> eq_force == NULL) { element -> node[i] -> eq_force = Allocate (double, 6); if (element -> node[i] -> eq_force == NULL) Fatal ("allocation error setting equivalent force memory\n"); /* * make the array unit offset and initialize all entries to zero */ UnitOffset (element -> node[i] -> eq_force); for (j = 1 ; j <= 6 ; j++) element -> node[i] -> eq_force[j] = 0.0; } } return; } /***************************************************************************** * * Function: MultiplyAtBA * * Description: Multiplies A(trans)*B*A without actually transposing * and with no full size temporary storage. It is the * caller's responsibility to create storage for C * and to make sure that dimensions match. * *****************************************************************************/ void MultiplyAtBA (C, A, B) Matrix A,B,C; { double temp [100]; double result; unsigned i,j,k; for (j = 1 ; j <= MatrixCols (A) ; j++) { for (i = 1 ; i <= MatrixCols (B) ; i++) { temp [i] = 0; for (k = 1 ; k <= MatrixRows (B) ; k++) temp [i] += MatrixData (B) [k][i] * MatrixData (A) [k][j]; } for (i = 1 ; i <= MatrixCols (A) ; i++) { result = 0; for (k = 1 ; k <= MatrixCols (B) ; k++) result += temp [k] * MatrixData (A) [k][i]; MatrixData (C) [j][i] = result; } } } /**************************************************************************** * * Function: ZeroRowCol * * Description: Zeros out the row and column given by dof. Places * a one on the diagonal. * ****************************************************************************/ Matrix ZeroRowCol (K,dof) Matrix K; unsigned dof; { unsigned i, size; size = MatrixRows (K); for (i = 1 ; i <= size ; i++) { MatrixData (K) [i][dof] = 0; MatrixData (K) [dof][i] = 0; } MatrixData (K) [dof][dof] = 1; return K; } /***************************************************************************** * * Function: AllocationError * ****************************************************************************/ void AllocationError (e, msg) Element e; char *msg; { Fatal ("allocation error computing element %d %s\n", e -> number, msg); }