/*****************************************************************************1*2* Elmer, A Finite Element Software for Multiphysical Problems3*4* Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland5*6* This program is free software; you can redistribute it and/or7* modify it under the terms of the GNU General Public License8* as published by the Free Software Foundation; either version 29* of the License, or (at your option) any later version.10*11* This program is distributed in the hope that it will be useful,12* but WITHOUT ANY WARRANTY; without even the implied warranty of13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14* GNU General Public License for more details.15*16* You should have received a copy of the GNU General Public License17* along with this program (in file fem/GPL-2); if not, write to the18* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,19* Boston, MA 02110-1301, USA.20*21*****************************************************************************/2223/*******************************************************************************24*25* Definition of 8 node quad element.26*27*******************************************************************************28*29* Author: Juha Ruokolainen30*31* Address: CSC - IT Center for Science Ltd.32* Keilaranta 14, P.O. BOX 40533* 02101 Espoo, Finland34* Tel. +358 0 457 272335* Telefax: +358 0 457 230236* EMail: [email protected]37*38* Date: 20 Sep 199539*40* Modification history:41*42* 28 Sep 1995, changed call to elm_triangle_normal to geo_triangle normal43* routine elm_... doesn't exist anymore44* Juha R45*46*47******************************************************************************/4849#include "../elmerpost.h"50#include <elements.h>5152/*53*54* shape functions: N0 = ( uv(1-u-v)+u^2+v^2-1)/455* N1 = (-uv(1+u-v)+u^2+v^2-1)/456* N2 = ( uv(1+u+v)+u^2+v^2-1)/4 3---6---257* N3 = (-uv(1-u+v)+u^2+v^2-1)/4 | |58* N4 = ((1-v)(1-u^2)/2 7 559* N5 = ((1+u)(1-v^2)/2 v | |60* N6 = ((1+v)(1-u^2)/2 0---4---161* N7 = ((1-u)(1-v^2)/2 u62*63*/6465static double N[8][8],A[8][8];6667static double NodeU[] = { -1.0, 1.0, 1.0, -1.0, 0.0, 1.0, 0.0, -1.0 };68static double NodeV[] = { -1.0, -1.0, 1.0, 1.0, -1.0, 0.0, 1.0, 0.0 };6970/*******************************************************************************71*72* Name: elm_8node_quad_shape_functions( )73*74* Purpose: Initialize element shape function array. Internal only.75*76* Parameters:77*78* Input: Global (filewise) variables NodeU,NodeV,NodeW79*80* Output: Global (filewise) variable N[6][6], will contain81* shape function coefficients82*83* Return value: void84*85******************************************************************************/86static void elm_8node_quad_shape_functions()87{88double u,v;8990int i,j;9192for( i=0; i<8; i++ )93{94u = NodeU[i];95v = NodeV[i];9697A[i][0] = 1;98A[i][1] = u;99A[i][2] = v;100A[i][3] = u*v;101A[i][4] = u*u;102A[i][5] = v*v;103A[i][6] = u*u*v;104A[i][7] = u*v*v;105}106107lu_mtrinv( (double *)A,8 );108109for( i=0; i<8; i++ )110for( j=0; j<8; j++ ) N[i][j] = A[j][i];111}112113114/*******************************************************************************115*116* Name: elm_8node_quad_triangulate( geometry_t *,element_t * )117*118* Purpose: Triangulate an element. The process also builds up an edge119* table and adds new nodes to node table. The triangulation120* and edge table is stored in geometry_t *geom-structure.121*122* Parameters:123*124* Input: (geometry_t *) pointer to structure holding triangulation125* (element_t *) element to triangulate126*127* Output: (geometry_t *) structure is modified128*129* Return value: FALSE if malloc() fails, TRUE otherwise130*131******************************************************************************/132int elm_8node_quad_triangulate( geometry_t *geom,element_t *Elm,element_t *Parent )133{134triangle_t triangle;135136triangle.Element = Parent;137138triangle.v[0] = Elm->Topology[0];139triangle.v[1] = Elm->Topology[4];140triangle.v[2] = Elm->Topology[7];141142triangle.Edge[0] = TRUE;143triangle.Edge[1] = FALSE;144triangle.Edge[2] = TRUE;145146if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;147148triangle.v[0] = Elm->Topology[4];149triangle.v[1] = Elm->Topology[1];150triangle.v[2] = Elm->Topology[5];151152triangle.Edge[0] = TRUE;153triangle.Edge[1] = TRUE;154triangle.Edge[2] = FALSE;155156if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;157158triangle.v[0] = Elm->Topology[4];159triangle.v[1] = Elm->Topology[5];160triangle.v[2] = Elm->Topology[7];161162triangle.Edge[0] = FALSE;163triangle.Edge[1] = FALSE;164triangle.Edge[2] = FALSE;165166if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;167168triangle.v[0] = Elm->Topology[5];169triangle.v[1] = Elm->Topology[2];170triangle.v[2] = Elm->Topology[6];171172triangle.Edge[0] = TRUE;173triangle.Edge[1] = TRUE;174triangle.Edge[2] = FALSE;175176if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;177178triangle.v[0] = Elm->Topology[5];179triangle.v[1] = Elm->Topology[6];180triangle.v[2] = Elm->Topology[7];181182triangle.Edge[0] = FALSE;183triangle.Edge[1] = FALSE;184triangle.Edge[2] = FALSE;185186if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;187188triangle.v[0] = Elm->Topology[6];189triangle.v[1] = Elm->Topology[3];190triangle.v[2] = Elm->Topology[7];191192triangle.Edge[0] = TRUE;193triangle.Edge[1] = TRUE;194triangle.Edge[2] = FALSE;195196if ( !geo_add_triangle( geom,&triangle ) ) return FALSE;197198return TRUE;199}200201/*******************************************************************************202*203* Name: elm_8node_quad_fvalue( double *,double,double )204*205* Purpose: return value of a quantity given on nodes at point (u,v)206*207*208*209* Parameters:210*211* Input: (double *) quantity values at nodes212* (double u,double v) point where values are evaluated213*214* Output: none215*216* Return value: quantity value217*218******************************************************************************/219static double elm_8node_quad_fvalue( double *F, double u, double v )220{221double R,uv=u*v,uu=u*u,vv=v*v,uuv=uu*v,uvv=u*vv;222int i;223224R = 0.0;225for( i=0; i<8; i++ )226{227R += F[i]*(N[i][0] +228N[i][1]*u +229N[i][2]*v +230N[i][3]*uv +231N[i][4]*uu +232N[i][5]*vv +233N[i][6]*uuv +234N[i][7]*uvv);235}236237return R;238}239240/*******************************************************************************241*242* Name: elm_8node_quad_dndu_fvalue( double *,double,double )243*244* Purpose: return value of a first partial derivate in (u) of a245* quantity given on nodes at point (u,v)246*247*248* Parameters:249*250* Input: (double *) quantity values at nodes251* (double u,double v) point where values are evaluated252*253* Output: none254*255* Return value: quantity value256*257******************************************************************************/258static double elm_8node_quad_dndu_fvalue( double *F, double u, double v )259{260double R=0.0,uv=u*v,vv=v*v;261int i;262263for( i=0; i<8; i++ )264{265R += F[i]*(N[i][1]+N[i][3]*v+2*N[i][4]*u+2*N[i][6]*uv+N[i][7]*vv);266}267268return R;269}270271/*******************************************************************************272*273* Name: elm_8node_quad_dndv_fvalue( double *,double,double )274*275* Purpose: return value of a first partial derivate in (v) of a276* quantity given on nodes at point (u,v)277*278*279* Parameters:280*281* Input: (double *) quantity values at nodes282* (double u,double v) point where values are evaluated283*284* Output: none285*286* Return value: quantity value287*288******************************************************************************/289static double elm_8node_quad_dndv_fvalue( double *F, double u, double v )290{291double R=0.0,uu=u*u,uv=u*v;292293int i;294295for( i=0; i<8; i++ )296{297R += F[i]*(N[i][2]+N[i][3]*u+2*N[i][5]*v+N[i][6]*uu+2*N[i][7]*uv);298}299300return R;301}302303/*******************************************************************************304*305* Name: elm_8node_quad_dd(double *F,double *u,double *v,double *Values)306*307* Purpose: Return matrix of second partial derivates of given quantity308* at given point u,v.309*310* Parameters:311*312* Input: (double *)F: quantity values at nodes313* (double)u,v: point of evaluation314*315* Output: (double *)Values: 2x2 matrix of partial derivates316*317* Return value: void318*319*******************************************************************************/320static void elm_8node_quad_ddu( double *F,double u,double v,double *Values )321{322double ddu = 0.0, dudv=0.0, ddv = 0.0;323324int i;325326for( i=0; i<8; i++ )327{328ddu += F[i]*( 2*N[i][4] + 2*v*N[i][6] );329ddv += F[i]*( 2*N[i][5] + 2*v*N[i][7] );330dudv += F[i]*( N[i][3] + 2*u*N[i][6] + 2*v*N[i][7] );331}332333Values[0] = ddu;334Values[1] = dudv;335Values[2] = dudv;336Values[3] = ddv;337}338339/*******************************************************************************340*341* Name: elm_8node_quad_point_inside(342* double *nx,double *ny,double *nz,343* double px, double py, double pz,344* double *u,double *v,double *w )345*346* Purpose: Find if point (px,py,pz) is inside the element, and return347* element coordinates of the point.348*349* Parameters:350*351* Input: (double *) nx,ny,nz n coordinates352* (double) px,py,pz point to consider353*354* Output: (double *) u,v,w point in element coordinates if inside355*356* Return value: in/out status357*358* NOTES: the goal here can be hard for more involved element types. kind of359* trivial for this one... TODO: FIX THIS....360*361******************************************************************************/362int elm_8node_quad_point_inside363(364double *nx, double *ny, double *nz,365double px, double py, double pz, double *u,double *v,double *w366)367{368double lx[4],ly[4],lz[4],cx,cy,cz;369370int i,j,k;371372static int map[4][3] =373{374{ 7,0,4 }, { 4,1,5 }, { 5,2,6 }, { 6,3,7 }375};376377int elm_4node_quad_point_inside();378379cx = elm_8node_quad_fvalue( nx,0.0,0.0 );380cy = elm_8node_quad_fvalue( ny,0.0,0.0 );381cz = elm_8node_quad_fvalue( nz,0.0,0.0 );382383for( i=0; i<4; i++ )384{385386switch( i )387{388case 0:389lx[0] = nx[0]; ly[0] = ny[0]; lz[0] = nz[0];390lx[1] = nx[4]; ly[1] = ny[4]; lz[1] = nz[4];391lx[2] = cx; ly[2] = cy; lz[2] = cz;392lx[3] = nx[7]; ly[3] = ny[7]; lz[3] = nz[7];393break;394case 1:395lx[0] = nx[4]; ly[0] = ny[4]; lz[0] = nz[4];396lx[1] = nx[1]; ly[1] = ny[1]; lz[1] = nz[1];397lx[2] = nx[5]; ly[2] = ny[5]; lz[2] = nz[5];398lx[3] = cx; ly[3] = cy; lz[3] = cz;399break;400case 2:401lx[0] = cx; ly[0] = cy; lz[0] = cz;402lx[1] = nx[5]; ly[1] = ny[5]; lz[1] = nz[5];403lx[2] = nx[2]; ly[2] = ny[2]; lz[2] = nz[2];404lx[3] = nx[6]; ly[3] = ny[6]; lz[3] = nz[6];405break;406case 3:407lx[0] = nx[7]; ly[0] = ny[7]; lz[0] = nz[7];408lx[1] = cx; ly[1] = cy; lz[1] = cz;409lx[2] = nx[6]; ly[2] = ny[6]; lz[2] = nz[6];410lx[3] = nx[3]; ly[3] = ny[3]; lz[3] = nz[3];411break;412}413414if ( elm_4node_quad_point_inside( lx,ly,lz,px,py,pz,u,v,w ) )415{416switch( i )417{418case 0:419*u = *u/2 - 0.5;420*v = *v/2 - 0.5;421break;422423case 1:424*u = *u/2 + 0.5;425*v = *v/2 - 0.5;426break;427428case 2:429*u = *u/2 + 0.5;430*v = *v/2 + 0.5;431break;432433case 3:434*u = *u/2 - 0.5;435*v = *v/2 + 0.5;436break;437}438439return TRUE;440}441}442443return FALSE;444}445446/*******************************************************************************447*448* Name: elm_8node_quad_isoline449*450* Purpose: Extract a iso line from triangle with given threshold451*452* Parameters:453*454* Input: (double) K, contour threshold455* (double *) F, contour quantity456* (double *) C, color quantity457* (double *) X,Y,Z vertex coords.458*459* Output: (line_t *) place to store the line460*461* Return value: number of lines generated (0,...,16)462*463******************************************************************************/464int elm_8node_quad_isoline465(466double K, double *F, double *C,double *X,double *Y,double *Z,line_t *Line467)468{469double f[4],c[4],x[4],y[4],z[4];470471int i, j, k, n=0, above=0;472473static int map[4][3] =474{475{ 7,0,4 }, { 4,1,5 }, { 5,2,6 }, { 6,3,7 }476};477478int elm_4node_quad_isoline();479480for( i=0; i<8; i++ ) above += F[i]>K;481if ( above == 0 || above == 8 ) return 0;482483f[0] = elm_8node_quad_fvalue( F,0.0,0.0 );484c[0] = elm_8node_quad_fvalue( C,0.0,0.0 );485x[0] = elm_8node_quad_fvalue( X,0.0,0.0 );486y[0] = elm_8node_quad_fvalue( Y,0.0,0.0 );487z[0] = elm_8node_quad_fvalue( Z,0.0,0.0 );488489for( i=0; i<4; i++ )490{491for( j=1; j<4; j++ )492{493k = map[i][j-1];494f[j] = F[k];495c[j] = C[k];496x[j] = X[k];497y[j] = Y[k];498z[j] = Z[k];499}500n += elm_4node_quad_isoline( K,f,c,x,y,z,&Line[n] );501}502503return n;504}505506507/******************************************************************************508*509* Name: elm_8node_quad_initialize( )510*511* Purpose: Register the element type512*513* Parameters:514*515* Input: (char *) description of the element516* (int) numeric code for the element517*518* Output: Global list of element types is modified519*520* Return value: malloc() success521*522******************************************************************************/523int elm_8node_quad_initialize()524{525element_type_t ElementDef;526527static char *Name = "ELM_8NODE_QUAD";528529int elm_add_element_type();530531elm_8node_quad_shape_functions();532533ElementDef.ElementName = Name;534ElementDef.ElementCode = 408;535536ElementDef.NumberOfNodes = 8;537ElementDef.NodeU = NodeU;538ElementDef.NodeV = NodeV;539ElementDef.NodeW = NULL;540541ElementDef.PartialU = (double (*)())elm_8node_quad_dndu_fvalue;542ElementDef.PartialV = (double (*)())elm_8node_quad_dndv_fvalue;543ElementDef.PartialW = NULL;544ElementDef.SecondPartials = (double (*)())elm_8node_quad_ddu;545546ElementDef.FunctionValue = (double (*)())elm_8node_quad_fvalue;547548ElementDef.Triangulate = (int (*)())elm_8node_quad_triangulate;549ElementDef.PointInside = (int (*)())elm_8node_quad_point_inside;550ElementDef.IsoLine = (int (*)())elm_8node_quad_isoline;551ElementDef.IsoSurface = (int (*)())NULL;552553return elm_add_element_type( &ElementDef );554}555556557