/* 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: iso_2d.c * * Description: contains the element definition routines for isoparametric * plane stress / plane strain elements * ******************************************************************************/ # include # include # include "fe.h" # include "error.h" # include "misc.h" # define PLANESTRESS 1 # define PLANESTRAIN 2 extern int iso2d_PlaneStressEltSetup ( ), iso2d_PlaneStressEltStress ( ); extern int iso2d_PlaneStrainEltSetup ( ), iso2d_PlaneStrainEltStress ( ); struct definition iso2d_PlaneStressDefinition = { "iso2d_PlaneStress", iso2d_PlaneStressEltSetup, iso2d_PlaneStressEltStress, Planar, 9, 4, 6, 2, {0, 1, 2, 0, 0, 0, 0}, 0 }; struct definition iso2d_PlaneStrainDefinition = { "iso2d_PlaneStrain", iso2d_PlaneStrainEltSetup, iso2d_PlaneStrainEltStress, Planar, 9, 4, 6, 2, {0, 1, 2, 0, 0, 0, 0}, 0 }; unsigned LocalIsoShapeFunctions ( ); Vector GlobalIsoShapeFunctions ( ); Matrix Iso2dLocalB ( ); int iso2dElementSetup ( ); int iso2dElementStress ( ); int iso2d_PlaneStressEltSetup (element, mass_mode, tangent) Element element; char mass_mode; int tangent; { return iso2dElementSetup (element, mass_mode, tangent, PLANESTRESS); } int iso2d_PlaneStrainEltSetup (element, mass_mode, tangent) Element element; char mass_mode; int tangent; { return iso2dElementSetup (element, mass_mode, tangent, PLANESTRAIN); } int iso2d_PlaneStressEltStress (element) Element element; { return iso2dElementStress (element, PLANESTRESS); } int iso2d_PlaneStrainEltStress (element) Element element; { return iso2dElementStress (element, PLANESTRAIN); } int iso2dElementSetup (element, mass_mode, tangent, type) Element element; char mass_mode; int tangent; unsigned type; { unsigned numnodes; unsigned i,j; int ninteg; Matrix B; Matrix D; Vector jac; static Vector weights; static Matrix tempK; static Matrix N, dNdxi, dNde, dNdx, dNdy = NullMatrix; static Matrix Bt, temp; if (dNdy == NullMatrix) { N = CreateMatrix (9,9); dNdxi = CreateMatrix (9,9); dNde = CreateMatrix (9,9); dNdx = CreateMatrix (9,9); dNdy = CreateMatrix (9,9); weights = CreateVector (9); tempK = CreateMatrix (18,18); Bt = CreateMatrix (18,3); temp = CreateMatrix (18,3); } if (element -> material -> E == 0) { error ("isoparametric element %d has 0.0 for Young's modulus (E)",element -> number); return 1; } if (element -> material -> nu == 0) { error ("isoparametric element %d has 0.0 for Poisson's ratio (nu)",element -> number); return 1; } if (element -> material -> t == 0) { error ("isoparametric element %d has 0.0 for thickness (t)",element -> number); return 1; } numnodes = LocalIsoShapeFunctions (element, N, dNdxi, dNde, weights); if (element -> node[3] -> number == element -> node[4] -> number) { if (numnodes != 4) { error ("triangular isoparametric elt %d has more than 3 unique nodes", element -> number); return 1; } else numnodes = 3; } if (numnodes > 4) { ninteg = 9; numnodes = 9; } else ninteg = 4; ninteg = 4; jac = GlobalIsoShapeFunctions (element,N,dNdxi,dNde,dNdx,dNdy, ninteg,numnodes); if (type == PLANESTRESS) D = PlaneStressD (element); else if (type == PLANESTRAIN) D = PlaneStrainD (element); else D = NullMatrix; /* gcc -Wall */ if (D == NullMatrix) return 1; for (i = 1 ; i <= ninteg ; i++) { if (VectorData (jac)[i] <= 0.0) { error ("det |J| for elt %d is <= 0, check elt distortion",element -> number); return 1; } } if (element -> K == NullMatrix) { if (numnodes == 3) { element -> K = CreateMatrix (8,8); MatrixRows (element -> K) = 6; MatrixCols (element -> K) = 6; } else element -> K = CreateMatrix (2*numnodes, 2*numnodes); } ZeroMatrix (element -> K); /* * We need to fool the matrix routines since really we can have * a variable size stiffness array ... there's no need to operate * on all those zeros if we don't have to */ MatrixRows (tempK) = 2*numnodes; MatrixCols (tempK) = 2*numnodes; for (i = 1 ; i <= ninteg ; i++) { B = Iso2dLocalB (element, numnodes, dNdx, dNdy, i); if (B == NullMatrix) return 1; MatrixRows (Bt) = MatrixRows (temp) = MatrixCols (B); TransposeMatrix (Bt, B); MultiplyMatrices (temp, Bt, D); MultiplyMatrices (tempK, temp, B); ScaleMatrix (tempK, tempK, VectorData (weights) [i]*VectorData (jac) [i], 0.0); AddMatrices (element -> K, element -> K, tempK); } ScaleMatrix (element -> K, element -> K, element -> material -> t, 0.0); /* * clean out the 7 & 8th rows and columns if this was a triangular * element so nothing extra gets assembled into the global * stiffness routines */ if (numnodes == 3) { for (i = 1 ; i <= 8 ; i++) for (j = 7 ; j <= 8 ; j++) MatrixData (element -> K) [i][j] = 0.0; for (i = 7 ; i <= 8 ; i++) for (j = 1 ; j <= 6 ; j++) MatrixData (element -> K) [i][j] = 0.0; } return 0; } int iso2dElementStress (element, type) Element element; unsigned type; { element -> ninteg = 0; return 0; } Matrix Iso2dLocalB (element, numnodes, dNdx, dNdy, point) Element element; unsigned numnodes; Matrix dNdx, dNdy; unsigned point; { unsigned i; static Matrix B = NullMatrix; if (B == NullMatrix) B = CreateMatrix (3,18); for (i = 1 ; i <= numnodes ; i++) { MatrixData (B) [1][2*i - 1] = MatrixData (dNdx) [i][point]; MatrixData (B) [1][2*i] = 0.0; MatrixData (B) [2][2*i - 1] = 0.0; MatrixData (B) [2][2*i] = MatrixData (dNdy) [i][point]; MatrixData (B) [3][2*i - 1] = MatrixData (dNdy) [i][point]; MatrixData (B) [3][2*i] = MatrixData (dNdx) [i][point]; } MatrixCols (B) = numnodes*2; return B; } Vector GlobalIsoShapeFunctions (element, N, dNdxi, dNde, dNdx, dNdy, ninteg,nodes) Element element; int ninteg; Matrix N, dNdxi, dNde, dNdx, dNdy; unsigned nodes; { unsigned i,j; static Vector jac, dxdxi, dxde, dydxi, dyde = NullMatrix; if (dyde == NullMatrix) { dxdxi = CreateVector (9); dxde = CreateVector (9); dydxi = CreateVector (9); dyde = CreateVector (9); jac = CreateVector (9); } for (i = 1 ; i <= 9 ; i++) { VectorData (dxdxi) [i] = 0.0; VectorData (dxde) [i] = 0.0; VectorData (dydxi) [i] = 0.0; VectorData (dyde) [i] = 0.0; VectorData (jac) [i] = 0.0; } for (i = 1 ; i <= ninteg ; i++) { for (j = 1 ; j <= nodes ; j++) { if (element -> node[j] != NULL) { VectorData (dxdxi) [i] += MatrixData (dNdxi) [j][i]* (element -> node[j] -> x); VectorData (dxde) [i] += MatrixData (dNde) [j][i]* (element -> node[j] -> x); VectorData (dydxi) [i] += MatrixData (dNdxi) [j][i]* (element -> node[j] -> y); VectorData (dyde) [i] += MatrixData (dNde) [j][i]* (element -> node[j] -> y); } } VectorData (jac) [i] = VectorData (dxdxi)[i] * VectorData (dyde)[i] - VectorData (dxde)[i] * VectorData (dydxi)[i]; for (j = 1 ; j <= nodes ; j++) { if (element -> node[j] != NULL) { MatrixData (dNdx) [j][i] = (MatrixData (dNdxi) [j][i]*VectorData (dyde)[i] - MatrixData (dNde)[j][i]*VectorData (dydxi)[i])/ VectorData (jac)[i]; MatrixData (dNdy) [j][i] = -(MatrixData (dNdxi)[j][i]*VectorData (dxde)[i] - MatrixData (dNde)[j][i]*VectorData (dxdxi)[i])/ VectorData (jac)[i]; } else { MatrixData (dNdx) [j][i] = 0.0; MatrixData (dNdy) [j][i] = 0.0; } } } return jac; } /***************************************************************************** * * Function: LocalIsoShapeFunctions * * Description: calculates the shape functions and the derivatives (w/ respect * to xi, eta coordinates) of the shape function for a four to * nine node plane stress / plane strain element * * Note: The approach looks rather brutish, but it seems much clearer * to me this way and we have to do each individual computation * anyways, whether we put ourselves in a loop and use index * notation or not ... * ******************************************************************************/ unsigned LocalIsoShapeFunctions (element, N, dNdx, dNde, weights) Element element; Matrix N, dNdx, dNde; Vector weights; { unsigned i,j,k; int ninteg; double eta,xi; double Nt[10]; double de[10],dx[10]; double *gauss_points; double *gauss_wts; static unsigned numnodes; static int points [10]; static int prev_points [10] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; unsigned same_flag; same_flag = 1; numnodes = 4; for (i = 5 ; i <= 9 ; i++) { points [i] = 0; if (element -> node[i] != NULL) { numnodes ++; points [i] = 1; } if (points [i] != prev_points [i]) same_flag = 0; } if (same_flag) return numnodes; if (numnodes == 4) ninteg = 2; else ninteg = 3; for (i = 5 ; i <= 9 ; i++) prev_points [i] = points [i]; ninteg = 2; GaussPoints (ninteg, &gauss_points, &gauss_wts); for (i = 0 ; i < ninteg ; i++) { xi = gauss_points [i]; for (j = 0 ; j < ninteg ; j++) { eta = gauss_points [j]; Nt [1] = 0.25*(1 - eta)*(1 - xi); dx [1] = 0.25*(-1 + eta); de [1] = 0.25*(-1 + xi); Nt [2] = 0.25*(1 - eta)*(1 + xi); dx [2] = 0.25*(1 - eta); de [2] = 0.25*(-1 - xi); Nt [3] = 0.25*(1 + eta)*(1 + xi); dx [3] = 0.25*(1 + eta); de [3] = 0.25*(1 + xi); Nt [4] = 0.25*(1 + eta)*(1 - xi); dx [4] = 0.25*(-1 - eta); de [4] = 0.25*(1 - xi); if (numnodes == 4 && element -> node[3] -> number == element -> node[4] -> number) { Nt [3] += Nt [4]; dx [3] += dx [4]; de [3] += de [4]; /* printf ("%g %g %g %g %g\n", eta, xi, Nt [3], dx [3], de [3]); */ } if (numnodes > 4) { if (points [9]) { Nt [9] = (1 - eta*eta)*(1 - xi*xi); dx [9] = 2*xi*(eta*eta - 1); de [9] = 2*eta*(xi*xi - 1); for (k = 1 ; k <= 4 ; k++) { Nt [k] -= 0.25*Nt [9]; dx [k] -= 0.25*dx [9]; de [k] -= 0.25*de [9]; } } else Nt [9] = dx [9] = de [9] = 0.0; if (points [5]) { Nt [5] = 0.5*((1 - eta)*(1 - xi*xi) - Nt[9]); dx [5] = -xi + xi*eta - 0.5*dx[9]; de [5] = 0.5*(-1 + xi*xi - de[9]); } else Nt [5] = dx [5] = de [5] = 0.0; if (points [6]) { Nt [6] = 0.5*((1 - eta*eta)*(1 + xi) - Nt[9]); dx [6] = 0.5*(1 - eta*eta - dx[9]); de [6] = -eta - eta*xi - 0.5*de[9]; } else Nt [6] = dx [6] = de [6] = 0.0; if (points [7]) { Nt [7] = 0.5*((1 + eta)*(1 - xi*xi) - Nt[9]); dx [7] = -xi - eta*xi - 0.5*dx[9]; de [7] = 0.5*(1 - xi*xi - de[9]); } else Nt [7] = dx [7] = de [7] = 0.0; if (points [8]) { Nt [8] = 0.5*((1 - eta*eta)*(1 - xi) - Nt[9]); dx [8] = 0.5*(-1 + eta*eta - dx[9]); de [8] = -eta + xi*eta - 0.5*de[9]; } else Nt [8] = dx [8] = de [8] = 0.0; Nt [1] -= 0.5*(Nt[5] + Nt[8]); dx [1] -= 0.5*(dx[5] + dx[8]); de [1] -= 0.5*(de[5] + de[8]); Nt [2] -= 0.5*(Nt[5] + Nt[6]); dx [2] -= 0.5*(dx[5] + dx[6]); de [2] -= 0.5*(de[5] + de[6]); Nt [3] -= 0.5*(Nt[6] + Nt[7]); dx [3] -= 0.5*(dx[6] + dx[7]); de [3] -= 0.5*(de[6] + de[7]); Nt [4] -= 0.5*(Nt[7] + Nt[8]); dx [4] -= 0.5*(dx[7] + dx[8]); de [4] -= 0.5*(de[7] + de[8]); } for (k = 1 ; k <= 9 ; k++) { MatrixData (N) [k][i*ninteg + j+1] = Nt [k]; MatrixData (dNdx) [k][i*ninteg + j+1] = dx [k]; MatrixData (dNde) [k][i*ninteg + j+1] = de [k]; } VectorData (weights) [i*ninteg + j+1] = gauss_wts [j]; } } return numnodes; }